diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/Cache.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/Cache.java new file mode 100644 index 0000000000000000000000000000000000000000..5ef7dc81c66d1d759b4e8e206c02d22fdee5b48b --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/Cache.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server.ftp; + +import java.util.HashMap; +import java.util.Map; + +import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSet; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; + +/** + * Helper class to cache objects retrieved from remote services. Used by + * {@link FtpPathResolverContext}. + * + * @author Franz-Josef Elmer + */ +public class Cache +{ + private final Map<String, DataSet> dataSets = new HashMap<String, DataSet>(); + private final Map<String, ExternalData> externalData = new HashMap<String, ExternalData>(); + private final Map<String, Experiment> experiments = new HashMap<String, Experiment>(); + + void putDataSet(DataSet dataSet) + { + dataSets.put(dataSet.getCode(), dataSet); + } + + DataSet getDataSet(String dataSetCode) + { + return dataSets.get(dataSetCode); + } + + ExternalData getExternalData(String code) + { + return externalData.get(code); + } + + void putDataSet(ExternalData dataSet) + { + externalData.put(dataSet.getCode(), dataSet); + } + + Experiment getExperiment(String experimentId) + { + return experiments.get(experimentId); + } + + void putDataSet(Experiment experiment) + { + experiments.put(experiment.getIdentifier(), experiment); + } + +} \ No newline at end of file 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 75057e7aedb484197264aacd75266b5051fefd2f..49f25bdab30561ad0655bb26238bba85faa72eda 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 @@ -131,6 +131,11 @@ public class DSSFileSystemView implements FileSystemView } public FtpFile getFile(String path) throws FtpException + { + return getFile(path, new Cache()); + } + + public FtpFile getFile(String path, Cache cache) throws FtpException { String normalizedPath = normalizePath(path); @@ -144,7 +149,7 @@ public class DSSFileSystemView implements FileSystemView { FtpPathResolverContext context = new FtpPathResolverContext(sessionToken, service, generalInfoService, - pathResolverRegistry); + pathResolverRegistry, cache); return pathResolverRegistry.resolve(normalizedPath, context); } catch (RuntimeException rex) { diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpPathResolverContext.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpPathResolverContext.java index 17d97ea23846f66b8697a2d6ed48a3445537fdb8..292b8ea7715169fab06cc91ae7569bf876c553b7 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpPathResolverContext.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpPathResolverContext.java @@ -16,8 +16,19 @@ package ch.systemsx.cisd.openbis.dss.generic.server.ftp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSService; import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationService; +import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSet; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentFetchOptions; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory; /** * An object holding all necessary context information for ftp path resolution. @@ -35,13 +46,16 @@ public class FtpPathResolverContext private final IFtpPathResolverRegistry resolverRegistry; + private final Cache cache; + public FtpPathResolverContext(String sessionToken, IETLLIMSService service, IGeneralInformationService generalInfoService, - IFtpPathResolverRegistry resolverRegistry) + IFtpPathResolverRegistry resolverRegistry, Cache cache) { this.sessionToken = sessionToken; this.service = service; this.generalInfoService = generalInfoService; this.resolverRegistry = resolverRegistry; + this.cache = cache; } public String getSessionToken() @@ -53,6 +67,65 @@ public class FtpPathResolverContext { return service; } + + public DataSet getDataSet(String dataSetCode) + { + DataSet dataSet = cache.getDataSet(dataSetCode); + if (dataSet == null) + { + List<DataSet> dataSetsWithMetaData = + generalInfoService.getDataSetMetaData(sessionToken, + Arrays.asList(dataSetCode)); + dataSet = dataSetsWithMetaData.get(0); + cache.putDataSet(dataSet); + } + return dataSet; + } + + public List<ExternalData> listDataSetsByCode(List<String> codes) + { + List<String> codesToAskFor = new ArrayList<String>(); + List<ExternalData> dataSets = new ArrayList<ExternalData>(); + for (String code : codes) + { + ExternalData dataSet = cache.getExternalData(code); + if (dataSet == null) + { + codesToAskFor.add(code); + } else + { + dataSets.add(dataSet); + } + } + if (codesToAskFor.isEmpty() == false) + { + List<ExternalData> newDataSets = service.listDataSetsByCode(sessionToken, codesToAskFor); + for (ExternalData newDataSet : newDataSets) + { + cache.putDataSet(newDataSet); + dataSets.add(newDataSet); + } + } + return dataSets; + } + + public Experiment getExperiment(String experimentId) + { + Experiment experiment = cache.getExperiment(experimentId); + if (experiment == null) + { + ExperimentIdentifier experimentIdentifier = + new ExperimentIdentifierFactory(experimentId).createIdentifier(); + + List<Experiment> result = + service.listExperiments(sessionToken, + Collections.singletonList(experimentIdentifier), + new ExperimentFetchOptions()); + experiment = result.isEmpty() ? null : result.get(0); + cache.putDataSet(experiment); + } + return experiment; + } public IGeneralInformationService getGeneralInfoService() { diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServer.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServer.java index 95fac237ab66851bfcce9946cea70012e1bd8a2f..8f99c0b1bb4ea536e4cf143e157d533c6878ac71 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServer.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/FtpServer.java @@ -45,7 +45,6 @@ import org.apache.ftpserver.ftplet.AuthenticationFailedException; import org.apache.ftpserver.ftplet.DefaultFtpReply; import org.apache.ftpserver.ftplet.DefaultFtplet; import org.apache.ftpserver.ftplet.FileSystemFactory; -import org.apache.ftpserver.ftplet.FileSystemView; import org.apache.ftpserver.ftplet.FtpException; import org.apache.ftpserver.ftplet.FtpFile; import org.apache.ftpserver.ftplet.FtpRequest; @@ -250,7 +249,7 @@ public class FtpServer implements FileSystemFactory, org.apache.sshd.server.File } } - public FileSystemView createFileSystemView(User user) throws FtpException + public DSSFileSystemView createFileSystemView(User user) throws FtpException { if (user instanceof FtpUser) { @@ -269,7 +268,7 @@ public class FtpServer implements FileSystemFactory, org.apache.sshd.server.File User user = session.getAttribute(USER_KEY); try { - final FileSystemView view = createFileSystemView(user); + final DSSFileSystemView view = createFileSystemView(user); return new org.apache.sshd.server.FileSystemView() { @@ -280,7 +279,7 @@ public class FtpServer implements FileSystemFactory, org.apache.sshd.server.File public SshFile getFile(String file) { - return new FileView(view, file); + return new FileView(view, file, new Cache()); } }; } catch (FtpException ex) @@ -288,18 +287,20 @@ public class FtpServer implements FileSystemFactory, org.apache.sshd.server.File throw new IOException(ex.getMessage()); } } - + private static final class FileView implements SshFile { - private final FileSystemView fileView; + private final DSSFileSystemView fileView; private final String path; private final List<InputStream> inputStreams = new ArrayList<InputStream>(); private FtpFile file; + private final Cache cache; - FileView(FileSystemView fileView, String path) + FileView(DSSFileSystemView fileView, String path, Cache cache) { this.fileView = fileView; this.path = path; + this.cache = cache; } private FtpFile getFile() @@ -308,7 +309,7 @@ public class FtpServer implements FileSystemFactory, org.apache.sshd.server.File { try { - file = fileView.getFile(path); + file = fileView.getFile(path, cache); } catch (FtpException ex) { throw CheckedExceptionTunnel.wrapIfNecessary(ex); @@ -413,7 +414,7 @@ public class FtpServer implements FileSystemFactory, org.apache.sshd.server.File List<SshFile> result = new ArrayList<SshFile>(); for (FtpFile child : files) { - result.add(new FileView(fileView, child.getAbsolutePath())); + result.add(new FileView(fileView, child.getAbsolutePath(), cache)); } return result; } 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 b319876429277cccdf34d873b45860355376e55a..7dea42bfc1f27c9b365b496b89ef2f8308bce9fb 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 @@ -17,7 +17,6 @@ package ch.systemsx.cisd.openbis.dss.generic.server.ftp.resolver; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -49,14 +48,10 @@ import ch.systemsx.cisd.openbis.dss.generic.server.ftp.resolver.FtpFileEvaluatio import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider; import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSService; -import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationService; import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSet; import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentFetchOptions; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory; /** * Resolves paths like @@ -114,14 +109,7 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, List<FtpFile> result = new ArrayList<FtpFile>(); if (showParentsAndChildren) { - IGeneralInformationService generalInfoService = - resolverContext.getGeneralInfoService(); - String sessionToken = resolverContext.getSessionToken(); - List<DataSet> dataSetsWithMetaData = - generalInfoService.getDataSetMetaData(sessionToken, - Arrays.asList(dataSet.getCode())); - - DataSet dataSetWithMetaData = dataSetsWithMetaData.get(0); + DataSet dataSetWithMetaData = resolverContext.getDataSet(dataSet.getCode()); addNodesOfType(PARENT_PREFIX, result, dataSetWithMetaData.getParentCodes()); addNodesOfType(CHILD_PREFIX, result, dataSetWithMetaData.getChildrenCodes()); } @@ -156,9 +144,7 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, { return; } - String sessionToken = resolverContext.getSessionToken(); - List<ExternalData> dataSets = - resolverContext.getService().listDataSetsByCode(sessionToken, dataSetCodes); + List<ExternalData> dataSets = resolverContext.listDataSetsByCode(dataSetCodes); for (int i = 0; i < dataSets.size(); i++) { ExternalData ds = dataSets.get(i); @@ -248,7 +234,7 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, IETLLIMSService service = resolverContext.getService(); String sessionToken = resolverContext.getSessionToken(); - Experiment experiment = tryGetExperiment(experimentId, service, sessionToken); + Experiment experiment = tryGetExperiment(experimentId, resolverContext); if (experiment == null) { return FtpPathResolverRegistry.getNonExistingFile(path, "Unknown experiment '" @@ -403,30 +389,15 @@ public class TemplateBasedDataSetResourceResolver implements IFtpPathResolver, return result; } - private Experiment tryGetExperiment(String experimentId, IETLLIMSService service, - String sessionToken) + private Experiment tryGetExperiment(String experimentId, FtpPathResolverContext context) { - ExperimentIdentifier experimentIdentifier = - new ExperimentIdentifierFactory(experimentId).createIdentifier(); - - List<Experiment> result = null; try { - result = - service.listExperiments(sessionToken, - Collections.singletonList(experimentIdentifier), - new ExperimentFetchOptions()); + return context.getExperiment(experimentId); } catch (Throwable t) { operationLog.warn("Failed to get experiment with identifier :" + experimentId, t); - } - - if (result == null || result.isEmpty()) - { return null; - } else - { - return result.get(0); } } diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/TemplateBasedDataSetResourceResolverTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/TemplateBasedDataSetResourceResolverTest.java index f33201490cdf1b0ce9cbbc3d1731cf8efb298b67..140461400c0370121b41506c730bc49d79b7db05 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/TemplateBasedDataSetResourceResolverTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/resolver/TemplateBasedDataSetResourceResolverTest.java @@ -44,6 +44,7 @@ import ch.systemsx.cisd.common.io.hierarchical_content.api.IHierarchicalContent; import ch.systemsx.cisd.common.io.hierarchical_content.api.IHierarchicalContentNode; import ch.systemsx.cisd.common.test.TrackingMockery; import ch.systemsx.cisd.common.utilities.IDelegatedAction; +import ch.systemsx.cisd.openbis.dss.generic.server.ftp.Cache; import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpConstants; import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpPathResolverContext; import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpServerConfig; @@ -166,7 +167,7 @@ public class TemplateBasedDataSetResourceResolverTest extends AbstractFileSystem simpleFileContentProvider = new SimpleFileContentProvider(root); resolverContext = - new FtpPathResolverContext(SESSION_TOKEN, service, generalInfoService, null); + new FtpPathResolverContext(SESSION_TOKEN, service, generalInfoService, null, new Cache()); context.checking(new Expectations() { {