/****************************************************************************** * Copyright (c) 2016 Oracle * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Konstantin Komissarchik - initial implementation and ongoing maintenance ******************************************************************************/ package org.eclipse.sapphire.services; import java.io.File; import java.io.IOException; import java.util.List; import org.eclipse.sapphire.modeling.Path; import org.eclipse.sapphire.modeling.util.MiscUtil; /** * Service for value properties of type Path that enables relative path support. Typically attached to * the property using the @Service annotation. * * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a> */ public abstract class RelativePathService extends Service { /** * Returns the absolute paths to folders that should be used as relativization roots. * * @return the absolute paths to folders that should be used as relativization roots */ public abstract List<Path> roots(); /** * Determines whether relative paths should be confined to paths beneath roots and * precluded from using "../" parent navigation. The default implementation returns true. * * @return true if relative paths should be confined to paths beneath roots */ public boolean enclosed() { return true; } /** * Converts the given absolute path to a relative path. The default implementation * logic is defined as follows: * * <pre><code> if( path != null ) * { * if( enclosed() ) * { * for( Path root : roots() ) * { * if( root is prefix of path ) * { * return path relative to root * } * } * } * else * { * for( Path root : roots() ) * { * if( root device matches path device ) * { * return path relative to root (possibly with parent navigations) * } * } * } * } * * return null</code></pre> * * <p>Can be overridden to customize conversion logic. The implementation must * return null if path parameter is null or if relative path could not be computed * for whatever reason. Exceptions must not be used to signal failure to convert.</p> * * @param path the absolute path that should be converted to relative * @return the relative path or null if a relative path could not be computed */ public Path convertToRelative( final Path path ) { if( path != null ) { if( enclosed() ) { for( Path root : roots() ) { if( root.isPrefixOf( path ) ) { return path.makeRelativeTo( root ); } } } else { final String pathDevice = path.getDevice(); for( Path root : roots() ) { if( MiscUtil.equal( pathDevice, root.getDevice() ) ) { return path.makeRelativeTo( root ); } } } } return null; } public final Path convertToRelative( final String path ) { if( path != null ) { return convertToRelative( new Path( path ) ); } return null; } /** * Converts the given relative path to an absolute path. The default implementation * logic is defined as follows: * * <pre><code> if( path != null ) * { * if( enclosed() and path starts with ".." ) * { * return null * } * * absolute = null * * for( Path root : roots() * { * absolute = canonicalize( root + path ) * * if( absolute path exists on the file system ) * { * break * } * } * * return absolute * } * * return null</code></pre> * * <p>Can be overridden to customize conversion logic. The implementation must * return null if path parameter is null or if absolute path could not be computed * for whatever reason. Exceptions must not be used to signal failure to convert.</p> * * @param path the relative path that should be converted to absolute * @return the absolute path or null if an absolute path could not be computed */ public Path convertToAbsolute( final Path path ) { if( path != null ) { if( enclosed() && path.segmentCount() > 0 && path.segment( 0 ).equals( ".." ) ) { return null; } Path absolute = null; for( Path root : roots() ) { try { final File file = root.append( path ).toFile().getCanonicalFile(); absolute = new Path( file.getPath() ); if( file.exists() ) { break; } } catch( IOException e ) { // Intentionally ignoring to continue to the next root. If none of the roots // produce a viable absolute path, a null return from this method signifies // being unable to convert the relative path. That is sufficient. } } return absolute; } return null; } public final Path convertToAbsolute( final String path ) { if( path != null ) { return convertToAbsolute( new Path( path ) ); } return null; } }