From cf1411262650c6d057c3f0acc165a9679e5aaee8 Mon Sep 17 00:00:00 2001 From: Lucian Tuca Date: Tue, 29 Jun 2021 11:30:03 +0300 Subject: [PATCH] ACS-1711 : [SPIKE] Update the S3 connector to support Storage Classes (#559) - update the storage class representation --- .../alfresco/repo/content/ContentStore.java | 35 +++++++++------ .../repo/content/StorageClassSet.java | 45 +++++++++++++++++++ .../api/impl/ContentStorageClassesImpl.java | 7 ++- .../resource/content/BinaryProperty.java | 16 +++---- .../alfresco/rest/api/tests/NodeApiTest.java | 2 +- .../rest/api/tests/StorageClassesTest.java | 23 +++++----- .../content/AbstractRoutingContentStore.java | 32 ++++++------- .../repo/content/ContentServiceImpl.java | 18 ++++---- .../content/caching/CachingContentStore.java | 15 ++++--- .../replication/AggregatingContentStore.java | 31 ++++++------- .../AbstractTenantRoutingContentStore.java | 15 ++++--- .../cmr/repository/ContentService.java | 18 ++++---- .../repo/content/RoutingContentStoreTest.java | 15 +++---- .../caching/CachingContentStoreTest.java | 20 ++++----- .../filestore/FileContentStoreTest.java | 6 +-- .../AggregatingContentStoreTest.java | 18 ++++---- ...AbstractTenantRoutingContentStoreTest.java | 4 +- .../repo/version/ContentServiceImplTest.java | 2 +- ...ServiceImplWithMockedContentStoreTest.java | 8 ++-- 19 files changed, 193 insertions(+), 137 deletions(-) create mode 100644 data-model/src/main/java/org/alfresco/repo/content/StorageClassSet.java diff --git a/data-model/src/main/java/org/alfresco/repo/content/ContentStore.java b/data-model/src/main/java/org/alfresco/repo/content/ContentStore.java index 1c60d9d207..7e3c0230f6 100644 --- a/data-model/src/main/java/org/alfresco/repo/content/ContentStore.java +++ b/data-model/src/main/java/org/alfresco/repo/content/ContentStore.java @@ -92,6 +92,10 @@ public interface ContentStore */ public static final String PROTOCOL_DELIMITER = "://"; + public static final String STORAGE_CLASS_DEFAULT = "default"; + public static final String STORAGE_CLASS_ARCHIVE = "archive"; + public static final String STORAGE_CLASS_WORM = "worm"; + /** * The 'default' storage class * @@ -100,8 +104,10 @@ public interface ContentStore * the value is an empty set * the value is null */ - public static final String DEFAULT_SC = "default"; - + public static final StorageClassSet SCS_DEFAULT = new StorageClassSet(STORAGE_CLASS_DEFAULT); + public static final StorageClassSet SCS_ARCHIVE = new StorageClassSet(STORAGE_CLASS_ARCHIVE); + public static final StorageClassSet SCS_WORM = new StorageClassSet(STORAGE_CLASS_WORM); + /** * Check if the content URL format is supported by the store. * @@ -280,14 +286,14 @@ public interface ContentStore /** * Checks whether or not the current {@link ContentStore} supports the provided {@link Set} storage classes * - * @param storageClasses The storage classes that will be checked whether or not are supported + * @param storageClassSet The storage classes that will be checked whether or not are supported * @return true if the storage classes are supported, false otherwise. */ - default boolean isStorageClassesSupported(Set storageClasses) + default boolean isStorageClassesSupported(StorageClassSet storageClassSet) { - return storageClasses == null || - storageClasses.isEmpty() || - (1 == storageClasses.size() && storageClasses.contains(DEFAULT_SC)); + return storageClassSet == null || + storageClassSet.isEmpty() || + (1 == storageClassSet.size() && storageClassSet.equals(SCS_DEFAULT)); } /** @@ -295,17 +301,18 @@ public interface ContentStore */ default Set getSupportedStorageClasses() { - return Set.of(DEFAULT_SC); + return Set.of(ContentStore.STORAGE_CLASS_DEFAULT); } + /** * Updates the storage class for content * * @param contentUrl The URL of the content that will have its storage classes updated - * @param storageClasses The new storage classes + * @param storageClassSet The new storage class * @param parameters extra parameters */ - default void updateStorageClasses(String contentUrl, Set storageClasses, Map parameters) + default void updateStorageClasses(String contentUrl, StorageClassSet storageClassSet, Map parameters) { } @@ -314,16 +321,16 @@ public interface ContentStore * @param contentUrl the URL of the content for which the storage classes are to be requested * @return Returns the current storage classes for the content found at the contentUrl */ - default Set findStorageClasses(String contentUrl) + default StorageClassSet findStorageClasses(String contentUrl) { - return Set.of(DEFAULT_SC); + return SCS_DEFAULT; } /** * @return Returns the complete collection of allowed storage classes transitions. * The key represents the source storage classes while the value (as a {@link Set}) represents all the possible target storage classes. */ - default Map, Set>> getStorageClassesTransitions() + default Map> getStorageClassesTransitions() { return Collections.emptyMap(); } @@ -332,7 +339,7 @@ public interface ContentStore * @param contentUrl the URL of the content for which the storage classes transitions are to be requested * @return Returns the complete collection of allowed storage classes transitions for the content found at content URL */ - default Map, Set>> findStorageClassesTransitions(String contentUrl) + default Map> findStorageClassesTransitions(String contentUrl) { return Collections.emptyMap(); } diff --git a/data-model/src/main/java/org/alfresco/repo/content/StorageClassSet.java b/data-model/src/main/java/org/alfresco/repo/content/StorageClassSet.java new file mode 100644 index 0000000000..224d069304 --- /dev/null +++ b/data-model/src/main/java/org/alfresco/repo/content/StorageClassSet.java @@ -0,0 +1,45 @@ +/* + * #%L + * Alfresco Data model classes + * %% + * 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% + */ +package org.alfresco.repo.content; + +import java.util.Collections; +import java.util.HashSet; + +/** + * Represents the state of the content and it is internally represented as a set. + * It can have none, one, or multiple storage classes to specify the state + * e.g. [default], [archive], [archive, encrypted] + * + * @author Lucian Tuca + */ +public class StorageClassSet extends HashSet +{ + public StorageClassSet(String... storageClasses) + { + super(); + Collections.addAll(this, storageClasses); + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageClassesImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageClassesImpl.java index ce06f27b52..32ad914480 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageClassesImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageClassesImpl.java @@ -26,16 +26,15 @@ package org.alfresco.rest.api.impl; +import java.util.Set; +import java.util.stream.Collectors; + import org.alfresco.rest.api.ContentStorageClasses; import org.alfresco.rest.api.model.StorageClass; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.Paging; import org.alfresco.service.cmr.repository.ContentService; -import java.util.Collections; -import java.util.Set; -import java.util.stream.Collectors; - /** * Centralises access to storage classes functionality */ diff --git a/remote-api/src/main/java/org/alfresco/rest/framework/resource/content/BinaryProperty.java b/remote-api/src/main/java/org/alfresco/rest/framework/resource/content/BinaryProperty.java index ab3b781951..d6f2ebf88a 100755 --- a/remote-api/src/main/java/org/alfresco/rest/framework/resource/content/BinaryProperty.java +++ b/remote-api/src/main/java/org/alfresco/rest/framework/resource/content/BinaryProperty.java @@ -25,12 +25,12 @@ */ package org.alfresco.rest.framework.resource.content; -import static org.alfresco.repo.content.ContentStore.DEFAULT_SC; +import static org.alfresco.repo.content.ContentStore.SCS_DEFAULT; import java.io.Serializable; import java.util.Locale; -import java.util.Set; +import org.alfresco.repo.content.StorageClassSet; import org.alfresco.service.cmr.repository.ContentReader; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -51,7 +51,7 @@ public class BinaryProperty implements ContentInfo, Serializable private final String encoding; private final long length; private final Locale locale; - private final Set storageClasses; + private final StorageClassSet storageClassSet; /** * Sets the content length to zero, Locale to null, no stream and no caching @@ -74,7 +74,7 @@ public class BinaryProperty implements ContentInfo, Serializable this.encoding = reader.getEncoding(); this.length = reader.getSize(); this.locale = reader.getLocale(); - this.storageClasses = Set.of(DEFAULT_SC); + this.storageClassSet = SCS_DEFAULT; } /** @@ -89,14 +89,14 @@ public class BinaryProperty implements ContentInfo, Serializable this(mimeType, encoding, length, locale, null); } - public BinaryProperty(String mimeType, String encoding, long length, Locale locale, Set storageClasses) + public BinaryProperty(String mimeType, String encoding, long length, Locale locale, StorageClassSet storageClassSet) { super(); this.mimeType = mimeType; this.encoding = encoding; this.length = length; this.locale = locale; - this.storageClasses = storageClasses; + this.storageClassSet = storageClassSet; } public String getMimeType() @@ -132,9 +132,9 @@ public class BinaryProperty implements ContentInfo, Serializable return this.locale; } @JsonIgnore - public Set getStorageClasses() + public StorageClassSet getStorageClasses() { - return storageClasses; + return storageClassSet; } } diff --git a/remote-api/src/test/java/org/alfresco/rest/api/tests/NodeApiTest.java b/remote-api/src/test/java/org/alfresco/rest/api/tests/NodeApiTest.java index 4cf3ffcbe6..0a15799d18 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/tests/NodeApiTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/tests/NodeApiTest.java @@ -4807,7 +4807,7 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest // Check that all storage classes are retrieved assertNotNull(documentResp.getContent().getStorageClasses()); - assertEquals(Set.of(ContentStore.DEFAULT_SC), documentResp.getContent().getStorageClasses()); + assertEquals(ContentStore.SCS_DEFAULT, documentResp.getContent().getStorageClasses()); } /** diff --git a/remote-api/src/test/java/org/alfresco/rest/api/tests/StorageClassesTest.java b/remote-api/src/test/java/org/alfresco/rest/api/tests/StorageClassesTest.java index 4fc1399fd5..4f4d4216e8 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/tests/StorageClassesTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/tests/StorageClassesTest.java @@ -26,6 +26,14 @@ package org.alfresco.rest.api.tests; +import static org.alfresco.rest.api.tests.util.RestApiUtil.parseRestApiEntries; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.Set; + import org.alfresco.repo.content.ContentStore; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.rest.AbstractSingleNetworkSiteTest; @@ -39,14 +47,6 @@ import org.junit.Test; import org.mockito.Mock; import org.springframework.test.util.ReflectionTestUtils; -import java.util.List; -import java.util.Set; - -import static org.alfresco.rest.api.tests.util.RestApiUtil.parseRestApiEntries; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.when; - /** * V1 REST API tests for Storage Classes * @@ -99,14 +99,15 @@ public class StorageClassesTest extends AbstractSingleNetworkSiteTest { ReflectionTestUtils.setField(contentService, "store", mockStore); - Set expectedStorageClasses = Set.of("default", "archive", "worm"); - when(mockStore.getSupportedStorageClasses()).thenReturn(expectedStorageClasses); + Set expectedStorageClass = + Set.of(ContentStore.STORAGE_CLASS_DEFAULT, ContentStore.STORAGE_CLASS_ARCHIVE); + when(mockStore.getSupportedStorageClasses()).thenReturn(expectedStorageClass); PublicApiClient.Paging paging = getPaging(0, 100); HttpResponse response = getAll(STORAGE_CLASSES, paging, 200); List nodes = parseRestApiEntries(response.getJsonResponse(), StorageClass.class); assertNotNull(nodes); - assertEquals(3, nodes.size()); + assertEquals(2, nodes.size()); } } \ No newline at end of file diff --git a/repository/src/main/java/org/alfresco/repo/content/AbstractRoutingContentStore.java b/repository/src/main/java/org/alfresco/repo/content/AbstractRoutingContentStore.java index 3287cd5eda..1fd69de8ba 100644 --- a/repository/src/main/java/org/alfresco/repo/content/AbstractRoutingContentStore.java +++ b/repository/src/main/java/org/alfresco/repo/content/AbstractRoutingContentStore.java @@ -422,12 +422,12 @@ public abstract class AbstractRoutingContentStore implements ContentStore } @Override - public boolean isStorageClassesSupported(Set storageClasses) + public boolean isStorageClassesSupported(StorageClassSet storageClassSet) { boolean supported = false; for (ContentStore store : getAllStores()) { - if (store.isStorageClassesSupported(storageClasses)) + if (store.isStorageClassesSupported(storageClassSet)) { supported = true; break; @@ -436,7 +436,7 @@ public abstract class AbstractRoutingContentStore implements ContentStore // Done if (logger.isDebugEnabled()) { - logger.debug("The storage classes " + storageClasses + (supported ? "are" : "are not") + " supported by at least one store."); + logger.debug("The storage classes " + storageClassSet + (supported ? "are" : "are not") + " supported by at least one store."); } return supported; } @@ -444,16 +444,16 @@ public abstract class AbstractRoutingContentStore implements ContentStore @Override public Set getSupportedStorageClasses() { - Set supportedStorageClasses = new HashSet<>(); + Set supportedStorageClassSets = new HashSet<>(); for (ContentStore store : getAllStores()) { - supportedStorageClasses.addAll(store.getSupportedStorageClasses()); + supportedStorageClassSets.addAll(store.getSupportedStorageClasses()); } - return supportedStorageClasses; + return supportedStorageClassSets; } @Override - public void updateStorageClasses(String contentUrl, Set storageClasses, + public void updateStorageClasses(String contentUrl, StorageClassSet storageClassSet, Map parameters) { ContentStore store; @@ -490,7 +490,7 @@ public abstract class AbstractRoutingContentStore implements ContentStore } } - if (!store.exists(contentUrl) || !store.isStorageClassesSupported(storageClasses)) + if (!store.exists(contentUrl) || !store.isStorageClassesSupported(storageClassSet)) { store = null; @@ -498,7 +498,7 @@ public abstract class AbstractRoutingContentStore implements ContentStore { if (storeInList.isWriteSupported() && storeInList.exists(contentUrl) && - storeInList.isStorageClassesSupported(storageClasses)) + storeInList.isStorageClassesSupported(storageClassSet)) { store = storeInList; break; @@ -511,7 +511,7 @@ public abstract class AbstractRoutingContentStore implements ContentStore throw new UnsupportedOperationException( "Unable to find a write store to update the storage classes for content URL: \n" + " Content URL: " + contentUrl + "\n" + - " StorageClasses: " + storageClasses); + " StorageClasses: " + storageClassSet); } if (logger.isDebugEnabled()) @@ -520,11 +520,11 @@ public abstract class AbstractRoutingContentStore implements ContentStore " Content URL: " + contentUrl + "\n" + " Store: " + store); } - store.updateStorageClasses(contentUrl, storageClasses, parameters); + store.updateStorageClasses(contentUrl, storageClassSet, parameters); } @Override - public Set findStorageClasses(String contentUrl) + public StorageClassSet findStorageClasses(String contentUrl) { ContentStore contentStore = selectReadStore(contentUrl); @@ -534,7 +534,7 @@ public abstract class AbstractRoutingContentStore implements ContentStore { logger.debug("Storage classes not found for content URL: " + contentUrl); } - return new HashSet<>(); + return new StorageClassSet(); } if (logger.isDebugEnabled()) @@ -547,9 +547,9 @@ public abstract class AbstractRoutingContentStore implements ContentStore } @Override - public Map, Set>> getStorageClassesTransitions() + public Map> getStorageClassesTransitions() { - Map, Set>> supportedTransitions = new HashMap<>(); + Map> supportedTransitions = new HashMap<>(); for (ContentStore store : getAllStores()) { supportedTransitions.putAll(store.getStorageClassesTransitions()); @@ -558,7 +558,7 @@ public abstract class AbstractRoutingContentStore implements ContentStore } @Override - public Map, Set>> findStorageClassesTransitions(String contentUrl) + public Map> findStorageClassesTransitions(String contentUrl) { ContentStore contentStore = selectReadStore(contentUrl); diff --git a/repository/src/main/java/org/alfresco/repo/content/ContentServiceImpl.java b/repository/src/main/java/org/alfresco/repo/content/ContentServiceImpl.java index 63f681f4a9..fea984f609 100644 --- a/repository/src/main/java/org/alfresco/repo/content/ContentServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/content/ContentServiceImpl.java @@ -588,9 +588,9 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa } @Override - public boolean isStorageClassesSupported(Set storageClasses) + public boolean isStorageClassesSupported(StorageClassSet storageClassSet) { - return store.isStorageClassesSupported(storageClasses); + return store.isStorageClassesSupported(storageClassSet); } @Override @@ -600,7 +600,7 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa } @Override - public void updateStorageClasses(NodeRef nodeRef, Set storageClasses, Map parameters) + public void updateStorageClasses(NodeRef nodeRef, StorageClassSet storageClassSet, Map parameters) { ContentData contentData = getContentData(nodeRef, ContentModel.PROP_CONTENT); @@ -610,16 +610,16 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa throw new IllegalArgumentException("The supplied nodeRef " + nodeRef + " has no content."); } - if (!isStorageClassesSupported(storageClasses)) + if (!isStorageClassesSupported(storageClassSet)) { - throw new UnsupportedStorageClassException(store, storageClasses, "The supplied storage classes are not supported"); + throw new UnsupportedStorageClassException(store, storageClassSet, "The supplied storage classes are not supported"); } - store.updateStorageClasses(contentData.getContentUrl(), storageClasses, parameters); + store.updateStorageClasses(contentData.getContentUrl(), storageClassSet, parameters); } @Override - public Set findStorageClasses(NodeRef nodeRef) + public StorageClassSet findStorageClasses(NodeRef nodeRef) { ContentData contentData = getContentData(nodeRef, ContentModel.PROP_CONTENT); @@ -633,13 +633,13 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa } @Override - public Map, Set>> getStorageClassesTransitions() + public Map> getStorageClassesTransitions() { return store.getStorageClassesTransitions(); } @Override - public Map, Set>> findStorageClassesTransitions(NodeRef nodeRef) + public Map> findStorageClassesTransitions(NodeRef nodeRef) { ContentData contentData = getContentData(nodeRef, ContentModel.PROP_CONTENT); diff --git a/repository/src/main/java/org/alfresco/repo/content/caching/CachingContentStore.java b/repository/src/main/java/org/alfresco/repo/content/caching/CachingContentStore.java index cf3aa05436..7031a1cd8e 100644 --- a/repository/src/main/java/org/alfresco/repo/content/caching/CachingContentStore.java +++ b/repository/src/main/java/org/alfresco/repo/content/caching/CachingContentStore.java @@ -34,6 +34,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.alfresco.repo.content.ContentContext; import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.content.StorageClassSet; import org.alfresco.repo.content.caching.quota.QuotaManagerStrategy; import org.alfresco.repo.content.caching.quota.UnlimitedQuotaStrategy; import org.alfresco.repo.content.filestore.FileContentStore; @@ -491,9 +492,9 @@ public class CachingContentStore implements ContentStore, ApplicationEventPublis } @Override - public boolean isStorageClassesSupported(Set storageClasses) + public boolean isStorageClassesSupported(StorageClassSet storageClassSet) { - return backingStore.isStorageClassesSupported(storageClasses); + return backingStore.isStorageClassesSupported(storageClassSet); } @Override @@ -503,25 +504,25 @@ public class CachingContentStore implements ContentStore, ApplicationEventPublis } @Override - public void updateStorageClasses(String contentUrl, Set storageClasses, Map parameters) + public void updateStorageClasses(String contentUrl, StorageClassSet storageClassSet, Map parameters) { - backingStore.updateStorageClasses(contentUrl, storageClasses, parameters); + backingStore.updateStorageClasses(contentUrl, storageClassSet, parameters); } @Override - public Set findStorageClasses(String contentUrl) + public StorageClassSet findStorageClasses(String contentUrl) { return backingStore.findStorageClasses(contentUrl); } @Override - public Map, Set>> getStorageClassesTransitions() + public Map> getStorageClassesTransitions() { return backingStore.getStorageClassesTransitions(); } @Override - public Map, Set>> findStorageClassesTransitions(String contentUrl) + public Map> findStorageClassesTransitions(String contentUrl) { return backingStore.findStorageClassesTransitions(contentUrl); } diff --git a/repository/src/main/java/org/alfresco/repo/content/replication/AggregatingContentStore.java b/repository/src/main/java/org/alfresco/repo/content/replication/AggregatingContentStore.java index 135007126b..0ca5a94451 100644 --- a/repository/src/main/java/org/alfresco/repo/content/replication/AggregatingContentStore.java +++ b/repository/src/main/java/org/alfresco/repo/content/replication/AggregatingContentStore.java @@ -37,6 +37,7 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.content.AbstractContentStore; import org.alfresco.repo.content.ContentContext; import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.content.StorageClassSet; import org.alfresco.repo.content.UnsupportedContentUrlException; import org.alfresco.repo.content.caching.CachingContentStore; import org.alfresco.service.cmr.repository.ContentIOException; @@ -385,11 +386,11 @@ public class AggregatingContentStore extends AbstractContentStore } @Override - public boolean isStorageClassesSupported(Set storageClasses) + public boolean isStorageClassesSupported(StorageClassSet storageClassesSet) { // We only need to provide info about the primary store, // because the aggregating CS only allows to be written in the primary - return primaryStore.isStorageClassesSupported(storageClasses); + return primaryStore.isStorageClassesSupported(storageClassesSet); } @Override @@ -401,13 +402,13 @@ public class AggregatingContentStore extends AbstractContentStore } @Override - public void updateStorageClasses(String contentUrl, Set storageClasses, Map parameters) + public void updateStorageClasses(String contentUrl, StorageClassSet storageClassSet, Map parameters) { - primaryStore.updateStorageClasses(contentUrl, storageClasses, parameters); + primaryStore.updateStorageClasses(contentUrl, storageClassSet, parameters); } @Override - public Set findStorageClasses(String contentUrl) + public StorageClassSet findStorageClasses(String contentUrl) { if (primaryStore == null) { @@ -420,12 +421,12 @@ public class AggregatingContentStore extends AbstractContentStore { // Keep track of the unsupported state of the content URL - it might be a rubbish URL boolean contentUrlSupported = true; - Set storageClasses = null; + StorageClassSet storageClassesSet = null; // Check the primary store try { - storageClasses = primaryStore.findStorageClasses(contentUrl); + storageClassesSet = primaryStore.findStorageClasses(contentUrl); } catch (UnsupportedContentUrlException e) { @@ -433,9 +434,9 @@ public class AggregatingContentStore extends AbstractContentStore contentUrlSupported = false; } - if (storageClasses != null) + if (storageClassesSet != null) { - return storageClasses; + return storageClassesSet; } // the content is not in the primary store so we have to go looking for it @@ -443,7 +444,7 @@ public class AggregatingContentStore extends AbstractContentStore { try { - storageClasses = store.findStorageClasses(contentUrl); + storageClassesSet = store.findStorageClasses(contentUrl); } catch (UnsupportedContentUrlException e) { @@ -451,19 +452,19 @@ public class AggregatingContentStore extends AbstractContentStore contentUrlSupported = false; } - if (storageClasses != null) + if (storageClassesSet != null) { break; } } - if (storageClasses == null && !contentUrlSupported) + if (storageClassesSet == null && !contentUrlSupported) { // The content URL was not supported throw new UnsupportedContentUrlException(this, contentUrl); } - return storageClasses; + return storageClassesSet; } finally { @@ -472,7 +473,7 @@ public class AggregatingContentStore extends AbstractContentStore } @Override - public Map, Set>> getStorageClassesTransitions() + public Map> getStorageClassesTransitions() { // We only need to provide info about the primary store, // because the aggregating CS only allows to be written in the primary @@ -480,7 +481,7 @@ public class AggregatingContentStore extends AbstractContentStore } @Override - public Map, Set>> findStorageClassesTransitions(String contentUrl) + public Map> findStorageClassesTransitions(String contentUrl) { // We only need to provide info about the primary store, // because the aggregating CS only allows to be written in the primary diff --git a/repository/src/main/java/org/alfresco/repo/tenant/AbstractTenantRoutingContentStore.java b/repository/src/main/java/org/alfresco/repo/tenant/AbstractTenantRoutingContentStore.java index c8103bf795..2e4c00e273 100644 --- a/repository/src/main/java/org/alfresco/repo/tenant/AbstractTenantRoutingContentStore.java +++ b/repository/src/main/java/org/alfresco/repo/tenant/AbstractTenantRoutingContentStore.java @@ -38,6 +38,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.alfresco.repo.content.AbstractRoutingContentStore; import org.alfresco.repo.content.ContentContext; import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.content.StorageClassSet; import org.alfresco.repo.domain.tenant.TenantAdminDAO; import org.alfresco.repo.domain.tenant.TenantEntity; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -273,9 +274,9 @@ public abstract class AbstractTenantRoutingContentStore extends AbstractRoutingC } @Override - public boolean isStorageClassesSupported(Set storageClasses) + public boolean isStorageClassesSupported(StorageClassSet storageClassSet) { - return getTenantContentStore().isStorageClassesSupported(storageClasses); + return getTenantContentStore().isStorageClassesSupported(storageClassSet); } @Override @@ -285,26 +286,26 @@ public abstract class AbstractTenantRoutingContentStore extends AbstractRoutingC } @Override - public void updateStorageClasses(String contentUrl, Set storageClasses, + public void updateStorageClasses(String contentUrl, StorageClassSet storageClassSet, Map parameters) { - getTenantContentStore().updateStorageClasses(contentUrl, storageClasses, parameters); + getTenantContentStore().updateStorageClasses(contentUrl, storageClassSet, parameters); } @Override - public Set findStorageClasses(String contentUrl) + public StorageClassSet findStorageClasses(String contentUrl) { return getTenantContentStore().findStorageClasses(contentUrl); } @Override - public Map, Set>> getStorageClassesTransitions() + public Map> getStorageClassesTransitions() { return getTenantContentStore().getStorageClassesTransitions(); } @Override - public Map, Set>> findStorageClassesTransitions(String contentUrl) + public Map> findStorageClassesTransitions(String contentUrl) { return getTenantContentStore().findStorageClassesTransitions(contentUrl); } diff --git a/repository/src/main/java/org/alfresco/service/cmr/repository/ContentService.java b/repository/src/main/java/org/alfresco/service/cmr/repository/ContentService.java index 8cc191ec31..8caf9cab9a 100644 --- a/repository/src/main/java/org/alfresco/service/cmr/repository/ContentService.java +++ b/repository/src/main/java/org/alfresco/service/cmr/repository/ContentService.java @@ -31,6 +31,8 @@ import java.util.Map; import java.util.Set; import org.alfresco.api.AlfrescoPublicApi; +import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.content.StorageClassSet; import org.alfresco.service.Auditable; import org.alfresco.service.cmr.dictionary.InvalidTypeException; import org.alfresco.service.namespace.QName; @@ -177,10 +179,10 @@ public interface ContentService /** * Checks whether or not the current {@link ContentService} supports the provided {@link Set} storage classes * - * @param storageClasses The storage classes that will be checked whether or not are supported + * @param storageClassSet The storage classes that will be checked whether or not are supported * @return true if the storage classes are supported, false otherwise. */ - default boolean isStorageClassesSupported(Set storageClasses) + default boolean isStorageClassesSupported(StorageClassSet storageClassSet) { return false; } @@ -197,10 +199,10 @@ public interface ContentService * Updates the storage class for a {@link NodeRef} * * @param nodeRef The ref of the node that will have its storage classes updated - * @param storageClasses The new storage classes + * @param storageClassSet The new storage classes * @param parameters extra parameters */ - default void updateStorageClasses(NodeRef nodeRef, Set storageClasses, Map parameters) + default void updateStorageClasses(NodeRef nodeRef, StorageClassSet storageClassSet, Map parameters) { } @@ -209,16 +211,16 @@ public interface ContentService * @param nodeRef the {@link NodeRef} for which the storage classes are to be requested * @return Returns the current storage classes for the given {@link NodeRef} */ - default Set findStorageClasses(NodeRef nodeRef) + default StorageClassSet findStorageClasses(NodeRef nodeRef) { - return Collections.emptySet(); + return ContentStore.SCS_DEFAULT; } /** * @return Returns the complete collection of allowed storage classes transitions. * The key represents the source storage classes while the value (as a {@link Set}) represents all the possible target storage classes. */ - default Map, Set>> getStorageClassesTransitions() + default Map> getStorageClassesTransitions() { return Collections.emptyMap(); } @@ -227,7 +229,7 @@ public interface ContentService * @param nodeRef the {@link NodeRef} for which the storage classes transitions are to be requested * @return Returns the complete collection of allowed storage classes transitions for the content found at content URL */ - default Map, Set>> findStorageClassesTransitions(NodeRef nodeRef) + default Map> findStorageClassesTransitions(NodeRef nodeRef) { return Collections.emptyMap(); } diff --git a/repository/src/test/java/org/alfresco/repo/content/RoutingContentStoreTest.java b/repository/src/test/java/org/alfresco/repo/content/RoutingContentStoreTest.java index 72c814af35..52813ae84e 100644 --- a/repository/src/test/java/org/alfresco/repo/content/RoutingContentStoreTest.java +++ b/repository/src/test/java/org/alfresco/repo/content/RoutingContentStoreTest.java @@ -34,7 +34,6 @@ import static org.junit.Assert.fail; import java.io.File; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -182,15 +181,11 @@ public class RoutingContentStoreTest extends AbstractWritableContentStoreTest writer.putContent(content); String contentUrl = writer.getContentUrl(); - final Set storageClasses = Set.of("a-storage-class"); - - // Empty storage classes before update - assertTrue(routingStore.findStorageClasses(contentUrl).isEmpty()); // Update storage classes - routingStore.updateStorageClasses(contentUrl, storageClasses, null); + routingStore.updateStorageClasses(contentUrl, ContentStore.SCS_DEFAULT, null); - assertEquals(storageClasses, routingStore.findStorageClasses(contentUrl)); + assertEquals(ContentStore.SCS_DEFAULT, routingStore.findStorageClasses(contentUrl)); } /** @@ -247,7 +242,7 @@ public class RoutingContentStoreTest extends AbstractWritableContentStoreTest private static class AnyStorageClassesSupportedStore extends AbstractContentStore { FileContentStore fileStore; - Set storageClasses = new HashSet<>(); + StorageClassSet storageClasses = new StorageClassSet(); public AnyStorageClassesSupportedStore(FileContentStore fileStore) { @@ -280,12 +275,12 @@ public class RoutingContentStoreTest extends AbstractWritableContentStoreTest return true; } - public void updateStorageClasses(String contentUrl, Set storageClasses, Map parameters) + public void updateStorageClasses(String contentUrl, StorageClassSet storageClasses, Map parameters) { this.storageClasses = storageClasses; } - public Set findStorageClasses(String contentUrl) + public StorageClassSet findStorageClasses(String contentUrl) { return this.storageClasses; } diff --git a/repository/src/test/java/org/alfresco/repo/content/caching/CachingContentStoreTest.java b/repository/src/test/java/org/alfresco/repo/content/caching/CachingContentStoreTest.java index ae1c9387a6..d379db4b10 100644 --- a/repository/src/test/java/org/alfresco/repo/content/caching/CachingContentStoreTest.java +++ b/repository/src/test/java/org/alfresco/repo/content/caching/CachingContentStoreTest.java @@ -35,7 +35,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doThrow; @@ -48,10 +47,10 @@ import static org.mockito.Mockito.when; import java.io.IOException; import java.util.Locale; -import java.util.Set; import org.alfresco.repo.content.ContentContext; import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.content.StorageClassSet; import org.alfresco.repo.content.caching.quota.QuotaManagerStrategy; import org.alfresco.repo.content.caching.quota.UnlimitedQuotaStrategy; import org.alfresco.repo.content.filestore.SpoofedTextContentReader; @@ -528,11 +527,11 @@ public class CachingContentStoreTest @Test public void testBackingStoreIsCalledForSupportedStorageClasses() { - when(backingStore.isStorageClassesSupported(anySet())).thenReturn(true); + when(backingStore.isStorageClassesSupported(new StorageClassSet("a-certain-storage-class"))).thenReturn(true); - final Set storageClasses = Set.of("a-certain-storage-class"); - assertTrue(cachingStore.isStorageClassesSupported(storageClasses)); - verify(backingStore, times(1)).isStorageClassesSupported(storageClasses); + final StorageClassSet storageClassSet = new StorageClassSet("a-certain-storage-class"); + assertTrue(cachingStore.isStorageClassesSupported(storageClassSet)); + verify(backingStore, times(1)).isStorageClassesSupported(storageClassSet); } @Test @@ -547,17 +546,18 @@ public class CachingContentStoreTest public void testUpdateStorageClassesForGivenContentUrl() { String contentUrl = "contentUrl"; - final Set storageClasses = Set.of("a-certain-storage-class"); + final StorageClassSet storageClassSet = new StorageClassSet("a-certain-storage-class"); - cachingStore.updateStorageClasses(contentUrl, storageClasses, null); + cachingStore.updateStorageClasses(contentUrl, storageClassSet, null); - verify(backingStore, times(1)).updateStorageClasses(contentUrl, storageClasses, null); + verify(backingStore, times(1)).updateStorageClasses(contentUrl, storageClassSet, null); } @Test public void testFindStorageClassesForGivenContentUrl() { - when(backingStore.findStorageClasses(anyString())).thenReturn(emptySet()); + final StorageClassSet storageClassSet = new StorageClassSet(); + when(backingStore.findStorageClasses(anyString())).thenReturn(storageClassSet); assertTrue(cachingStore.findStorageClasses("a-contentUrl").isEmpty()); verify(backingStore, times(1)).findStorageClasses("a-contentUrl"); diff --git a/repository/src/test/java/org/alfresco/repo/content/filestore/FileContentStoreTest.java b/repository/src/test/java/org/alfresco/repo/content/filestore/FileContentStoreTest.java index 809185869f..aee4957d47 100644 --- a/repository/src/test/java/org/alfresco/repo/content/filestore/FileContentStoreTest.java +++ b/repository/src/test/java/org/alfresco/repo/content/filestore/FileContentStoreTest.java @@ -34,7 +34,6 @@ import static org.junit.Assert.fail; import java.io.File; import java.nio.ByteBuffer; import java.util.Locale; -import java.util.Set; import org.alfresco.repo.content.AbstractWritableContentStoreTest; import org.alfresco.repo.content.ContentContext; @@ -43,6 +42,7 @@ import org.alfresco.repo.content.ContentLimitProvider; import org.alfresco.repo.content.ContentLimitProvider.SimpleFixedLimitProvider; import org.alfresco.repo.content.ContentLimitViolationException; import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.content.StorageClassSet; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; @@ -352,13 +352,13 @@ public class FileContentStoreTest extends AbstractWritableContentStoreTest @Test public void testSupportsDefaultStorageClass() { - assertTrue(store.isStorageClassesSupported(Set.of(ContentStore.DEFAULT_SC))); + assertTrue(store.isStorageClassesSupported(ContentStore.SCS_DEFAULT)); } @Test public void testDoesNotSupportUnknownStorageClass() { - assertFalse(store.isStorageClassesSupported(Set.of("unknown"))); + assertFalse(store.isStorageClassesSupported(new StorageClassSet("unknown"))); } private void assertDirExists(File root, String dir) diff --git a/repository/src/test/java/org/alfresco/repo/content/replication/AggregatingContentStoreTest.java b/repository/src/test/java/org/alfresco/repo/content/replication/AggregatingContentStoreTest.java index 1eaf685975..72f0307c95 100644 --- a/repository/src/test/java/org/alfresco/repo/content/replication/AggregatingContentStoreTest.java +++ b/repository/src/test/java/org/alfresco/repo/content/replication/AggregatingContentStoreTest.java @@ -44,11 +44,11 @@ import static org.mockito.Mockito.when; import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.Set; import org.alfresco.repo.content.AbstractWritableContentStoreTest; import org.alfresco.repo.content.ContentContext; import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.content.StorageClassSet; import org.alfresco.repo.content.UnsupportedContentUrlException; import org.alfresco.repo.content.filestore.FileContentStore; import org.alfresco.service.cmr.repository.ContentReader; @@ -319,7 +319,7 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes @Test public void testIsStorageClassesSupported() { - Set sc = Set.of("a-certain-storage-class"); + final StorageClassSet sc = new StorageClassSet("a-certain-storage-class"); when(primaryStoreMock.isStorageClassesSupported(sc)).thenReturn(true); assertTrue(aggregatingContentStoreMock.isStorageClassesSupported(sc)); @@ -330,7 +330,7 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes @Test public void testStorageClassesIsNotSupported() { - Set sc = Set.of("a-certain-storage-class"); + final StorageClassSet sc = new StorageClassSet("a-certain-storage-class"); when(primaryStoreMock.isStorageClassesSupported(sc)).thenReturn(false); assertFalse(aggregatingContentStoreMock.isStorageClassesSupported(sc)); @@ -352,18 +352,19 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes public void testUpdateStorageClassesForGivenContentUrl() { String contentUrl = "contentUrl"; - final Set storageClasses = Set.of("a-certain-storage-class"); + final StorageClassSet sc = new StorageClassSet("a-certain-storage-class"); - aggregatingContentStoreMock.updateStorageClasses(contentUrl, storageClasses, null); + aggregatingContentStoreMock.updateStorageClasses(contentUrl, sc, null); - verify(primaryStoreMock, times(1)).updateStorageClasses(contentUrl, storageClasses, null); + verify(primaryStoreMock, times(1)).updateStorageClasses(contentUrl, sc, null); verifyNoInteractions(secondaryStoreMock); } @Test public void testFindStorageClassesForGivenContentUrlInPrimaryStore() { - when(primaryStoreMock.findStorageClasses(anyString())).thenReturn(emptySet()); + final StorageClassSet sc = new StorageClassSet(); + when(primaryStoreMock.findStorageClasses(anyString())).thenReturn(sc); assertTrue(aggregatingContentStoreMock.findStorageClasses("a-contentUrl").isEmpty()); verify(primaryStoreMock, times(1)).findStorageClasses("a-contentUrl"); @@ -373,11 +374,12 @@ public class AggregatingContentStoreTest extends AbstractWritableContentStoreTes @Test public void testFindStorageClassesForGivenContentUrlInSecondaryStore() { + final StorageClassSet sc = new StorageClassSet(); UnsupportedContentUrlException unsupportedContentUrlExc = new UnsupportedContentUrlException( aggregatingContentStoreMock, ""); when(primaryStoreMock.findStorageClasses(anyString())).thenThrow(unsupportedContentUrlExc); - when(secondaryStoreMock.findStorageClasses(anyString())).thenReturn(emptySet()); + when(secondaryStoreMock.findStorageClasses(anyString())).thenReturn(sc); assertTrue(aggregatingContentStoreMock.findStorageClasses("a-contentUrl").isEmpty()); verify(primaryStoreMock, times(1)).findStorageClasses("a-contentUrl"); diff --git a/repository/src/test/java/org/alfresco/repo/tenant/AbstractTenantRoutingContentStoreTest.java b/repository/src/test/java/org/alfresco/repo/tenant/AbstractTenantRoutingContentStoreTest.java index 8e2db48aa4..8dd610456f 100644 --- a/repository/src/test/java/org/alfresco/repo/tenant/AbstractTenantRoutingContentStoreTest.java +++ b/repository/src/test/java/org/alfresco/repo/tenant/AbstractTenantRoutingContentStoreTest.java @@ -26,7 +26,6 @@ package org.alfresco.repo.tenant; import java.io.Serializable; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,6 +34,7 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.ContentStore; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.content.StorageClassSet; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; @@ -120,7 +120,7 @@ public class AbstractTenantRoutingContentStoreTest extends TestCase public void testIsStorageClassesSupported() { - assertTrue(fileContentStore.isStorageClassesSupported(Collections.emptySet())); + assertTrue(fileContentStore.isStorageClassesSupported(new StorageClassSet())); } public void testGetSupportedStorageClasses() diff --git a/repository/src/test/java/org/alfresco/repo/version/ContentServiceImplTest.java b/repository/src/test/java/org/alfresco/repo/version/ContentServiceImplTest.java index 4301a8cf38..fdaa0f353f 100644 --- a/repository/src/test/java/org/alfresco/repo/version/ContentServiceImplTest.java +++ b/repository/src/test/java/org/alfresco/repo/version/ContentServiceImplTest.java @@ -180,7 +180,7 @@ public class ContentServiceImplTest extends BaseVersionStoreTest final NodeRef newNode = createNewNode(); final Set storageClasses = contentService.findStorageClasses(newNode); assertEquals(1, storageClasses.size()); - assertTrue(storageClasses.contains(ContentStore.DEFAULT_SC)); + assertEquals(storageClasses, ContentStore.SCS_DEFAULT); } @Test diff --git a/repository/src/test/java/org/alfresco/repo/version/ContentServiceImplWithMockedContentStoreTest.java b/repository/src/test/java/org/alfresco/repo/version/ContentServiceImplWithMockedContentStoreTest.java index 88f2d71bf1..6158d7b77f 100644 --- a/repository/src/test/java/org/alfresco/repo/version/ContentServiceImplWithMockedContentStoreTest.java +++ b/repository/src/test/java/org/alfresco/repo/version/ContentServiceImplWithMockedContentStoreTest.java @@ -34,6 +34,7 @@ import static org.mockito.Mockito.when; import org.alfresco.repo.content.ContentServiceImpl; import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.content.StorageClassSet; import org.alfresco.service.cmr.repository.ContentService; import org.junit.Before; import org.junit.Test; @@ -65,9 +66,10 @@ public class ContentServiceImplWithMockedContentStoreTest @Test public void testStoreIsCalledForIsStorageClassesSupported() { - when(store.isStorageClassesSupported(emptySet())).thenReturn(true); - assertTrue(contentService.isStorageClassesSupported(emptySet())); - verify(store, times(1)).isStorageClassesSupported(emptySet()); + final StorageClassSet sc = new StorageClassSet(); + when(store.isStorageClassesSupported(sc)).thenReturn(true); + assertTrue(contentService.isStorageClassesSupported(sc)); + verify(store, times(1)).isStorageClassesSupported(sc); } @Test