diff --git a/remote-api/src/main/java/org/alfresco/rest/api/ContentStorageInformation.java b/remote-api/src/main/java/org/alfresco/rest/api/ContentStorageInformation.java new file mode 100644 index 0000000000..454dc8ea68 --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/ContentStorageInformation.java @@ -0,0 +1,51 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 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.rest.api; + +import org.alfresco.rest.api.model.ContentStorageInfo; +import org.alfresco.rest.framework.resource.parameters.Parameters; +import org.alfresco.service.Experimental; + +/** + * Storage information for content API. + * Note: Currently marked as experimental and subject to change. + * + * @author mpichura + */ +@Experimental +public interface ContentStorageInformation +{ + /** + * Note: Currently marked as experimental and subject to change. + * @param nodeId Identifier of the node + * @param contentPropName Qualified name of content property (e.g. 'cm_content') + * @param parameters {@link Parameters} object to get the parameters passed into the request + * @return {@link ContentStorageInfo} object consisting of qualified name of content property and a map of storage properties + */ + @Experimental + ContentStorageInfo getStorageInfo(String nodeId, String contentPropName, Parameters parameters); +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageInformationImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageInformationImpl.java new file mode 100644 index 0000000000..164b0927a4 --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/ContentStorageInformationImpl.java @@ -0,0 +1,83 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 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.rest.api.impl; + +import org.alfresco.rest.api.ContentStorageInformation; +import org.alfresco.rest.api.model.ContentStorageInfo; +import org.alfresco.rest.framework.resource.parameters.Parameters; +import org.alfresco.service.Experimental; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +import java.util.Map; +/** + * Default implementation for {@link ContentStorageInformation} + * Note: Currently marked as experimental and subject to change. + * + * @author mpichura + */ +@Experimental +public class ContentStorageInformationImpl implements ContentStorageInformation +{ + + public static final char PREFIX_SEPARATOR = '_'; + + private final ContentService contentService; + private final NamespaceService namespaceService; + + public ContentStorageInformationImpl(ContentService contentService, NamespaceService namespaceService) + { + this.contentService = contentService; + this.namespaceService = namespaceService; + } + + /** + * {@inheritDoc} + */ + @Override + @Experimental + public ContentStorageInfo getStorageInfo(String nodeId, String contentPropName, Parameters parameters) + { + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId); + final QName propQName = getQName(contentPropName); + final Map storageProperties = contentService.getStorageProperties(nodeRef, propQName); + final ContentStorageInfo storageInfo = new ContentStorageInfo(); + storageInfo.setId(propQName.toPrefixString(namespaceService)); + storageInfo.setStorageProperties(storageProperties); + return storageInfo; + } + + private QName getQName(final String contentPropName) + { + final String properContentPropName = contentPropName.replace(PREFIX_SEPARATOR, QName.NAMESPACE_PREFIX); + return QName.resolveToQName(namespaceService, properContentPropName); + } + +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/ContentStorageInfo.java b/remote-api/src/main/java/org/alfresco/rest/api/model/ContentStorageInfo.java new file mode 100644 index 0000000000..d5d3329990 --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/ContentStorageInfo.java @@ -0,0 +1,71 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 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.rest.api.model; + +import java.util.HashMap; +import java.util.Map; + +/** + * Representation of storage information for content. + * + * @author mpichura + */ +public class ContentStorageInfo +{ + + /** + * Qualified name of content property + */ + private String id; + /** + * Key-value (String-String) collection representing storage properties of given content + */ + private Map storageProperties; + + public String getId() + { + return id; + } + + public void setId(String id) + { + this.id = id; + } + + public Map getStorageProperties() + { + if (storageProperties == null) { + storageProperties = new HashMap<>(); + } + return storageProperties; + } + + public void setStorageProperties(Map storageProperties) + { + this.storageProperties = storageProperties; + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelation.java b/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelation.java new file mode 100644 index 0000000000..78dca635f0 --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeStorageInfoRelation.java @@ -0,0 +1,75 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 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.rest.api.nodes; + +import org.alfresco.rest.api.ContentStorageInformation; +import org.alfresco.rest.api.model.ContentStorageInfo; +import org.alfresco.rest.framework.WebApiDescription; +import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException; +import org.alfresco.rest.framework.resource.RelationshipResource; +import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction; +import org.alfresco.rest.framework.resource.parameters.Parameters; +import org.alfresco.service.Experimental; +import org.alfresco.util.PropertyCheck; +import org.springframework.beans.factory.InitializingBean; + +import javax.servlet.http.HttpServletResponse; + +/** + * Node storage information. + * Note: Currently marked as experimental and subject to change. + * + * @author mpichura + */ +@Experimental +@RelationshipResource(name = "storage-info", entityResource = NodesEntityResource.class, title = "Node's content storage information") +public class NodeStorageInfoRelation implements RelationshipResourceAction.ReadById, InitializingBean +{ + + private final ContentStorageInformation storageInformation; + + public NodeStorageInfoRelation(ContentStorageInformation storageInformation) + { + this.storageInformation = storageInformation; + } + + @WebApiDescription(title = "Get storage properties", + description = "Retrieves storage properties for given node's content", + successStatus = HttpServletResponse.SC_OK) + @Override + public ContentStorageInfo readById(String entityResourceId, String id, Parameters parameters) + throws RelationshipResourceNotFoundException + { + return storageInformation.getStorageInfo(entityResourceId, id, parameters); + } + + @Override + public void afterPropertiesSet() throws Exception + { + PropertyCheck.mandatory(this, "storageInformation", storageInformation); + } +} diff --git a/remote-api/src/main/resources/alfresco/public-rest-context.xml b/remote-api/src/main/resources/alfresco/public-rest-context.xml index 825eff0312..1c642a8323 100644 --- a/remote-api/src/main/resources/alfresco/public-rest-context.xml +++ b/remote-api/src/main/resources/alfresco/public-rest-context.xml @@ -606,6 +606,26 @@ + + + + + + + + + org.alfresco.rest.api.ContentStorageInformation + + + + + + + + + + + @@ -977,7 +997,11 @@ - + + + + + diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/ContentStorageInformationImplTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/ContentStorageInformationImplTest.java new file mode 100644 index 0000000000..bddec6f0ca --- /dev/null +++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/ContentStorageInformationImplTest.java @@ -0,0 +1,96 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 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.rest.api.impl; + +import org.alfresco.rest.api.model.ContentStorageInfo; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.NamespaceService; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@RunWith(MockitoJUnitRunner.class) +public class ContentStorageInformationImplTest +{ + @Mock + private ContentService contentService; + @Mock + private NamespaceService namespaceService; + + @InjectMocks + private ContentStorageInformationImpl objectUnderTest; + + @Test + public void shouldReturnStorageInfoResponseWithNonEmptyStorageProps() + { + + final String nodeId = "dummy-node-id"; + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId); + final String contentPropName = "cm:content"; + + final Map storageProps = Map.of("x-amz-storage-class", "INTELLIGENT_TIERING", "x-alf-archived", "false"); + Mockito.when(contentService.getStorageProperties(Mockito.eq(nodeRef), Mockito.any())).thenReturn(storageProps); + Mockito.when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)) + .thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + Mockito.when(namespaceService.getPrefixes(NamespaceService.CONTENT_MODEL_1_0_URI)) + .thenReturn(List.of(NamespaceService.CONTENT_MODEL_PREFIX)); + + final ContentStorageInfo storageInfo = objectUnderTest.getStorageInfo(nodeId, contentPropName, null); + + Assert.assertEquals(storageProps, storageInfo.getStorageProperties()); + Assert.assertEquals(storageInfo.getId(), contentPropName); + } + + @Test + public void shouldReturnStorageInfoResponseWithEmptyStorageProps() + { + final String nodeId = "dummy-node-id"; + final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId); + final String contentPropName = "cm:content"; + + Mockito.when(contentService.getStorageProperties(Mockito.eq(nodeRef), Mockito.any())).thenCallRealMethod(); + Mockito.when(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)) + .thenReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + Mockito.when(namespaceService.getPrefixes(NamespaceService.CONTENT_MODEL_1_0_URI)) + .thenReturn(List.of(NamespaceService.CONTENT_MODEL_PREFIX)); + + final ContentStorageInfo storageInfo = objectUnderTest.getStorageInfo(nodeId, contentPropName, null); + + Assert.assertEquals(Collections.emptyMap(), storageInfo.getStorageProperties()); + Assert.assertEquals(storageInfo.getId(), contentPropName); + } +}