diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java index 5419d242e6727f0d7a07f5182cc198460503560e..8a05aa1779f8972b298edeee6ceb2240b00ea24c 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java @@ -33,6 +33,7 @@ import ch.systemsx.cisd.cifex.rpc.client.ICIFEXComponent; import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; import ch.systemsx.cisd.common.exceptions.InvalidAuthenticationException; import ch.systemsx.cisd.common.exceptions.InvalidSessionException; +import ch.systemsx.cisd.common.filesystem.QueueingPathRemoverService; import ch.systemsx.cisd.common.mail.IMailClient; import ch.systemsx.cisd.common.mail.MailClient; import ch.systemsx.cisd.common.mail.MailClientParameters; @@ -82,7 +83,7 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic private final MailClientParameters mailClientParameters; - private final PluginTaskInfoProvider pluginTaskParameters; + private final PluginTaskInfoProvider pluginTaskInfoProvider; private IHierarchicalContentProvider hierarchicalContentProvider; @@ -120,7 +121,7 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic this.sessionTokenManager = sessionTokenManager; this.commandExecutorFactory = commandExecutorFactory; this.mailClientParameters = mailClientParameters; - this.pluginTaskParameters = pluginTaskParameters; + this.pluginTaskInfoProvider = pluginTaskParameters; storeRoot = pluginTaskParameters.getStoreRoot(); } @@ -320,7 +321,7 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic sessionTokenManager.assertValidSessionToken(sessionToken); PluginTaskProvider<IReportingPluginTask> reportingPlugins = - pluginTaskParameters.getReportingPluginsProvider(); + pluginTaskInfoProvider.getReportingPluginsProvider(); IReportingPluginTask task = reportingPlugins.getPluginInstance(serviceKey); IShareIdManager manager = getShareIdManager(); try @@ -330,10 +331,16 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic manager.lock(dataSet.getDataSetCode()); } IMailClient mailClient = createEMailClient(); - return task.createReport(datasets, new DataSetProcessingContext( - getHierarchicalContentProvider(), new DataSetDirectoryProvider(storeRoot, - manager), new HashMap<String, String>(), mailClient, userEmailOrNull, - userSessionToken)); + return task.createReport( + datasets, + new DataSetProcessingContext( + getHierarchicalContentProvider(), new DataSetDirectoryProvider( + storeRoot, + manager), new SessionWorkspaceProvider(pluginTaskInfoProvider + .getSessionWorkspaceRootDir(), + userSessionToken), + new HashMap<String, String>(), mailClient, userEmailOrNull, + userSessionToken)); } finally { @@ -349,7 +356,7 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic sessionTokenManager.assertValidSessionToken(sessionToken); PluginTaskProvider<IProcessingPluginTask> plugins = - pluginTaskParameters.getProcessingPluginsProvider(); + pluginTaskInfoProvider.getProcessingPluginsProvider(); IProcessingPluginTask task = plugins.getPluginInstance(serviceKey); DatastoreServiceDescription pluginDescription = plugins.getPluginDescription(serviceKey); @@ -381,7 +388,7 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic @Override public IArchiverPlugin getArchiverPlugin() { - ArchiverPluginFactory factory = pluginTaskParameters.getArchiverPluginFactory(); + ArchiverPluginFactory factory = pluginTaskInfoProvider.getArchiverPluginFactory(); return factory.createInstance(storeRoot); } @@ -398,16 +405,22 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic { sessionTokenManager.assertValidSessionToken(sessionToken); PluginTaskProvider<IReportingPluginTask> reportingPlugins = - pluginTaskParameters.getReportingPluginsProvider(); + pluginTaskInfoProvider.getReportingPluginsProvider(); IReportingPluginTask task = reportingPlugins.getPluginInstance(serviceKey); IShareIdManager manager = getShareIdManager(); try { IMailClient mailClient = createEMailClient(); - return task.createAggregationReport(parameters, new DataSetProcessingContext( - getHierarchicalContentProvider(), new DataSetDirectoryProvider(storeRoot, - manager), new HashMap<String, String>(), mailClient, userEmailOrNull, - userSessionToken)); + return task.createAggregationReport( + parameters, + new DataSetProcessingContext( + getHierarchicalContentProvider(), new DataSetDirectoryProvider( + storeRoot, + manager), new SessionWorkspaceProvider(pluginTaskInfoProvider + .getSessionWorkspaceRootDir(), + userSessionToken), + new HashMap<String, String>(), mailClient, userEmailOrNull, + userSessionToken)); } finally { @@ -492,7 +505,7 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic sessionTokenManager.assertValidSessionToken(sessionToken); PluginTaskProvider<IReportingPluginTask> reportingPlugins = - pluginTaskParameters.getReportingPluginsProvider(); + pluginTaskInfoProvider.getReportingPluginsProvider(); IReportingPluginTask task = reportingPlugins.getPluginInstance(serviceKey); return task.createLink(dataSet); } @@ -511,6 +524,17 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic return service.putDataSet(sessionToken, dropboxName, customImportFile); } + @Override + public void cleanupSession(String userSessionToken) + { + final File sessionWorkspace = + new File(pluginTaskInfoProvider.getSessionWorkspaceRootDir(), userSessionToken); + if (sessionWorkspace.exists()) + { + QueueingPathRemoverService.removeRecursively(sessionWorkspace); + } + } + private PutDataSetService getPutDataSetService() { if (putService == null) diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java index 39b74ad44d339547f79fd1d7cf84bea8f6d9dab9..2ad2542bb904578b31facd2dc906a59acacbbc9a 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java @@ -193,4 +193,10 @@ class DataStoreServiceLogger implements IDataStoreService, IInitializable log("putDataSet", "DROPBOX_NAME(%s), CUSTOM_IMPORT_FILE(%s)", dropboxName, customImportFile); return null; } + + @Override + public void cleanupSession(String userSessionToken) + { + log("cleanupSession", "USER_SESSION(%s)", userSessionToken); + } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ISessionWorkspaceProvider.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ISessionWorkspaceProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..b236fadfb93b0aaee33ddc9ba8e560b36e50d57b --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ISessionWorkspaceProvider.java @@ -0,0 +1,36 @@ +/* + * 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; + +import java.io.File; + +/** + * A provider for a workspace directory with the lifetime of a user session. + * + * @author Bernd Rinn + */ +public interface ISessionWorkspaceProvider +{ + + /** + * Returns the directory representing this user session's workspace. + * <p> + * Files put in this directory will be available during the user session and will be + * automatically cleaned up when the user session is closed (or expires). + */ + public File getSessionWorkspace(); +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/SessionWorkspaceProvider.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/SessionWorkspaceProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..6db05f12b56e1d0a821f5878521f6d099d14b7b7 --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/SessionWorkspaceProvider.java @@ -0,0 +1,48 @@ +/* + * 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; + +import java.io.File; + +/** + * A provider for the session workspace directory. + * + * @author Bernd Rinn + */ +public class SessionWorkspaceProvider implements ISessionWorkspaceProvider +{ + private final String sessionToken; + + private final File sessionWorkspace; + + public SessionWorkspaceProvider(File sessionWorkspaceRootDirectory, String userSessionToken) + { + this.sessionToken = userSessionToken; + this.sessionWorkspace = new File(sessionWorkspaceRootDirectory, sessionToken); + } + + @Override + public File getSessionWorkspace() + { + if (sessionWorkspace.exists() == false) + { + sessionWorkspace.mkdirs(); + } + return sessionWorkspace; + } + +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/jython/PluginScriptRunnerFactory.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/jython/PluginScriptRunnerFactory.java index 0d490b06febe67bb9a453e77aa61d1c6e2689672..55f7e46a09194af79d497511004ab2b19d1fb9c6 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/jython/PluginScriptRunnerFactory.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/jython/PluginScriptRunnerFactory.java @@ -32,6 +32,7 @@ import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.common.shared.basic.utils.StringUtils; import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSetRegistrationTransactionV2; +import ch.systemsx.cisd.openbis.dss.generic.server.ISessionWorkspaceProvider; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.jython.api.IDataSet; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.jython.api.IMailService; import ch.systemsx.cisd.openbis.dss.generic.shared.DataSetProcessingContext; @@ -66,6 +67,8 @@ public class PluginScriptRunnerFactory implements IPluginScriptRunnerFactory private final static String AUTHORIZATION_SERVICE = "authorizationService"; private static final String CONTENT_PROVIDER_VARIABLE_NAME = "contentProvider"; + + private static final String SESSION_WORKSPACE_PROVIDER_NAME = "sessionWorkspaceProvider"; private final String scriptPath; @@ -187,6 +190,11 @@ public class PluginScriptRunnerFactory implements IPluginScriptRunnerFactory evaluator.set(MAIL_SERVICE_VARIABLE_NAME, createMailService(context)); evaluator.set(DATA_SOURCE_QUERY_SERVICE_VARIABLE_NAME, createDataSourceQueryService()); evaluator.set(AUTHORIZATION_SERVICE, createAuthorizationService()); + final ISessionWorkspaceProvider workspaceProvider = context.tryGetSessionWorkspaceProvider(); + if (workspaceProvider != null) + { + evaluator.set(SESSION_WORKSPACE_PROVIDER_NAME, workspaceProvider); + } return evaluator; } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/PluginTaskInfoProvider.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/PluginTaskInfoProvider.java index df99ca820842bb771d0340b8c7dc3fe569619e58..ca03d064ae3471e0065dc7857054ef3622318632 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/PluginTaskInfoProvider.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/PluginTaskInfoProvider.java @@ -37,6 +37,10 @@ public class PluginTaskInfoProvider { public static final String STOREROOT_DIR_KEY = "storeroot-dir"; + private static final String SESSION_WORKSPACE_ROOT_DIR_KEY = "session-workspace-root-dir"; + + private static final String SESSION_WORKSPACE_ROOT_DIR_DEFAULT = "sessionWorkspace"; + /** name of archiver properties section */ @Private static final String ARCHIVER_SECTION_NAME = "archiver"; @@ -49,6 +53,8 @@ public class PluginTaskInfoProvider private final File storeRoot; + private final File sessionWorkspaceRootDir; + /** for external injections */ public static PluginTaskInfoProvider create() { @@ -56,8 +62,13 @@ public class PluginTaskInfoProvider Properties properties = DssPropertyParametersUtil.loadServiceProperties(); final String storeRootDir = properties.getProperty(STOREROOT_DIR_KEY); final File storeRoot = new File(storeRootDir); - final PluginTaskInfoProvider providers = - new PluginTaskInfoProvider(properties, servletPropertiesManager, storeRoot); + final String workspaceRootDir = + properties.getProperty(SESSION_WORKSPACE_ROOT_DIR_KEY, + SESSION_WORKSPACE_ROOT_DIR_DEFAULT); + final File workspaceRoot = new File(workspaceRootDir); + PluginTaskInfoProvider providers = + new PluginTaskInfoProvider(properties, servletPropertiesManager, storeRoot, + workspaceRoot); providers.check(); providers.logConfigurations(); return providers; @@ -66,9 +77,11 @@ public class PluginTaskInfoProvider @Private // public only for tests public PluginTaskInfoProvider(Properties serviceProperties, - IServletPropertiesManager servletPropertiesManager, File storeRoot) + IServletPropertiesManager servletPropertiesManager, File storeRoot, + File sessionWorkspaceRoot) { this.storeRoot = storeRoot; + this.sessionWorkspaceRootDir = sessionWorkspaceRoot; String datastoreCode = DssPropertyParametersUtil.getDataStoreCode(serviceProperties); this.reportingPlugins = createReportingPluginsFactories(serviceProperties, servletPropertiesManager, @@ -87,6 +100,14 @@ public class PluginTaskInfoProvider return storeRoot; } + /** + * Returns the root directory of session workspaces. + */ + public File getSessionWorkspaceRootDir() + { + return sessionWorkspaceRootDir; + } + public PluginTaskProvider<IReportingPluginTask> getReportingPluginsProvider() { return reportingPlugins; diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DataSetProcessingContext.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DataSetProcessingContext.java index 233bdb72fa14705cd5caf37a51b22cba07d4c68d..b03d2264b9f49ec7ea869af7b9597993cd33291d 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DataSetProcessingContext.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DataSetProcessingContext.java @@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.dss.generic.shared; import java.util.Map; import ch.systemsx.cisd.common.mail.IMailClient; +import ch.systemsx.cisd.openbis.dss.generic.server.ISessionWorkspaceProvider; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IProcessingPluginTask; /** @@ -40,6 +41,8 @@ public class DataSetProcessingContext private final String sessionTokenOrNull; + private final ISessionWorkspaceProvider sessionWorkspaceProviderOrNull; + /** * Creates an instance for specified directory provider, parameter bindings, e-mail client, and * optional user e-mail address and sessionToken. @@ -59,6 +62,20 @@ public class DataSetProcessingContext public DataSetProcessingContext(IHierarchicalContentProvider contentProvider, IDataSetDirectoryProvider directoryProvider, Map<String, String> parameterBindings, IMailClient mailClient, String userEmailOrNull, String sessionTokenOrNull) + { + this(contentProvider, directoryProvider, null, parameterBindings, mailClient, + userEmailOrNull, sessionTokenOrNull); + } + + /** + * Creates an instance for specified directory provider, workspace provider, parameter bindings, + * e-mail client, and optional user e-mail address and sessionToken. + */ + public DataSetProcessingContext(IHierarchicalContentProvider contentProvider, + IDataSetDirectoryProvider directoryProvider, + ISessionWorkspaceProvider sessionWorkspaceProviderOrNull, + Map<String, String> parameterBindings, + IMailClient mailClient, String userEmailOrNull, String sessionTokenOrNull) { this.hierarchicalContentProvider = contentProvider; this.directoryProvider = directoryProvider; @@ -66,6 +83,7 @@ public class DataSetProcessingContext this.mailClient = mailClient; this.userEmailOrNull = userEmailOrNull; this.sessionTokenOrNull = sessionTokenOrNull; + this.sessionWorkspaceProviderOrNull = sessionWorkspaceProviderOrNull; } public IDataSetDirectoryProvider getDirectoryProvider() @@ -73,6 +91,15 @@ public class DataSetProcessingContext return directoryProvider; } + /** + * Returns the session workspace provider of this context, if available and <code>null</code> if + * this context has no session workspace provider. + */ + public ISessionWorkspaceProvider tryGetSessionWorkspaceProvider() + { + return sessionWorkspaceProviderOrNull; + } + public final Map<String, String> getParameterBindings() { return parameterBindings; diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonBusinessObjectFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonBusinessObjectFactory.java index e220ade5f280a08bb8a7704e2d23224ba21c43c3..41e7812e8ea2d94098c7fa2eafeeb510c5ca34e7 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonBusinessObjectFactory.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonBusinessObjectFactory.java @@ -32,7 +32,6 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.ExperimentBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.ExperimentTable; import ch.systemsx.cisd.openbis.generic.server.business.bo.GridCustomColumnBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.GridCustomFilterBO; -import ch.systemsx.cisd.openbis.generic.server.business.bo.SpaceBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.IAttachmentBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.IAuthorizationGroupBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory; @@ -47,7 +46,6 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.IEntityTypePropertyTy import ch.systemsx.cisd.openbis.generic.server.business.bo.IExperimentBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.IExperimentTable; import ch.systemsx.cisd.openbis.generic.server.business.bo.IGridCustomFilterOrColumnBO; -import ch.systemsx.cisd.openbis.generic.server.business.bo.ISpaceBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.IMaterialBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.IMaterialTable; import ch.systemsx.cisd.openbis.generic.server.business.bo.IProjectBO; @@ -57,6 +55,7 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.IRoleAssignmentTable; import ch.systemsx.cisd.openbis.generic.server.business.bo.ISampleBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.ISampleTable; import ch.systemsx.cisd.openbis.generic.server.business.bo.IScriptBO; +import ch.systemsx.cisd.openbis.generic.server.business.bo.ISpaceBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.ITrashBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.IVocabularyBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.IVocabularyTermBO; @@ -69,6 +68,7 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.RoleAssignmentTable; import ch.systemsx.cisd.openbis.generic.server.business.bo.SampleBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.SampleTable; import ch.systemsx.cisd.openbis.generic.server.business.bo.ScriptBO; +import ch.systemsx.cisd.openbis.generic.server.business.bo.SpaceBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.TrashBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.VocabularyBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.VocabularyTermBO; @@ -94,10 +94,20 @@ public final class CommonBusinessObjectFactory extends AbstractBusinessObjectFac ICommonBusinessObjectFactory { + private final DataStoreUserSessionCleaner dssUserSessionCleaner; + public CommonBusinessObjectFactory(IDAOFactory daoFactory, IDataStoreServiceFactory dssFactory, - IRelationshipService relationshipService, IEntityOperationChecker entityOperationChecker) + IRelationshipService relationshipService, + IEntityOperationChecker entityOperationChecker, + DataStoreUserSessionCleaner dssUserSessionCleaner) { super(daoFactory, dssFactory, relationshipService, entityOperationChecker); + this.dssUserSessionCleaner = dssUserSessionCleaner; + } + + protected DataStoreUserSessionCleaner getDssUserSessionCleaner() + { + return dssUserSessionCleaner; } @Override @@ -165,7 +175,8 @@ public final class CommonBusinessObjectFactory extends AbstractBusinessObjectFac @Override public final IDataSetTable createDataSetTable(final Session session) { - return new DataSetTable(getDaoFactory(), getDSSFactory(), session, getRelationshipService()); + return new DataSetTable(getDaoFactory(), getDSSFactory(), getDssUserSessionCleaner(), + session, getRelationshipService()); } @Override diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/DataStoreUserSessionCleaner.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/DataStoreUserSessionCleaner.java new file mode 100644 index 0000000000000000000000000000000000000000..73b650fbb1a306ed97dc0bcb31a8994eca703c19 --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/DataStoreUserSessionCleaner.java @@ -0,0 +1,69 @@ +/* + * 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.generic.server; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService; +import ch.systemsx.cisd.openbis.generic.shared.dto.Session; +import ch.systemsx.cisd.openbis.generic.shared.dto.Session.ISessionCleaner; + +/** + * A cleaner for user session data on data store servers. + * + * @author Bernd Rinn + */ +public class DataStoreUserSessionCleaner +{ + + private final Map<String, List<IDataStoreService>> sessions = + new HashMap<String, List<IDataStoreService>>(); + + public void add(Session userSession, IDataStoreService dataStore) + { + final String userSessionToken = userSession.getSessionToken(); + final List<IDataStoreService> dataStores = getOrCreateDataStores(userSessionToken); + dataStores.add(dataStore); + userSession.addCleanupListener(new ISessionCleaner() + { + @Override + public void cleanup() + { + for (IDataStoreService service : dataStores) + { + service.cleanupSession(userSessionToken); + } + sessions.remove(userSessionToken); + } + }); + } + + private List<IDataStoreService> getOrCreateDataStores(String userSessionToken) + { + List<IDataStoreService> dataStores = sessions.get(userSessionToken); + if (dataStores == null) + { + dataStores = new ArrayList<IDataStoreService>(); + sessions.put(userSessionToken, dataStores); + } + return dataStores; + } + +} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java index 1f57f31a80f1a2a544e44d1a86d92ff55c06e254..4a0538576f4ef49d7d1783eac220cce4dc3cbc1d 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java @@ -43,6 +43,7 @@ import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; +import ch.systemsx.cisd.openbis.generic.server.DataStoreUserSessionCleaner; import ch.systemsx.cisd.openbis.generic.server.business.IDataStoreServiceFactory; import ch.systemsx.cisd.openbis.generic.server.business.bo.exception.DataSetDeletionDisallowedTypesException; import ch.systemsx.cisd.openbis.generic.server.business.bo.exception.DataSetDeletionUnknownLocationsException; @@ -197,11 +198,15 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements private List<DataPE> dataSets; - public DataSetTable(final IDAOFactory daoFactory, IDataStoreServiceFactory dssFactory, - final Session session, IRelationshipService relationshipService) + private final DataStoreUserSessionCleaner dssUserSessionCleaner; + + public DataSetTable(IDAOFactory daoFactory, IDataStoreServiceFactory dssFactory, + DataStoreUserSessionCleaner dssUserSessionCleaner, + Session session, IRelationshipService relationshipService) { super(daoFactory, session, relationshipService); this.dssFactory = dssFactory; + this.dssUserSessionCleaner = dssUserSessionCleaner; } // @@ -596,6 +601,7 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements List<DatasetDescription> locations = loadAvailableDatasetDescriptions(datasetCodes); String sessionToken = dataStore.getSessionToken(); String userSessionToken = session.getSessionToken(); + dssUserSessionCleaner.add(session, service); return service.createReportFromDatasets(sessionToken, userSessionToken, datastoreServiceKey, locations, tryGetLoggedUserEmail()); } @@ -1050,6 +1056,7 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements } String sessionToken = dataStore.getSessionToken(); String userSessionToken = session.getSessionToken(); + dssUserSessionCleaner.add(session, service); return service.createReportFromAggregationService(sessionToken, userSessionToken, datastoreServiceKey, parameters, tryGetLoggedUserEmail()); } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java index b57331150e6f8887dc9750a72dca9fa7d3de6a72..a6be88f2faa7f2ac9a8daf1ee7ddbcc53b354535 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java @@ -39,7 +39,7 @@ public interface IDataStoreService /** * Every time this interface and related DTO's are changed, we should increment this number. */ - public static final int VERSION = 7; // for release 131 + public static final int VERSION = 8; // for release 137 /** * Returns the version of this service. @@ -83,7 +83,12 @@ public interface IDataStoreService public void uploadDataSetsToCIFEX(String sessionToken, List<ExternalData> dataSets, DataSetUploadContext context) throws InvalidAuthenticationException; - /** Runs the reporting task with the specified id for provided datasets */ + /** + * Runs the reporting task with the specified id for provided datasets. + * <p> + * <i> Ensure that you call {@link #cleanupSession(String)} on closing of the user sesssion + * <var>userSessionToken</var> so that DSS gets the chance to cleanup session files. </i> + */ public TableModel createReportFromDatasets(String sessionToken, String userSessionToken, String serviceKey, List<DatasetDescription> datasets, String userEmailOrNull); @@ -138,6 +143,9 @@ public interface IDataStoreService /** * Gets the link from a service that supports the IReportingPluginTask#createLink method. + * <p> + * <i> Ensure that you call {@link #cleanupSession(String)} on closing of the user sesssion + * <var>userSessionToken</var> so that DSS gets the chance to cleanup session files. </i> * * @param sessionToken The sessionToken. * @param userSessionToken The session token of the user that initiated the processing. @@ -152,4 +160,12 @@ public interface IDataStoreService public String putDataSet(String sessionToken, String dropboxName, CustomImportFile customImportFile); + + /** + * Cleans up the user session with given <var>userSessionToken</var>. + * + * @since 8 + */ + public void cleanupSession(String userSessionToken); + } diff --git a/openbis/source/java/genericApplicationContext.xml b/openbis/source/java/genericApplicationContext.xml index 50f4e2d6be4941424b4b209d542283402678f897..7ceb626655308b2c6f1cc4ee6ef3b5609025e91a 100644 --- a/openbis/source/java/genericApplicationContext.xml +++ b/openbis/source/java/genericApplicationContext.xml @@ -49,6 +49,8 @@ <bean id="dss-factory" class="ch.systemsx.cisd.openbis.generic.server.business.DataStoreServiceFactory"/> + <bean id="dss-user-session-cleaner" class="ch.systemsx.cisd.openbis.generic.server.DataStoreUserSessionCleaner" /> + <bean id="authentication-service" class="ch.systemsx.cisd.openbis.generic.server.AuthenticationServiceHolder"> <constructor-arg ref="${authentication-service}" /> @@ -83,6 +85,7 @@ <constructor-arg ref="dss-factory" /> <constructor-arg ref="relationship-service" /> <constructor-arg ref="entity-operation-checker" /> + <constructor-arg ref="dss-user-session-cleaner" /> </bean> <bean id="last-modification-state" diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTableTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTableTest.java index 75d4d8db2ff37a0c0bbe8afc505b40f4189c34e3..9367c1e603453e8b1dc7dd180bc86bdb2ca8ca53 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTableTest.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTableTest.java @@ -39,6 +39,7 @@ import org.testng.annotations.Test; import ch.rinn.restrictions.Friend; import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.openbis.generic.server.DataStoreUserSessionCleaner; import ch.systemsx.cisd.openbis.generic.server.business.IDataStoreServiceFactory; import ch.systemsx.cisd.openbis.generic.server.business.ManagerTestTool; import ch.systemsx.cisd.openbis.generic.server.business.bo.exception.DataSetDeletionUnknownLocationsException; @@ -79,6 +80,8 @@ public final class DataSetTableTest extends AbstractBOTest { private IDataStoreServiceFactory dssFactory; + private DataStoreUserSessionCleaner dssUserSessionCleaner; + private DataStorePE dss1; private DataStorePE dss2; @@ -93,8 +96,8 @@ public final class DataSetTableTest extends AbstractBOTest private final DataSetTable createDataSetTable() { - return new DataSetTable(daoFactory, dssFactory, ManagerTestTool.EXAMPLE_SESSION, - relationshipService); + return new DataSetTable(daoFactory, dssFactory, dssUserSessionCleaner, + ManagerTestTool.EXAMPLE_SESSION, relationshipService); } @BeforeMethod @@ -103,6 +106,7 @@ public final class DataSetTableTest extends AbstractBOTest { super.beforeMethod(); dssFactory = context.mock(IDataStoreServiceFactory.class); + dssUserSessionCleaner = new DataStoreUserSessionCleaner(); dss1 = createDataStore("dss1", false); dss2 = createDataStore("dss2", true); dss3 = createDataStore("dss3", true); @@ -546,8 +550,8 @@ public final class DataSetTableTest extends AbstractBOTest final ExternalDataPE d3Available = createDataSet("d3a", dss3, AVAILABLE); final ExternalDataPE d3NonAvailable = createDataSet("d3n", dss3, ARCHIVED); final ExternalDataPE[] allDataSets = - { d2Available1, d2Available2, d2NonAvailable1, d2NonAvailable2, d3Available, - d3NonAvailable, d2NonAvailable3 }; + { d2Available1, d2Available2, d2NonAvailable1, d2NonAvailable2, d3Available, + d3NonAvailable, d2NonAvailable3 }; context.checking(new Expectations() { { @@ -581,8 +585,8 @@ public final class DataSetTableTest extends AbstractBOTest final ExternalDataPE d3Archived = createDataSet("d3a", dss3, ARCHIVED); final ExternalDataPE d3NonArchived = createDataSet("d3n", dss3, AVAILABLE); final ExternalDataPE[] allDataSets = - { d2Archived1, d2Archived2, d2NonArchived1, d2NonArchived2, d3Archived, - d3NonArchived, d2NonAvailable3 }; + { d2Archived1, d2Archived2, d2NonArchived1, d2NonArchived2, d3Archived, + d3NonArchived, d2NonAvailable3 }; context.checking(new Expectations() { {