From 4b9996d204b04ea54deb9a8e0fa91bc845891d83 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Thu, 16 Jul 2020 16:46:10 +0300 Subject: [PATCH] REPO-5094: Allow switching between existing content store subsystems (#1101) - Update CryptodocSwitchableApplicationContextFactory to accept switching between existing content store subsystems, not just based on plain bean names - Add EncryptedContentStoreChildApplicationContextFactory as extension of ChildApplicationContextFactory with support to specify if the content store in the subsystem is encrypted or not --- ...ocSwitchableApplicationContextFactory.java | 203 +++++++++--------- ...ntStoreChildApplicationContextFactory.java | 45 ++++ .../SwitchableApplicationContextFactory.java | 52 ++--- .../alfresco/content-services-context.xml | 8 +- ...itchableApplicationContextFactoryTest.java | 140 ++++++++++-- 5 files changed, 296 insertions(+), 152 deletions(-) create mode 100644 src/main/java/org/alfresco/repo/management/subsystems/EncryptedContentStoreChildApplicationContextFactory.java diff --git a/src/main/java/org/alfresco/repo/management/subsystems/CryptodocSwitchableApplicationContextFactory.java b/src/main/java/org/alfresco/repo/management/subsystems/CryptodocSwitchableApplicationContextFactory.java index fe908e306a..99c4be99ec 100644 --- a/src/main/java/org/alfresco/repo/management/subsystems/CryptodocSwitchableApplicationContextFactory.java +++ b/src/main/java/org/alfresco/repo/management/subsystems/CryptodocSwitchableApplicationContextFactory.java @@ -1,121 +1,58 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - * #L% - */ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ package org.alfresco.repo.management.subsystems; -import java.io.IOException; - import org.alfresco.repo.descriptor.DescriptorServiceAvailableEvent; import org.alfresco.service.descriptor.DescriptorService; import org.alfresco.service.license.LicenseDescriptor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeansException; import org.springframework.context.ApplicationEvent; +import java.io.IOException; + /** - * {@link SwitchableApplicationContextFactory} that only allows the subsystem to be switched - * if the current subsystem is the unencrypted content store. When an attempt is made to switch away - * from any other store (e.g. the encrypted store) then nothing happens. This is achieved by returning - * false for {@link #isUpdateable(String)} calls when the current sourceBeanName is - * that of the unencrypted content store's subsystem. - * + * {@link SwitchableApplicationContextFactory} that only allows the subsystem to be switched from unencrypted to encrypted, + * or if the two subsystems have the same ecrypted state. + * Switching back to unencrypted from encrypted content store is not allowed. + * * @author Matt Ward */ public class CryptodocSwitchableApplicationContextFactory extends SwitchableApplicationContextFactory - { - private static final String SOURCE_BEAN_PROPERTY = "sourceBeanName"; - private String unencryptedContentStoreBeanName; - private String encryptedContentStoreBeanName; private DescriptorService descriptorService; private static final Log logger = LogFactory.getLog(CryptodocSwitchableApplicationContextFactory.class); - @Override - public boolean isUpdateable(String name) - { - if (name == null) - { - throw new IllegalStateException("Property name cannot be null"); - } - - boolean updateable = true; - if (name.equals(SOURCE_BEAN_PROPERTY)) - { - if(getCurrentSourceBeanName().equals(unencryptedContentStoreBeanName)) - { - if(descriptorService != null) - { - LicenseDescriptor license = descriptorService.getLicenseDescriptor(); - if(license != null && license.isCryptodocEnabled()) - { - return true; - } - return false; - } - } - - // can the source bean name be changed? - if(!getCurrentSourceBeanName().equals(unencryptedContentStoreBeanName)) - { - // the subsystem has been switched once. - return false; - } - } - return updateable; - } - @Override protected PropertyBackedBeanState createInitialState() throws IOException { return new CryptoSwitchableState(sourceBeanName); } - - - /** - * The bean name of the unencrypted ContentStore subsystem. - * - * @param unencryptedContentStoreBeanName String - */ - public void setUnencryptedContentStoreBeanName(String unencryptedContentStoreBeanName) - { - this.unencryptedContentStoreBeanName = unencryptedContentStoreBeanName; - } - public String getEncryptedContentStoreBeanName() - { - return encryptedContentStoreBeanName; - } - - public void setEncryptedContentStoreBeanName( - String encryptedContentStoreBeanName) - { - this.encryptedContentStoreBeanName = encryptedContentStoreBeanName; - } - - - protected class CryptoSwitchableState extends SwitchableState { protected CryptoSwitchableState(String sourceBeanName) @@ -126,25 +63,77 @@ public class CryptodocSwitchableApplicationContextFactory extends SwitchableAppl @Override public void setProperty(String name, String value) { - if (!isUpdateable(name)) + if (name.equals(SOURCE_BEAN_PROPERTY)) { - if(value.equalsIgnoreCase(unencryptedContentStoreBeanName)) - { - throw new IllegalStateException("Switching to an unencrypted content store is not possible."); - } - if(value.equalsIgnoreCase(encryptedContentStoreBeanName)) - { - throw new IllegalStateException("Switching to an encrypted content store is not licensed."); - } - throw new IllegalStateException("Switching to an unknown content store is not possible." + value); + ChildApplicationContextFactory newSourceBean; + try + { + newSourceBean = getParent().getBean(value, ChildApplicationContextFactory.class); + } + catch (BeansException e) + { + throw new IllegalStateException("Switching to the unknown content store \"" + value + "\" is not possible."); + } + + if (canSwitchSubsystemTo(newSourceBean, value)) + { + boolean isNewEncrypted = isEncryptedContentStoreSubsystem(newSourceBean, value); + if (isNewEncrypted && !isEncryptionSupported()) + { + throw new IllegalStateException("Switching to the encrypted content store \"" + value + "\" is not licensed."); + } + } + else + { + throw new IllegalStateException("Switching to the unencrypted content store \"" + value + "\" is not possible."); + } } super.setProperty(name, value); } } - + + private boolean canSwitchSubsystemTo(Object newSourceBean, String beanName) + { + Object currentSourceBean = getParent().getBean(getCurrentSourceBeanName()); + boolean isCurrentEncrypted = isEncryptedContentStoreSubsystem(currentSourceBean, getCurrentSourceBeanName()); + // Can switch from an unencrypted content store to any kind of content store + if (!isCurrentEncrypted) + { + return true; + } + boolean isNewEncrypted = isEncryptedContentStoreSubsystem(newSourceBean, beanName); + // Can switch from an encrypted content store only to another encrypted one + return isCurrentEncrypted && isNewEncrypted; + } + + private boolean isEncryptedContentStoreSubsystem(Object sourceBean, String beanName) + { + boolean isEncrypted = false; + if (sourceBean instanceof EncryptedContentStoreChildApplicationContextFactory) + { + isEncrypted = ((EncryptedContentStoreChildApplicationContextFactory) sourceBean).isEncryptedContent(); + } + //If not explicitly set as encrypted, check if the source bean is the cryptodoc subsystem bean + if (!isEncrypted) + { + isEncrypted = beanName.equals("encryptedContentStore"); + } + return isEncrypted; + } + + private boolean isEncryptionSupported() + { + boolean isSupported = true; + if (descriptorService != null) + { + LicenseDescriptor license = descriptorService.getLicenseDescriptor(); + isSupported = license != null && license.isCryptodocEnabled(); + } + return isSupported; + } + public void onApplicationEvent(ApplicationEvent event) { - if(logger.isDebugEnabled()) { logger.debug("event : " + event); diff --git a/src/main/java/org/alfresco/repo/management/subsystems/EncryptedContentStoreChildApplicationContextFactory.java b/src/main/java/org/alfresco/repo/management/subsystems/EncryptedContentStoreChildApplicationContextFactory.java new file mode 100644 index 0000000000..d7280658c4 --- /dev/null +++ b/src/main/java/org/alfresco/repo/management/subsystems/EncryptedContentStoreChildApplicationContextFactory.java @@ -0,0 +1,45 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.repo.management.subsystems; + +/** + * ChildApplicationContextFactory extension used to identify the type of the content store subsystem, encrypted or unecrypted. + * See {@link CryptodocSwitchableApplicationContextFactory} for how is used. + */ +public class EncryptedContentStoreChildApplicationContextFactory extends ChildApplicationContextFactory +{ + private boolean encryptedContent; + + public boolean isEncryptedContent() + { + return encryptedContent; + } + + public void setEncryptedContent(boolean encryptedContent) + { + this.encryptedContent = encryptedContent; + } +} diff --git a/src/main/java/org/alfresco/repo/management/subsystems/SwitchableApplicationContextFactory.java b/src/main/java/org/alfresco/repo/management/subsystems/SwitchableApplicationContextFactory.java index f927def54c..d9e22289b8 100644 --- a/src/main/java/org/alfresco/repo/management/subsystems/SwitchableApplicationContextFactory.java +++ b/src/main/java/org/alfresco/repo/management/subsystems/SwitchableApplicationContextFactory.java @@ -1,28 +1,28 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - * #L% - */ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ package org.alfresco.repo.management.subsystems; import java.io.IOException; @@ -41,7 +41,7 @@ public class SwitchableApplicationContextFactory extends AbstractPropertyBackedB { /** The name of the property holding the bean name of the source {@link ApplicationContextFactory}. */ - private static final String SOURCE_BEAN_PROPERTY = "sourceBeanName"; + protected static final String SOURCE_BEAN_PROPERTY = "sourceBeanName"; /** The default bean name of the source {@link ApplicationContextFactory}. */ protected String sourceBeanName; diff --git a/src/main/resources/alfresco/content-services-context.xml b/src/main/resources/alfresco/content-services-context.xml index 87d3080df3..8f39d8aeea 100644 --- a/src/main/resources/alfresco/content-services-context.xml +++ b/src/main/resources/alfresco/content-services-context.xml @@ -22,8 +22,6 @@ manager - - @@ -229,9 +227,9 @@ - - - + + + diff --git a/src/test/java/org/alfresco/repo/management/subsystems/CryptodocSwitchableApplicationContextFactoryTest.java b/src/test/java/org/alfresco/repo/management/subsystems/CryptodocSwitchableApplicationContextFactoryTest.java index 18c3261b76..cc1a9cb51c 100644 --- a/src/test/java/org/alfresco/repo/management/subsystems/CryptodocSwitchableApplicationContextFactoryTest.java +++ b/src/test/java/org/alfresco/repo/management/subsystems/CryptodocSwitchableApplicationContextFactoryTest.java @@ -30,6 +30,9 @@ import static org.mockito.Mockito.*; import java.util.Properties; +import org.alfresco.repo.descriptor.DescriptorServiceAvailableEvent; +import org.alfresco.service.descriptor.DescriptorService; +import org.alfresco.service.license.LicenseDescriptor; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,60 +48,133 @@ import org.springframework.context.ApplicationContext; @RunWith(MockitoJUnitRunner.class) public class CryptodocSwitchableApplicationContextFactoryTest { - private static final String UNENCRYPTED_STORE_SUBSYSTEM = "unencrypted"; - private static final String ENCRYPTED_STORE_SUBSYSTEM = "encrypted"; + private static final String UNENCRYPTED_STORE_SUBSYSTEM = "unencryptedContentStore"; + private static final String NEW_UNENCRYPTED_STORE_SUBSYSTEM = "newUnencryptedContentStore"; + private static final String ENCRYPTED_STORE_SUBSYSTEM = "encryptedContentStore"; + private static final String NEW_STORE_SUBSYSTEM = "newContentStore"; + private static final String UNKNOWN_STORE_SUBSYSTEM = "unknownBean"; + private static final String SOURCE_BEAN_NAME_PROPERTY = "sourceBeanName"; // The class under test private CryptodocSwitchableApplicationContextFactory switchableContext; + private @Mock ChildApplicationContextFactory unencrytedContentStore; + private @Mock ChildApplicationContextFactory newUnencrytedContentStore; + private @Mock ChildApplicationContextFactory cryptodocContentStore; + private @Mock EncryptedContentStoreChildApplicationContextFactory newContentStore; + private @Mock PropertyBackedBeanRegistry propertyBackedBeanRegistry; private @Mock ApplicationContext parentContext; + private @Mock DescriptorService descriptorService; + private @Mock LicenseDescriptor licenseDescriptor; @Before public void setUp() throws Exception { switchableContext = new CryptodocSwitchableApplicationContextFactory(); + + when(parentContext.getBean(UNENCRYPTED_STORE_SUBSYSTEM)).thenReturn(unencrytedContentStore); + when(parentContext.getBean(UNENCRYPTED_STORE_SUBSYSTEM, ChildApplicationContextFactory.class)).thenReturn(unencrytedContentStore); + + when(parentContext.containsBean(NEW_UNENCRYPTED_STORE_SUBSYSTEM)).thenReturn(true); + when(parentContext.getBean(NEW_UNENCRYPTED_STORE_SUBSYSTEM, ChildApplicationContextFactory.class)).thenReturn(newUnencrytedContentStore); when(parentContext.containsBean(ENCRYPTED_STORE_SUBSYSTEM)).thenReturn(true); - when(parentContext.containsBean(UNENCRYPTED_STORE_SUBSYSTEM)).thenReturn(true); + when(parentContext.getBean(ENCRYPTED_STORE_SUBSYSTEM)).thenReturn(cryptodocContentStore); + when(parentContext.getBean(ENCRYPTED_STORE_SUBSYSTEM, ChildApplicationContextFactory.class)).thenReturn(cryptodocContentStore); + + when(parentContext.containsBean(NEW_STORE_SUBSYSTEM)).thenReturn(true); + when(parentContext.getBean(NEW_STORE_SUBSYSTEM)).thenReturn(newContentStore); + when(parentContext.getBean(NEW_STORE_SUBSYSTEM, ChildApplicationContextFactory.class)).thenReturn(newContentStore); + + when(parentContext.containsBean(UNKNOWN_STORE_SUBSYSTEM)).thenReturn(false); } private void initSwitchableContext(String sourceBeanName) { switchableContext.setSourceBeanName(sourceBeanName); switchableContext.setPropertyDefaults(new Properties()); - switchableContext.setUnencryptedContentStoreBeanName(UNENCRYPTED_STORE_SUBSYSTEM); switchableContext.setRegistry(propertyBackedBeanRegistry); switchableContext.setApplicationContext(parentContext); switchableContext.init(); } - + @Test - public void sourceBeanIsUpdateableWhenCurrentStoreIsUnencrypted() + public void canSwitchFromUnencryptedToUnencrypted() { initSwitchableContext(UNENCRYPTED_STORE_SUBSYSTEM); - boolean updateable = switchableContext.isUpdateable(SOURCE_BEAN_NAME_PROPERTY); - assertTrue("It should be possible to switch subsystems when the current store is unencrypted.", updateable); + + switchableContext.setProperty(SOURCE_BEAN_NAME_PROPERTY, NEW_UNENCRYPTED_STORE_SUBSYSTEM); + assertEquals(NEW_UNENCRYPTED_STORE_SUBSYSTEM, switchableContext.getProperty(SOURCE_BEAN_NAME_PROPERTY)); } @Test - public void canSetSourceBeanWhenCurrentStoreIsUnencrypted() + public void canSwitchFromUnencryptedToEncrypted_NoLicenseInfo() { initSwitchableContext(UNENCRYPTED_STORE_SUBSYSTEM); + switchableContext.setProperty(SOURCE_BEAN_NAME_PROPERTY, ENCRYPTED_STORE_SUBSYSTEM); assertEquals(ENCRYPTED_STORE_SUBSYSTEM, switchableContext.getProperty(SOURCE_BEAN_NAME_PROPERTY)); } @Test - public void sourceBeanIsNotUpdatableWhenCurrentStoreIsEncrypted() + public void canSwitchFromUnencryptedToEncrypted_Supported() + { + initSwitchableContext(UNENCRYPTED_STORE_SUBSYSTEM); + + DescriptorServiceAvailableEvent event = new DescriptorServiceAvailableEvent(descriptorService); + when(descriptorService.getLicenseDescriptor()).thenReturn(licenseDescriptor); + when(licenseDescriptor.isCryptodocEnabled()).thenReturn(true); + switchableContext.onApplicationEvent(event); + + switchableContext.setProperty(SOURCE_BEAN_NAME_PROPERTY, ENCRYPTED_STORE_SUBSYSTEM); + assertEquals(ENCRYPTED_STORE_SUBSYSTEM, switchableContext.getProperty(SOURCE_BEAN_NAME_PROPERTY)); + } + + @Test + public void canSwitchFromEncryptedToEncrypted_NoLicenseInfo() { initSwitchableContext(ENCRYPTED_STORE_SUBSYSTEM); - boolean updateable = switchableContext.isUpdateable(SOURCE_BEAN_NAME_PROPERTY); - assertFalse("It should not be possible to switch subsystems when the current store is encrypted.", updateable); + + when(newContentStore.isEncryptedContent()).thenReturn(true); + switchableContext.setProperty(SOURCE_BEAN_NAME_PROPERTY, NEW_STORE_SUBSYSTEM); + assertEquals(NEW_STORE_SUBSYSTEM, switchableContext.getProperty(SOURCE_BEAN_NAME_PROPERTY)); + } + + @Test + public void canSwitchFromNewEncryptedToEncrypted_NoLicenseInfo() + { + initSwitchableContext(NEW_STORE_SUBSYSTEM); + + when(newContentStore.isEncryptedContent()).thenReturn(true); + switchableContext.setProperty(SOURCE_BEAN_NAME_PROPERTY, ENCRYPTED_STORE_SUBSYSTEM); + assertEquals(ENCRYPTED_STORE_SUBSYSTEM, switchableContext.getProperty(SOURCE_BEAN_NAME_PROPERTY)); + } + + @Test + public void cannotSwitchFromUnencryptedToEncrypted_NotSupported() + { + initSwitchableContext(UNENCRYPTED_STORE_SUBSYSTEM); + + DescriptorServiceAvailableEvent event = new DescriptorServiceAvailableEvent(descriptorService); + when(descriptorService.getLicenseDescriptor()).thenReturn(licenseDescriptor); + when(licenseDescriptor.isCryptodocEnabled()).thenReturn(false); + switchableContext.onApplicationEvent(event); + try + { + switchableContext.setProperty(SOURCE_BEAN_NAME_PROPERTY, ENCRYPTED_STORE_SUBSYSTEM); + fail("It shouldn't be possible to switch to an encrypted content store when the license doesn't support it."); + } + catch (IllegalStateException e) + { + // expected + } + // The content store didn't change + assertEquals(UNENCRYPTED_STORE_SUBSYSTEM, switchableContext.getProperty(SOURCE_BEAN_NAME_PROPERTY)); } @Test - public void cannotSetSourceBeanWhenCurrentStoreIsEncrypted() + public void cannotSwitchFromEncryptedToUnencrypted() { initSwitchableContext(ENCRYPTED_STORE_SUBSYSTEM); try @@ -108,9 +184,45 @@ public class CryptodocSwitchableApplicationContextFactoryTest } catch (IllegalStateException e) { - // Good + // expected } + // The content store didn't change assertEquals(ENCRYPTED_STORE_SUBSYSTEM, switchableContext.getProperty(SOURCE_BEAN_NAME_PROPERTY)); } + @Test + public void cannotSwitchFromEncryptedToNewUnencrypted() + { + initSwitchableContext(ENCRYPTED_STORE_SUBSYSTEM); + + when(newContentStore.isEncryptedContent()).thenReturn(false); + try + { + switchableContext.setProperty(SOURCE_BEAN_NAME_PROPERTY, NEW_STORE_SUBSYSTEM); + fail("It shouldn't be possible to switch to an unencrypted content store from an encrypted one."); + } + catch (IllegalStateException e) + { + // expected + } + // The content store didn't change + assertEquals(ENCRYPTED_STORE_SUBSYSTEM, switchableContext.getProperty(SOURCE_BEAN_NAME_PROPERTY)); + } + + @Test + public void sourceBeanIsNotUpdatableToUnknownBean() + { + initSwitchableContext(UNENCRYPTED_STORE_SUBSYSTEM); + try + { + switchableContext.setProperty(SOURCE_BEAN_NAME_PROPERTY, UNKNOWN_STORE_SUBSYSTEM); + fail("It shouldn't be possible to set the sourceBean to an unknown one."); + } + catch (IllegalStateException e) + { + // expected + } + // The content store didn't change + assertEquals(UNENCRYPTED_STORE_SUBSYSTEM, switchableContext.getProperty(SOURCE_BEAN_NAME_PROPERTY)); + } }