diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/DSSFileSystemView.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/DSSFileSystemView.java index d4d423da408075ed1d1b9d6efdcd538056c419aa..6ec471c0ffca140e3c6b6f5349d6102ca12949df 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/DSSFileSystemView.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/DSSFileSystemView.java @@ -143,7 +143,7 @@ public class DSSFileSystemView implements FileSystemView FtpPathResolverContext context = new FtpPathResolverContext(sessionToken, service, generalInfoService, pathResolverRegistry); - return pathResolverRegistry.tryResolve(normalizedPath, context); + return pathResolverRegistry.resolve(normalizedPath, context); } catch (RuntimeException rex) { String message = diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpPathResolverRegistry.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpPathResolverRegistry.java index 31b862e0fd498df745b90faf8b9bceaf454de57e..cee9ed0f854e7c1e3d39cf5936e859b5e72464b4 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpPathResolverRegistry.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpPathResolverRegistry.java @@ -16,9 +16,14 @@ package ch.systemsx.cisd.openbis.dss.generic.server.ftp; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import org.apache.commons.io.FilenameUtils; import org.apache.ftpserver.ftplet.FtpFile; import org.apache.log4j.Logger; @@ -72,7 +77,7 @@ public class FtpPathResolverRegistry implements IFtpPathResolverRegistry return null; } - public FtpFile tryResolve(String path, FtpPathResolverContext resolverContext) + public FtpFile resolve(String path, FtpPathResolverContext resolverContext) { IFtpPathResolver resolver = tryFindResolver(path); if (resolver != null) @@ -83,8 +88,137 @@ public class FtpPathResolverRegistry implements IFtpPathResolverRegistry String message = String.format("Cannot find resolver for path '%s'. Wrong user input ?", path); operationLog.warn(message); - return null; + return getNonExistingFile(path, message); } } + /** + * Create a representation for a non-existing {@link FtpFile}, optionally providing an error + * message. + */ + public static final FtpFile getNonExistingFile(final String path, final String errorMsgOrNull) + { + return new FtpFile() + { + public String getAbsolutePath() + { + return path; + } + + public String getName() + { + return FilenameUtils.getName(path); + } + + public boolean isHidden() + { + return false; + } + + public boolean isDirectory() + { + return false; + } + + public boolean isFile() + { + return false; + } + + public boolean doesExist() + { + return false; + } + + public boolean isReadable() + { + return false; + } + + public boolean isWritable() + { + return false; + } + + public boolean isRemovable() + { + return false; + } + + public String getOwnerName() + { + return "UNKNOWN"; + } + + public String getGroupName() + { + return "UNKNOWN"; + } + + public int getLinkCount() + { + return 0; + } + + public long getLastModified() + { + return 0; + } + + public boolean setLastModified(long time) + { + return false; + } + + public long getSize() + { + return 0; + } + + public boolean mkdir() + { + return false; + } + + public boolean delete() + { + return false; + } + + public boolean move(FtpFile destination) + { + return false; + } + + public List<FtpFile> listFiles() + { + return Collections.emptyList(); + } + + public OutputStream createOutputStream(long offset) throws IOException + { + if (errorMsgOrNull != null) + { + throw new IOException("File '" + path + "' does not exist (" + + errorMsgOrNull + "."); + } else + { + throw new IOException("File '" + path + "' does not exist."); + } + } + + public InputStream createInputStream(long offset) throws IOException + { + if (errorMsgOrNull != null) + { + throw new IOException("File '" + path + "' does not exist (" + + errorMsgOrNull + "."); + } else + { + throw new IOException("File '" + path + "' does not exist."); + } + } + }; + } + } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/IFtpPathResolverRegistry.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/IFtpPathResolverRegistry.java index ab79a831eeb77964fc143a2033b2d8d55d7f9956..35ecfca203ff3778174f1682bc3c6273b57a1c0a 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/IFtpPathResolverRegistry.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/IFtpPathResolverRegistry.java @@ -24,6 +24,11 @@ import org.apache.ftpserver.ftplet.FtpFile; public interface IFtpPathResolverRegistry { - FtpFile tryResolve(String path, FtpPathResolverContext resolverContext); + /** + * Returns an {@link FtpFile} for <var>path</var>. + * <p> + * <i>You need to check {@link FtpFile#doesExist()} before using it!</i> + */ + FtpFile resolve(String path, FtpPathResolverContext resolverContext); } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/ProjectFolderResolver.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/ProjectFolderResolver.java index fef581f8a4b4a5e5e2b639daf09c20786916c460..89e5903264c5a952443c8b04f3d6429e432c294e 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/ProjectFolderResolver.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/ProjectFolderResolver.java @@ -63,7 +63,7 @@ public class ProjectFolderResolver implements IFtpPathResolver String childPath = path + FtpConstants.FILE_SEPARATOR + experiment.getCode(); FtpFile childFile = - resolverContext.getResolverRegistry().tryResolve(childPath, + resolverContext.getResolverRegistry().resolve(childPath, resolverContext); result.add(childFile); } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/RootFolderResolver.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/RootFolderResolver.java index ab8597ebe75f29f599afa040ce54e07c866b70fd..c4140e267b26f2cdb5924967a5b491268ce27931 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/RootFolderResolver.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/RootFolderResolver.java @@ -64,7 +64,7 @@ public class RootFolderResolver implements IFtpPathResolver { String childPath = FtpConstants.ROOT_DIRECTORY + spaceCode; FtpFile child = - resolverContext.getResolverRegistry().tryResolve(childPath, + resolverContext.getResolverRegistry().resolve(childPath, resolverContext); if (child != null) { diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/SpaceFolderResolver.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/SpaceFolderResolver.java index 599d28dfcf798ce394a59f905bf0c6cd821a6888..d143eb18023900c7def7f6f63e17f60430e85e93 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/SpaceFolderResolver.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/SpaceFolderResolver.java @@ -70,7 +70,7 @@ public class SpaceFolderResolver implements IFtpPathResolver { String childPath = path + FtpConstants.FILE_SEPARATOR + childProject; FtpFile childFile = - resolverContext.getResolverRegistry().tryResolve(childPath, + resolverContext.getResolverRegistry().resolve(childPath, resolverContext); result.add(childFile); } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/TemplateBasedDataSetResourceResolver.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/TemplateBasedDataSetResourceResolver.java index 38d880cbf0b82c11780f50652a332ebede61bd8a..280f123407ca4f5f0af2d6b80295dd959ec71ac0 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/TemplateBasedDataSetResourceResolver.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/TemplateBasedDataSetResourceResolver.java @@ -42,6 +42,7 @@ import ch.systemsx.cisd.common.utilities.Template; import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpConstants; import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpFileFactory; import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpPathResolverContext; +import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpPathResolverRegistry; import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpServerConfig; import ch.systemsx.cisd.openbis.dss.generic.server.ftp.IFtpPathResolver; import ch.systemsx.cisd.openbis.dss.generic.server.ftp.resolver.FtpFileEvaluationContext.EvaluatedElement; @@ -58,9 +59,11 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifi /** * Resolves paths like + * * <pre> * /<space-code>/<project-code>/<experiment-code>/<dataset-template>[/[PARENT-<dataset-template>|CHILD-<dataset-template>|<sub-path>]]* * </pre> + * * to {@link FtpFile} objects. * <p> * Subpaths are resolved as relative paths starting from the root of a dataset. @@ -84,12 +87,12 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, private static final String DATA_SET_DATE_FORMAT = "yyyy-MM-dd-HH-mm"; private static final String PARENT_PREFIX = "PARENT-"; - + private static final String CHILD_PREFIX = "CHILD-"; - + private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, TemplateBasedDataSetResourceResolver.class); - + private final class DataSetFtpFolder extends AbstractFtpFolder { private final ExternalData dataSet; @@ -209,7 +212,7 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, private boolean fileNamePresent; private IHierarchicalContentProvider contentProvider; - + public TemplateBasedDataSetResourceResolver(FtpServerConfig ftpServerConfig) { this.template = new Template(ftpServerConfig.getDataSetDisplayTemplate()); @@ -217,14 +220,13 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, fileNamePresent = template.getPlaceholderNames().contains(FILE_NAME_VARNAME); if (fileNamePresent && showParentsAndChildren) { - throw new ConfigurationFailureException( - "Template contains file name variable and " - + "the flag to show parents/children data sets is set."); + throw new ConfigurationFailureException("Template contains file name variable and " + + "the flag to show parents/children data sets is set."); } this.dataSetTypeConfigs = initializeDataSetTypeConfigs(ftpServerConfig); this.defaultDSTypeConfig = new DataSetTypeConfig(); } - + void setContentProvider(IHierarchicalContentProvider contentProvider) { this.contentProvider = contentProvider; @@ -248,14 +250,15 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, Experiment experiment = tryGetExperiment(experimentId, service, sessionToken); if (experiment == null) { - throw new IllegalArgumentException("Unknown experiment '" + experimentId + "'."); + return FtpPathResolverRegistry.getNonExistingFile(path, "Unknown experiment '" + + experimentId + "'."); } List<ExternalData> dataSets = service.listDataSetsByExperimentID(sessionToken, new TechId(experiment)); if (fileNamePresent) { FtpFileEvaluationContext evalContext = evaluateDataSetPaths(dataSets); - + try { return extractMatchingFileOrNull(path, experimentId, evalContext); @@ -282,7 +285,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ExternalData dataSet = tryToFindDataSet(dataSets, dataSetPathElement); if (dataSet == null) { - throw createException(dataSetPathElement); + return FtpPathResolverRegistry.getNonExistingFile(path, + "No match found for path element '" + dataSetPathElement + "'."); } String subPath = StringUtils.join(pathElements, FtpConstants.FILE_SEPARATOR, 0, i + 1); @@ -301,7 +305,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, } if (matchingFile == null) { - throw createException(dataSetPathElement); + return FtpPathResolverRegistry.getNonExistingFile(path, + "No match found for path element '" + dataSetPathElement + "'."); } result = matchingFile; } @@ -309,12 +314,6 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, return result; } - private IllegalArgumentException createException(String dataSetPathElement) - { - return new IllegalArgumentException("No match found for path element '" - + dataSetPathElement + "'."); - } - private ExternalData tryToFindDataSet(List<ExternalData> dataSets, String dataSetPathElement) { for (int disambiguationIdx = 0; disambiguationIdx < dataSets.size(); disambiguationIdx++) @@ -464,8 +463,7 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, String childPath = parentPath + FtpConstants.FILE_SEPARATOR + evalElement.evaluatedTemplate; String dataSetCode = evalElement.dataSet.getCode(); - IHierarchicalContentProvider getContentProvider = - getContentProvider(); + IHierarchicalContentProvider getContentProvider = getContentProvider(); FtpFile childFtpFile = FtpFileFactory.createFtpFile(dataSetCode, childPath, @@ -572,7 +570,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, /** * @return all values to be used when evaluating the template "${fileName}" variable. */ - private List<IHierarchicalContentNode> getFileNamesRequiredByTemplate(IHierarchicalContentNode rootNode) + private List<IHierarchicalContentNode> getFileNamesRequiredByTemplate( + IHierarchicalContentNode rootNode) { if (fileNamePresent) { @@ -603,7 +602,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, /** * Formats a date as it will appear after template evaluation. */ - @Private static String extractDateValue(Date dataSetDate) + @Private + static String extractDateValue(Date dataSetDate) { return DateFormatUtils.format(dataSetDate, DATA_SET_DATE_FORMAT); } @@ -692,5 +692,5 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, } return contentProvider; } - + } diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/DSSFileSystemViewTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/DSSFileSystemViewTest.java index c2e23d5bd37dc23ac3a2961a20d1734fc6e095df..17d368af1d1e954cea2baa48383df1aa76c51de0 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/DSSFileSystemViewTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/DSSFileSystemViewTest.java @@ -110,7 +110,7 @@ public class DSSFileSystemViewTest extends AssertJUnit { { RecordingMatcher<FtpPathResolverContext> recorder = new RecordingMatcher<FtpPathResolverContext>(); - one(registry).tryResolve(with(normalizedPath), with(recorder)); + one(registry).resolve(with(normalizedPath), with(recorder)); will(returnValue(new AbstractFtpFile(normalizedPath) {