From 477fcb0a32b353365b16b88b4e147da5bcfd0287 Mon Sep 17 00:00:00 2001 From: felmer <felmer> Date: Thu, 7 Mar 2013 09:48:26 +0000 Subject: [PATCH] SP-542, BIS-350: Invoke DSS session cleanup from AS at logout/session expiration. AbstractDatasetDownloadServlet asks AS for valid session token. Valid session tokens are cached (OpenbisSessionTokenCache) until session cleanup. SVN: 28549 --- .../AbstractDatasetDownloadServlet.java | 6 +- .../generic/server/ApplicationContext.java | 11 +++- .../dss/generic/server/DataStoreServer.java | 6 +- .../dss/generic/server/DataStoreService.java | 10 ++- .../server/OpenbisSessionTokenCache.java | 61 +++++++++++++++++++ .../source/java/dssApplicationContext.xml | 7 ++- .../generic/server/DataStoreServiceTest.java | 14 +++-- .../server/DatasetDownloadServletTest.java | 26 +++++++- .../generic/server/AbstractServer.java | 8 +++ .../generic/server/SessionFactory.java | 32 +++++----- 10 files changed, 153 insertions(+), 28 deletions(-) create mode 100644 datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/OpenbisSessionTokenCache.java diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDatasetDownloadServlet.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDatasetDownloadServlet.java index bf13f10c9ea..c27c5e289d4 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDatasetDownloadServlet.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/AbstractDatasetDownloadServlet.java @@ -90,7 +90,6 @@ abstract public class AbstractDatasetDownloadServlet extends HttpServlet this.applicationContext = applicationContext; } - @SuppressWarnings("unchecked") @Override public final void init(final ServletConfig servletConfig) throws ServletException { @@ -170,6 +169,10 @@ abstract public class AbstractDatasetDownloadServlet extends HttpServlet appendServletSessionTimeout(sb); operationLog.info(sb.toString()); } + if (applicationContext.getSessionTokenCache().isValidSessionToken(sessionIdOrNull) == false) + { + return null; + } return session; } @@ -180,7 +183,6 @@ abstract public class AbstractDatasetDownloadServlet extends HttpServlet sb.append(" sec"); } - @SuppressWarnings("unchecked") private void appendRequestParameters(final HttpServletRequest request, StringBuilder sb) { Enumeration<String> e = request.getParameterNames(); diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ApplicationContext.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ApplicationContext.java index c874a4e70b7..e22ced917e1 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ApplicationContext.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ApplicationContext.java @@ -37,11 +37,15 @@ class ApplicationContext private final IHierarchicalContentProvider hierarchicalContentProvider; - ApplicationContext(IEncapsulatedOpenBISService service, IShareIdManager shareIdManager, + private final OpenbisSessionTokenCache sessionTokenCache; + + ApplicationContext(IEncapsulatedOpenBISService service, + OpenbisSessionTokenCache sessionTokenCache, IShareIdManager shareIdManager, IHierarchicalContentProvider hierarchicalContentProvider, ConfigParameters configParameters) { this.dataSetService = service; + this.sessionTokenCache = sessionTokenCache; this.shareIdManager = shareIdManager; this.configParameters = configParameters; this.hierarchicalContentProvider = hierarchicalContentProvider; @@ -52,6 +56,11 @@ class ApplicationContext return dataSetService; } + public OpenbisSessionTokenCache getSessionTokenCache() + { + return sessionTokenCache; + } + public IShareIdManager getShareIdManager() { return shareIdManager; diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServer.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServer.java index 0aab796b0a0..46e3bbe87da 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServer.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServer.java @@ -145,8 +145,12 @@ public class DataStoreServer assert server == null : "Server already started"; ConfigParameters configParams = getConfigParameters(); final IEncapsulatedOpenBISService openBISService = ServiceProvider.getOpenBISService(); + OpenbisSessionTokenCache sessionTokenCache = + (OpenbisSessionTokenCache) ServiceProvider.getApplicationContext().getBean( + "as-session-token-cache"); final ApplicationContext applicationContext = - new ApplicationContext(openBISService, ServiceProvider.getShareIdManager(), + new ApplicationContext(openBISService, sessionTokenCache, + ServiceProvider.getShareIdManager(), ServiceProvider.getHierarchicalContentProvider(), configParams); DssSessionAuthorizationHolder.setAuthorizer(new DatasetSessionAuthorizer(configParams .getAuthCacheExpirationTimeMins(), configParams 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 0cf6d97e5c5..861f277a405 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 @@ -82,6 +82,8 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic { private final SessionTokenManager sessionTokenManager; + private final OpenbisSessionTokenCache sessionTokenCache; + private final IDataSetCommandExecutorFactory commandExecutorFactory; private final MailClientParameters mailClientParameters; @@ -106,10 +108,10 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic private ConfigProvider config; - public DataStoreService(SessionTokenManager sessionTokenManager, + public DataStoreService(SessionTokenManager sessionTokenManager, OpenbisSessionTokenCache sessionTokenCache, MailClientParameters mailClientParameters, IPluginTaskInfoProvider pluginTaskParameters) { - this(sessionTokenManager, new IDataSetCommandExecutorFactory() + this(sessionTokenManager, sessionTokenCache, new IDataSetCommandExecutorFactory() { @Override public IDataSetCommandExecutor create(File store, File queueDir) @@ -120,10 +122,11 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic } DataStoreService(SessionTokenManager sessionTokenManager, - IDataSetCommandExecutorFactory commandExecutorFactory, + OpenbisSessionTokenCache sessionTokenCache, IDataSetCommandExecutorFactory commandExecutorFactory, MailClientParameters mailClientParameters, IPluginTaskInfoProvider pluginTaskParameters) { this.sessionTokenManager = sessionTokenManager; + this.sessionTokenCache = sessionTokenCache; this.commandExecutorFactory = commandExecutorFactory; this.mailClientParameters = mailClientParameters; this.pluginTaskInfoProvider = pluginTaskParameters; @@ -491,6 +494,7 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic @Override public void cleanupSession(String userSessionToken) { + sessionTokenCache.removeSessionToken(userSessionToken); final File sessionWorkspace = new File(pluginTaskInfoProvider.getSessionWorkspaceRootDir(), userSessionToken); if (sessionWorkspace.exists()) diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/OpenbisSessionTokenCache.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/OpenbisSessionTokenCache.java new file mode 100644 index 00000000000..985b490779d --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/OpenbisSessionTokenCache.java @@ -0,0 +1,61 @@ +/* + * Copyright 2013 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.util.HashSet; +import java.util.Set; + +import ch.systemsx.cisd.common.exceptions.InvalidSessionException; +import ch.systemsx.cisd.openbis.generic.shared.IServiceForDataStoreServer; + +/** + * Cache of user session tokens for openBIS AS. + * + * @author Franz-Josef Elmer + */ +public class OpenbisSessionTokenCache +{ + private final IServiceForDataStoreServer service; + private final Set<String> sessionTokens = new HashSet<String>(); + + public OpenbisSessionTokenCache(IServiceForDataStoreServer service) + { + this.service = service; + } + + public boolean isValidSessionToken(String sessionToken) + { + if (sessionTokens.contains(sessionToken)) + { + return true; + } + try + { + service.checkSession(sessionToken); + sessionTokens.add(sessionToken); + return true; + } catch (InvalidSessionException ex) + { + return false; + } + } + + public void removeSessionToken(String sessionToken) + { + sessionTokens.remove(sessionToken); + } +} diff --git a/datastore_server/source/java/dssApplicationContext.xml b/datastore_server/source/java/dssApplicationContext.xml index 83af08f032f..c226cee5246 100644 --- a/datastore_server/source/java/dssApplicationContext.xml +++ b/datastore_server/source/java/dssApplicationContext.xml @@ -56,6 +56,10 @@ <property name="dataStoreCode" value="${data-store-server-code}"/> </bean> + <bean id="as-session-token-cache" class="ch.systemsx.cisd.openbis.dss.generic.server.OpenbisSessionTokenCache"> + <constructor-arg ref="etl-lims-service"/> + </bean> + <bean id="reauthenticateInterceptor" class="ch.systemsx.cisd.openbis.dss.generic.server.openbisauth.OpenBISAuthenticationInterceptor"> <constructor-arg ref="session-token-manager"/> <constructor-arg ref="etl-lims-service"/> @@ -73,7 +77,7 @@ <bean id="reauthenticateAdvisor" class="ch.systemsx.cisd.openbis.dss.generic.server.openbisauth.OpenBISAuthenticationAdvisor"> <constructor-arg ref="reauthenticateInterceptor"/> </bean> - + <bean id="openBIS-service" class="ch.systemsx.cisd.openbis.dss.generic.server.EncapsulatedOpenBISService"> <constructor-arg ref="etl-lims-service"/> <constructor-arg ref="sessionHolder"/> @@ -96,6 +100,7 @@ <bean id="data-store-service" class="ch.systemsx.cisd.openbis.dss.generic.server.DataStoreService"> <constructor-arg ref="session-token-manager" /> + <constructor-arg ref="as-session-token-cache" /> <constructor-arg> <bean class="ch.systemsx.cisd.common.mail.MailClientParameters"> <property name="from" value="${mail.from}"/> diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceTest.java index c34b497dc57..e1e23a2158a 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceTest.java @@ -38,6 +38,7 @@ import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IPluginTaskInfo import ch.systemsx.cisd.openbis.dss.generic.shared.IShareIdManager; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.PluginUtilTest; import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService; +import ch.systemsx.cisd.openbis.generic.shared.IServiceForDataStoreServer; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData; import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext; import ch.systemsx.cisd.openbis.generic.shared.dto.builders.DatasetDescriptionBuilder; @@ -61,13 +62,13 @@ public class DataStoreServiceTest extends AssertJUnit private final String expectedCIFEXURL; - MockDataStoreService(SessionTokenManager sessionTokenManager, + MockDataStoreService(SessionTokenManager sessionTokenManager, OpenbisSessionTokenCache sessionTokenCache, IDataSetCommandExecutorFactory commandExecutorFactory, MailClientParameters mailClientParameters, ICIFEXRPCServiceFactory cifexServiceFactory, String expectedCIFEXURL, IPluginTaskInfoProvider pluginTaskParameters) { - super(sessionTokenManager, commandExecutorFactory, mailClientParameters, + super(sessionTokenManager, sessionTokenCache, commandExecutorFactory, mailClientParameters, pluginTaskParameters); this.cifexServiceFactory = cifexServiceFactory; this.expectedCIFEXURL = expectedCIFEXURL; @@ -101,12 +102,15 @@ public class DataStoreServiceTest extends AssertJUnit private IShareIdManager shareIdManager; + private IServiceForDataStoreServer openbisService; + @BeforeMethod public void setup() { context = new Mockery(); sessionTokenManager = new SessionTokenManager(); sessionToken = sessionTokenManager.drawSessionToken(); + openbisService = context.mock(IServiceForDataStoreServer.class); commandExecutorFactory = context.mock(IDataSetCommandExecutorFactory.class); commandExecutor = context.mock(IDataSetCommandExecutor.class); shareIdManager = context.mock(IShareIdManager.class); @@ -289,9 +293,11 @@ public class DataStoreServiceTest extends AssertJUnit will(returnValue(commandExecutor)); } }); + OpenbisSessionTokenCache sessionTokenCache = new OpenbisSessionTokenCache(openbisService); MockDataStoreService service = - new MockDataStoreService(sessionTokenManager, commandExecutorFactory, - mailClientParameters, cifexServiceFactory, CIFEX_URL, pluginTaskParameters); + new MockDataStoreService(sessionTokenManager, sessionTokenCache, + commandExecutorFactory, mailClientParameters, cifexServiceFactory, + CIFEX_URL, pluginTaskParameters); service.setShareIdManager(shareIdManager); service.afterPropertiesSet(); return service; diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetDownloadServletTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetDownloadServletTest.java index e841dd9e388..a99cfe04620 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetDownloadServletTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetDownloadServletTest.java @@ -62,6 +62,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider; import ch.systemsx.cisd.openbis.dss.generic.shared.IShareIdManager; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.DatasetLocationUtil; +import ch.systemsx.cisd.openbis.generic.shared.IServiceForDataStoreServer; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PhysicalDataSet; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStore; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment; @@ -155,6 +156,8 @@ public class DatasetDownloadServletTest private IHierarchicalContentProvider hierarchicalContentProvider; + private IServiceForDataStoreServer service; + @BeforeMethod public void setUp() { @@ -165,6 +168,7 @@ public class DatasetDownloadServletTest response = context.mock(HttpServletResponse.class); shareIdManager = context.mock(IShareIdManager.class); openbisService = context.mock(IEncapsulatedOpenBISService.class); + service = context.mock(IServiceForDataStoreServer.class); // test with DefaultFileBasedHierarchicalContentFactory to actually access files final IHierarchicalContentFactory fileBasedContentFactory = new DefaultFileBasedHierarchicalContentFactory(); @@ -207,6 +211,7 @@ public class DatasetDownloadServletTest final StringWriter writer = new StringWriter(); final AbstractExternalData externalData = createDataSet(); prepareParseRequestURL(); + prepareCheckSession(); prepareForObtainingDataSetFromServer(externalData); prepareForGettingDataSetFromSession(externalData, ""); prepareLocking(); @@ -274,6 +279,16 @@ public class DatasetDownloadServletTest } }); } + + private void prepareCheckSession() + { + context.checking(new Expectations() + { + { + one(service).checkSession(EXAMPLE_SESSION_ID); + } + }); + } @Test() public void testInitialDoGetButDataSetNotFoundInStore() throws Exception @@ -281,6 +296,7 @@ public class DatasetDownloadServletTest final StringWriter writer = new StringWriter(); final AbstractExternalData externalData = createDataSet(); prepareParseRequestURL(); + prepareCheckSession(); prepareForObtainingDataSetFromServer(externalData); prepareLocking(); context.checking(new Expectations() @@ -318,6 +334,7 @@ public class DatasetDownloadServletTest { final StringWriter writer = new StringWriter(); prepareParseRequestURL(); + prepareCheckSession(); prepareForObtainingDataSetFromServer(null); context.checking(new Expectations() { @@ -356,6 +373,7 @@ public class DatasetDownloadServletTest { final StringWriter writer = new StringWriter(); final AbstractExternalData externalData = createDataSet(); + prepareCheckSession(); prepareForObtainingDataSetFromServer(externalData); prepareForGettingDataSetFromSession(externalData, ESCAPED_EXAMPLE_DATA_SET_SUB_FOLDER_NAME); prepareLocking(); @@ -392,6 +410,7 @@ public class DatasetDownloadServletTest final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); prepareParseRequestURL(); + prepareCheckSession(); prepareCheckDatasetAccess(); prepareForObtainingDataSetFromServer(externalData); prepareLocking(); @@ -436,6 +455,7 @@ public class DatasetDownloadServletTest BufferedImage image = new BufferedImage(100, 200, BufferedImage.TYPE_INT_RGB); ImageIO.write(image, "png", EXAMPLE_FILE); prepareParseRequestURLForThumbnail(100, 50); + prepareCheckSession(); final AbstractExternalData externalData = createDataSet(); prepareCheckDatasetAccess(); prepareForObtainingDataSetFromServer(externalData); @@ -487,6 +507,7 @@ public class DatasetDownloadServletTest final StringWriter writer = new StringWriter(); final AbstractExternalData externalData = createDataSet(); prepareParseRequestURL(); + prepareCheckSession(); prepareForObtainingDataSetFromServer(externalData); prepareLocking(); context.checking(new Expectations() @@ -822,8 +843,9 @@ public class DatasetDownloadServletTest properties.setProperty(ConfigParameters.KEYSTORE_KEY_PASSWORD_KEY, "y"); properties.setProperty(ConfigParameters.DOWNLOAD_URL, "http://localhost:8080"); ConfigParameters configParameters = new ConfigParameters(properties); - return new DatasetDownloadServlet(new ApplicationContext(openbisService, shareIdManager, - hierarchicalContentProvider, configParameters)); + OpenbisSessionTokenCache sessionTokenCache = new OpenbisSessionTokenCache(service); + return new DatasetDownloadServlet(new ApplicationContext(openbisService, sessionTokenCache, + shareIdManager, hierarchicalContentProvider, configParameters)); } private String getNormalizedLogContent() diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java index 1d44689d3ac..2df19bc1267 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java @@ -50,6 +50,7 @@ import ch.systemsx.cisd.openbis.common.spring.AbstractServiceWithLogger; import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.ReturnValueFilter; import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed; import ch.systemsx.cisd.openbis.generic.server.authorization.validator.ExpressionValidator; +import ch.systemsx.cisd.openbis.generic.server.business.IDataStoreServiceFactory; import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager; import ch.systemsx.cisd.openbis.generic.server.business.bo.DataSetTable; import ch.systemsx.cisd.openbis.generic.server.business.bo.IDataSetTable; @@ -148,6 +149,9 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp @Resource(name = ComponentNames.DAO_FACTORY) private IDAOFactory daoFactory; + @Resource(name = ComponentNames.DSS_FACTORY) + private IDataStoreServiceFactory dssFactory; + @Resource(name = ComponentNames.REMOTE_HOST_VALIDATOR) private IRemoteHostValidator remoteHostValidator; @@ -447,6 +451,8 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp try { sessionManager.closeSession(sessionToken); + SessionFactory.cleanUpSessionOnDataStoreServers(sessionToken, + daoFactory.getDataStoreDAO(), dssFactory); } catch (InvalidSessionException e) { // ignore the situation when session is not available @@ -460,6 +466,8 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp try { sessionManager.expireSession(sessionToken); + SessionFactory.cleanUpSessionOnDataStoreServers(sessionToken, + daoFactory.getDataStoreDAO(), dssFactory); } catch (InvalidSessionException e) { // ignore the situation when session is not available diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SessionFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SessionFactory.java index f09df44ecd8..d35190f0fbe 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SessionFactory.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SessionFactory.java @@ -74,23 +74,27 @@ public final class SessionFactory implements ISessionFactory<Session> @Override public void cleanup() { - for (DataStorePE datastore : datastoreDAO.listDataStores()) - { - final String remoteUrl = datastore.getRemoteUrl(); - if (StringUtils.isBlank(remoteUrl) == false) - { - dssFactory.createMonitored(remoteUrl).cleanupSession( - sessionToken); - } else - { - operationLog.warn("datastore remoteUrl of datastore " - + datastore.getCode() - + " is empty - skipping DSS session cleanup."); - } - } + cleanUpSessionOnDataStoreServers(sessionToken, datastoreDAO, dssFactory); } }); } return session; } + + public static void cleanUpSessionOnDataStoreServers(String sessionToken, + IDataStoreDAO datastoreDAO, IDataStoreServiceFactory dssFactory) + { + for (DataStorePE datastore : datastoreDAO.listDataStores()) + { + final String remoteUrl = datastore.getRemoteUrl(); + if (StringUtils.isBlank(remoteUrl) == false) + { + dssFactory.createMonitored(remoteUrl).cleanupSession(sessionToken); + } else + { + operationLog.warn("datastore remoteUrl of datastore " + datastore.getCode() + + " is empty - skipping DSS session cleanup."); + } + } + } } -- GitLab