Skip to content
Snippets Groups Projects
Commit 23083fe8 authored by brinn's avatar brinn
Browse files

Fix issue that FileView.doesExist() throws an FTPException if the file does...

Fix issue that FileView.doesExist() throws an FTPException if the file does not exist rather than returning false. This lead to some strange effects with Windows clients.

SVN: 24250
parent cf057a38
No related branches found
No related tags found
No related merge requests found
Showing
with 170 additions and 31 deletions
...@@ -143,7 +143,7 @@ public class DSSFileSystemView implements FileSystemView ...@@ -143,7 +143,7 @@ public class DSSFileSystemView implements FileSystemView
FtpPathResolverContext context = FtpPathResolverContext context =
new FtpPathResolverContext(sessionToken, service, generalInfoService, new FtpPathResolverContext(sessionToken, service, generalInfoService,
pathResolverRegistry); pathResolverRegistry);
return pathResolverRegistry.tryResolve(normalizedPath, context); return pathResolverRegistry.resolve(normalizedPath, context);
} catch (RuntimeException rex) } catch (RuntimeException rex)
{ {
String message = String message =
......
...@@ -16,9 +16,14 @@ ...@@ -16,9 +16,14 @@
package ch.systemsx.cisd.openbis.dss.generic.server.ftp; 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.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.commons.io.FilenameUtils;
import org.apache.ftpserver.ftplet.FtpFile; import org.apache.ftpserver.ftplet.FtpFile;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
...@@ -72,7 +77,7 @@ public class FtpPathResolverRegistry implements IFtpPathResolverRegistry ...@@ -72,7 +77,7 @@ public class FtpPathResolverRegistry implements IFtpPathResolverRegistry
return null; return null;
} }
public FtpFile tryResolve(String path, FtpPathResolverContext resolverContext) public FtpFile resolve(String path, FtpPathResolverContext resolverContext)
{ {
IFtpPathResolver resolver = tryFindResolver(path); IFtpPathResolver resolver = tryFindResolver(path);
if (resolver != null) if (resolver != null)
...@@ -83,8 +88,137 @@ public class FtpPathResolverRegistry implements IFtpPathResolverRegistry ...@@ -83,8 +88,137 @@ public class FtpPathResolverRegistry implements IFtpPathResolverRegistry
String message = String message =
String.format("Cannot find resolver for path '%s'. Wrong user input ?", path); String.format("Cannot find resolver for path '%s'. Wrong user input ?", path);
operationLog.warn(message); 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.");
}
}
};
}
} }
...@@ -24,6 +24,11 @@ import org.apache.ftpserver.ftplet.FtpFile; ...@@ -24,6 +24,11 @@ import org.apache.ftpserver.ftplet.FtpFile;
public interface IFtpPathResolverRegistry 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);
} }
...@@ -63,7 +63,7 @@ public class ProjectFolderResolver implements IFtpPathResolver ...@@ -63,7 +63,7 @@ public class ProjectFolderResolver implements IFtpPathResolver
String childPath = String childPath =
path + FtpConstants.FILE_SEPARATOR + experiment.getCode(); path + FtpConstants.FILE_SEPARATOR + experiment.getCode();
FtpFile childFile = FtpFile childFile =
resolverContext.getResolverRegistry().tryResolve(childPath, resolverContext.getResolverRegistry().resolve(childPath,
resolverContext); resolverContext);
result.add(childFile); result.add(childFile);
} }
......
...@@ -64,7 +64,7 @@ public class RootFolderResolver implements IFtpPathResolver ...@@ -64,7 +64,7 @@ public class RootFolderResolver implements IFtpPathResolver
{ {
String childPath = FtpConstants.ROOT_DIRECTORY + spaceCode; String childPath = FtpConstants.ROOT_DIRECTORY + spaceCode;
FtpFile child = FtpFile child =
resolverContext.getResolverRegistry().tryResolve(childPath, resolverContext.getResolverRegistry().resolve(childPath,
resolverContext); resolverContext);
if (child != null) if (child != null)
{ {
......
...@@ -70,7 +70,7 @@ public class SpaceFolderResolver implements IFtpPathResolver ...@@ -70,7 +70,7 @@ public class SpaceFolderResolver implements IFtpPathResolver
{ {
String childPath = path + FtpConstants.FILE_SEPARATOR + childProject; String childPath = path + FtpConstants.FILE_SEPARATOR + childProject;
FtpFile childFile = FtpFile childFile =
resolverContext.getResolverRegistry().tryResolve(childPath, resolverContext.getResolverRegistry().resolve(childPath,
resolverContext); resolverContext);
result.add(childFile); result.add(childFile);
} }
......
...@@ -42,6 +42,7 @@ import ch.systemsx.cisd.common.utilities.Template; ...@@ -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.FtpConstants;
import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpFileFactory; 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.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.FtpServerConfig;
import ch.systemsx.cisd.openbis.dss.generic.server.ftp.IFtpPathResolver; import ch.systemsx.cisd.openbis.dss.generic.server.ftp.IFtpPathResolver;
import ch.systemsx.cisd.openbis.dss.generic.server.ftp.resolver.FtpFileEvaluationContext.EvaluatedElement; 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 ...@@ -58,9 +59,11 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifi
/** /**
* Resolves paths like * Resolves paths like
*
* <pre> * <pre>
* /&lt;space-code>/&lt;project-code>/&lt;experiment-code>/&lt;dataset-template>[/[PARENT-&lt;dataset-template>|CHILD-&lt;dataset-template>|&lt;sub-path>]]* * /&lt;space-code>/&lt;project-code>/&lt;experiment-code>/&lt;dataset-template>[/[PARENT-&lt;dataset-template>|CHILD-&lt;dataset-template>|&lt;sub-path>]]*
* </pre> * </pre>
*
* to {@link FtpFile} objects. * to {@link FtpFile} objects.
* <p> * <p>
* Subpaths are resolved as relative paths starting from the root of a dataset. * Subpaths are resolved as relative paths starting from the root of a dataset.
...@@ -84,12 +87,12 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -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 DATA_SET_DATE_FORMAT = "yyyy-MM-dd-HH-mm";
private static final String PARENT_PREFIX = "PARENT-"; private static final String PARENT_PREFIX = "PARENT-";
private static final String CHILD_PREFIX = "CHILD-"; private static final String CHILD_PREFIX = "CHILD-";
private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
TemplateBasedDataSetResourceResolver.class); TemplateBasedDataSetResourceResolver.class);
private final class DataSetFtpFolder extends AbstractFtpFolder private final class DataSetFtpFolder extends AbstractFtpFolder
{ {
private final ExternalData dataSet; private final ExternalData dataSet;
...@@ -209,7 +212,7 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -209,7 +212,7 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver,
private boolean fileNamePresent; private boolean fileNamePresent;
private IHierarchicalContentProvider contentProvider; private IHierarchicalContentProvider contentProvider;
public TemplateBasedDataSetResourceResolver(FtpServerConfig ftpServerConfig) public TemplateBasedDataSetResourceResolver(FtpServerConfig ftpServerConfig)
{ {
this.template = new Template(ftpServerConfig.getDataSetDisplayTemplate()); this.template = new Template(ftpServerConfig.getDataSetDisplayTemplate());
...@@ -217,14 +220,13 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -217,14 +220,13 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver,
fileNamePresent = template.getPlaceholderNames().contains(FILE_NAME_VARNAME); fileNamePresent = template.getPlaceholderNames().contains(FILE_NAME_VARNAME);
if (fileNamePresent && showParentsAndChildren) if (fileNamePresent && showParentsAndChildren)
{ {
throw new ConfigurationFailureException( throw new ConfigurationFailureException("Template contains file name variable and "
"Template contains file name variable and " + "the flag to show parents/children data sets is set.");
+ "the flag to show parents/children data sets is set.");
} }
this.dataSetTypeConfigs = initializeDataSetTypeConfigs(ftpServerConfig); this.dataSetTypeConfigs = initializeDataSetTypeConfigs(ftpServerConfig);
this.defaultDSTypeConfig = new DataSetTypeConfig(); this.defaultDSTypeConfig = new DataSetTypeConfig();
} }
void setContentProvider(IHierarchicalContentProvider contentProvider) void setContentProvider(IHierarchicalContentProvider contentProvider)
{ {
this.contentProvider = contentProvider; this.contentProvider = contentProvider;
...@@ -248,14 +250,15 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -248,14 +250,15 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver,
Experiment experiment = tryGetExperiment(experimentId, service, sessionToken); Experiment experiment = tryGetExperiment(experimentId, service, sessionToken);
if (experiment == null) if (experiment == null)
{ {
throw new IllegalArgumentException("Unknown experiment '" + experimentId + "'."); return FtpPathResolverRegistry.getNonExistingFile(path, "Unknown experiment '"
+ experimentId + "'.");
} }
List<ExternalData> dataSets = List<ExternalData> dataSets =
service.listDataSetsByExperimentID(sessionToken, new TechId(experiment)); service.listDataSetsByExperimentID(sessionToken, new TechId(experiment));
if (fileNamePresent) if (fileNamePresent)
{ {
FtpFileEvaluationContext evalContext = evaluateDataSetPaths(dataSets); FtpFileEvaluationContext evalContext = evaluateDataSetPaths(dataSets);
try try
{ {
return extractMatchingFileOrNull(path, experimentId, evalContext); return extractMatchingFileOrNull(path, experimentId, evalContext);
...@@ -282,7 +285,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -282,7 +285,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver,
ExternalData dataSet = tryToFindDataSet(dataSets, dataSetPathElement); ExternalData dataSet = tryToFindDataSet(dataSets, dataSetPathElement);
if (dataSet == null) if (dataSet == null)
{ {
throw createException(dataSetPathElement); return FtpPathResolverRegistry.getNonExistingFile(path,
"No match found for path element '" + dataSetPathElement + "'.");
} }
String subPath = String subPath =
StringUtils.join(pathElements, FtpConstants.FILE_SEPARATOR, 0, i + 1); StringUtils.join(pathElements, FtpConstants.FILE_SEPARATOR, 0, i + 1);
...@@ -301,7 +305,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -301,7 +305,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver,
} }
if (matchingFile == null) if (matchingFile == null)
{ {
throw createException(dataSetPathElement); return FtpPathResolverRegistry.getNonExistingFile(path,
"No match found for path element '" + dataSetPathElement + "'.");
} }
result = matchingFile; result = matchingFile;
} }
...@@ -309,12 +314,6 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -309,12 +314,6 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver,
return result; 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) private ExternalData tryToFindDataSet(List<ExternalData> dataSets, String dataSetPathElement)
{ {
for (int disambiguationIdx = 0; disambiguationIdx < dataSets.size(); disambiguationIdx++) for (int disambiguationIdx = 0; disambiguationIdx < dataSets.size(); disambiguationIdx++)
...@@ -464,8 +463,7 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -464,8 +463,7 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver,
String childPath = String childPath =
parentPath + FtpConstants.FILE_SEPARATOR + evalElement.evaluatedTemplate; parentPath + FtpConstants.FILE_SEPARATOR + evalElement.evaluatedTemplate;
String dataSetCode = evalElement.dataSet.getCode(); String dataSetCode = evalElement.dataSet.getCode();
IHierarchicalContentProvider getContentProvider = IHierarchicalContentProvider getContentProvider = getContentProvider();
getContentProvider();
FtpFile childFtpFile = FtpFile childFtpFile =
FtpFileFactory.createFtpFile(dataSetCode, childPath, FtpFileFactory.createFtpFile(dataSetCode, childPath,
...@@ -572,7 +570,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -572,7 +570,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver,
/** /**
* @return all values to be used when evaluating the template "${fileName}" variable. * @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) if (fileNamePresent)
{ {
...@@ -603,7 +602,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -603,7 +602,8 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver,
/** /**
* Formats a date as it will appear after template evaluation. * 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); return DateFormatUtils.format(dataSetDate, DATA_SET_DATE_FORMAT);
} }
...@@ -692,5 +692,5 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, ...@@ -692,5 +692,5 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver,
} }
return contentProvider; return contentProvider;
} }
} }
...@@ -110,7 +110,7 @@ public class DSSFileSystemViewTest extends AssertJUnit ...@@ -110,7 +110,7 @@ public class DSSFileSystemViewTest extends AssertJUnit
{ {
{ {
RecordingMatcher<FtpPathResolverContext> recorder = new RecordingMatcher<FtpPathResolverContext>(); 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) will(returnValue(new AbstractFtpFile(normalizedPath)
{ {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment