diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/metadata-delegation-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/metadata-delegation-context.xml deleted file mode 100644 index 106cf0cb90..0000000000 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/metadata-delegation-context.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationAdminService - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationAdminService.attachDelegate=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationAdminService.detachDelegate=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationAdminService.getDefinedDelegations=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationAdminService.getDelegationFor=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationAdminService.getDelegationsFrom=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationAdminService.*=ACL_DENY - - - - - - - - - - - - - - - - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationService - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationService.hasDelegateForAspect=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationService.getDelegateFor=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationService.getDelegateProperties=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationService.getDelegateProperty=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationService.hasAspectOnDelegate=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationService.getDelegations=ACL_ALLOW - org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationService.*=ACL_DENY - - - - - - - - - - - - diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/metadata-referral-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/metadata-referral-context.xml new file mode 100644 index 0000000000..f5c7c81edb --- /dev/null +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/metadata-referral-context.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferralAdminService + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferralAdminService.attachReferrer=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferralAdminService.detachReferrer=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferralAdminService.getDefinedReferrals=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferralAdminService.getReferralFor=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferralAdminService.getAttachedReferralsFrom=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferralAdminService.*=ACL_DENY + + + + + + + + + + + + + + + + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataService + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataService.isReferringMetadata=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataService.getReferentNode=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataService.getReferredProperties=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataService.getReferredProperty=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataService.hasReferredAspect=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataService.getAttachedReferrals=ACL_ALLOW + org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataService.*=ACL_DENY + + + + + + + + + + + + diff --git a/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml b/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml index 921a34aaf0..e38c0e6e54 100644 --- a/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml +++ b/rm-server/config/alfresco/module/org_alfresco_module_rm/module-context.xml @@ -267,8 +267,8 @@ - - + + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationAdminService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationAdminService.java deleted file mode 100644 index 0a49ce4d2c..0000000000 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationAdminService.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2005-2015 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; - -import static org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.ChainedDelegationUnsupported; - -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.namespace.QName; - -import java.util.Set; - -/** - * A service to manage the delegation of aspect metadata. - * Using this service a node can be {@link #attachDelegate linked} to a delegate node for a configured set of aspects. - * (Note that this delegate node must already exist within the database.) - * Then any read request for relevant metadata such as hasAspect or getProperties can be delegated to the - * linked node. - *

- * For a link to be made, there must be a {@link #getDefinedDelegations() defined Delegation} already in the system. - * This means that a peer-association type will have to have been declared and that a spring bean will have to have - * defined which aspects are to be handled by this {@code Delegation}. - * - * @author Neil Mc Erlean - * @since 3.0.a - */ -public interface DelegationAdminService -{ - /** - * Creates a link between two nodes such that the first {@code nodeRef} can 'inherit' or reuse some aspect - * metadata from another node - the {@code delegateNodeRef}. - *

- * Note that links can currently only extend between two pairs of nodes and cannot be chained. - * - * @param nodeRef the node which is to inherit additional metadata. - * @param delegateNodeRef the node which will provide the additional metadata. - * @param assocType the type of the peer association which will link the two nodes. - * @return a {@link Delegation} object which defines the link type. - * @throws ChainedDelegationUnsupported if an attempt is made to attach nodes such that a chain would be made. - */ - Delegation attachDelegate(NodeRef nodeRef, NodeRef delegateNodeRef, QName assocType); - - /** - * Removes an existing metadata delegation link between two nodes. - * - * @param nodeRef the node which has been linked to a delegate. - * @param assocType the type of the peer assocation forming the link. - * @return the removed {@link Delegation}. - */ - Delegation detachDelegate(NodeRef nodeRef, QName assocType); - - /** - * Gets the set of defined {@link Delegation}s. - * - * @return the set of defined Delegations. - */ - Set getDefinedDelegations(); - - /** - * Gets the {@link Delegation} which contains the specified {@code aspectName} if there is one. - * Note that only one {@link Delegation} may declare that it handles any particular aspect. - * - * @param aspectName the name of the aspect whose {@link Delegation} is sought. - * @return the {@link Delegation} which handles the specified aspect, if there is one. - */ - Delegation getDelegationFor(QName aspectName); - - /** - * Gets the set of {@link Delegation}s which are in effect from the specified {@code nodeRef}. - * From these, you can retrieve the types of peer associations which are linked to the specified - * {@code nodeRef} as well as the aspect types that are handled. - * - * @param nodeRef the NodeRef whose delegations are sought. - * @return the set of {@link Delegation}s from the specified nodeRef. - */ - Set getDelegationsFrom(NodeRef nodeRef); -} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationAdminServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationAdminServiceImpl.java deleted file mode 100644 index 0a2463ba05..0000000000 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationAdminServiceImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2005-2015 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; - -import static org.alfresco.util.collections.CollectionUtils.transform; - -import org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.ChainedDelegationUnsupported; -import org.alfresco.service.cmr.repository.AssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.collections.Function; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * @author Neil Mc Erlean - * @since 3.0.a - */ -public class DelegationAdminServiceImpl implements DelegationAdminService -{ - private DelegationRegistry registry; - private NodeService nodeService; - - public void setNodeService(NodeService service) - { - this.nodeService = service; - } - - public void setDelegationRegistry(DelegationRegistry registry) - { - this.registry = registry; - } - - @Override public Delegation attachDelegate(NodeRef nodeRef, NodeRef delegateNodeRef, QName assocType) - { - final Delegation delegation = getDelegationForAssociation(assocType); - - // Prevent the creation of chains of delegation from node A to B to C. - - // If any nodes are already delegating to nodeRef for the specified assoc, then we can't chain. - final List existingDelegatorAssocs = nodeService.getSourceAssocs(nodeRef, assocType); - if ( !existingDelegatorAssocs.isEmpty()) - { - final List existingDelegators = transform(existingDelegatorAssocs, - new Function() - { - @Override public NodeRef apply(AssociationRef assocRef) - { - return assocRef.getSourceRef(); - } - }); - throw new ChainedDelegationUnsupported("Cannot attach delegate", existingDelegators); - } - - // Likewise if this delegate node is already itself delegating elsewhere, we cannot chain. - final List existingDelegateAssocs = nodeService.getTargetAssocs(delegateNodeRef, assocType); - if ( !existingDelegateAssocs.isEmpty()) - { - // If it's not empty, it should only have one value in it, but just in case... - final List existingDelegates = transform(existingDelegateAssocs, - new Function() - { - @Override public NodeRef apply(AssociationRef assocRef) - { - return assocRef.getTargetRef(); - } - }); - throw new ChainedDelegationUnsupported("Cannot attach delegate", existingDelegates); - } - - // OK. We're good to go. We're not making a chain here. - nodeService.createAssociation(nodeRef, delegateNodeRef, assocType); - - return delegation; - } - - private Delegation getDelegationForAssociation(QName assocType) - { - final Delegation delegation = registry.getDelegateForAssociation(assocType); - - if (delegation == null) - { - throw new IllegalArgumentException("No " + Delegation.class.getSimpleName() + - " configured for assocType " + assocType); - } - return delegation; - } - - @Override public Delegation detachDelegate(NodeRef nodeRef, QName assocType) - { - // Is the association there? - final List assocs = nodeService.getTargetAssocs(nodeRef, assocType); - - if (assocs == null || assocs.isEmpty()) - { - return null; - } - else - { - Delegation result = getDelegationForAssociation(assocType); - - // There should only be one such association... but we'll remove them all just in case - for (AssociationRef assocRef : assocs) - { - nodeService.removeAssociation(nodeRef, assocRef.getTargetRef(), assocType); - } - - return result; - } - } - - @Override public Delegation getDelegationFor(QName aspectName) - { - Delegation delegation = null; - - for (Delegation d : getDefinedDelegations()) - { - if (d.getAspects().contains(aspectName)) - { - delegation = d; - break; - } - } - return delegation; - } - - @Override public Set getDelegationsFrom(NodeRef nodeRef) - { - final Set allDelegations = getDefinedDelegations(); - - final Set result = new HashSet<>(); - for (Delegation d : allDelegations) - { - final QName assocType = d.getAssocType(); - if ( !nodeService.getTargetAssocs(nodeRef, assocType).isEmpty()) - { - result.add(d); - } - } - - return result; - } - - @Override public Set getDefinedDelegations() - { - return registry.getDelegations(); - } -} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationException.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationException.java deleted file mode 100644 index ea978abf7b..0000000000 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationException.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2005-2015 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.service.cmr.repository.NodeRef; - -import java.util.List; - -/** - * Generic class for any runtime exceptions related to metadata delegates. - * - * @author Neil Mc Erlean - * @since 3.0.a - */ -public class DelegationException extends AlfrescoRuntimeException -{ - public DelegationException(String msgId) { super(msgId); } - public DelegationException(String msgId, Throwable cause) { super(msgId, cause); } - - public static class InvalidDelegation extends DelegationException - { - public InvalidDelegation(String msgId) - { - super(msgId); - } - } - - /** A Metadata Delegation already exists. */ - public static class DelegationAlreadyExists extends DelegationException - { - private final Delegation delegation; - - public DelegationAlreadyExists(String msgId, Delegation delegation) - { - super(msgId); - this.delegation = delegation; - } - } - - /** - * A {@link Delegation} has not been found. - * Remember that a Delegation is the definition of a type of link. - */ - public static class DelegationNotFound extends DelegationException - { - public DelegationNotFound(String msgId) - { - super(msgId); - } - } - - /** - * A Delegate has not been found. - * Remember that a Delegate is an instance of a link between two nodes. - */ - public static class DelegateNotFound extends DelegationException - { - public DelegateNotFound(String msgId) - { - super(msgId); - } - } - - /** - * Exception to report that we currently do not support chained delegation. - */ - public static class ChainedDelegationUnsupported extends DelegationException - { - private final List nodesAlreadyDelegating; - - public ChainedDelegationUnsupported(String msgId, List nodesAlreadyDelegating) - { - super(msgId); - this.nodesAlreadyDelegating = nodesAlreadyDelegating; - } - - public List getNodesAlreadyDelegating() - { - return this.nodesAlreadyDelegating; - } - - @Override public String toString() - { - StringBuilder msg = new StringBuilder(); - msg.append(this.getClass().getSimpleName()).append(" Already delegating from: ") - .append(nodesAlreadyDelegating.toString()); - return msg.toString(); - } - } -} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationRegistry.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationRegistry.java deleted file mode 100644 index 54133ee40b..0000000000 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationRegistry.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2005-2015 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; - -import org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.DelegationAlreadyExists; -import org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.InvalidDelegation; -import org.alfresco.service.namespace.QName; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -/** - * This is a registry of {@link Delegation delegations} which have been defined in the system. - * - * @author Neil Mc Erlean - * @since 3.0.a - */ -public class DelegationRegistry -{ - private final Set delegations = new HashSet<>(); - - public void register(Delegation delegation) - { - // Various validation steps to do here to ensure we get consistent, sensible Delegations registered. - if (delegations.contains(delegation)) - { - throw new DelegationAlreadyExists("Cannot register duplicate delegation", delegation); - } - for (Delegation existingDelegation : delegations) - { - if (existingDelegation.getAssocType().equals(delegation.getAssocType())) - { - throw new InvalidDelegation("Cannot register two delegations with the same assocType. " + - "Existing: " + existingDelegation + - " New: " + delegation); - } - // Yes this is a for loop inside a for loop but we're assuming these sets will not be large. - for (QName existingAspect : existingDelegation.getAspects()) - { - if (delegation.getAspects().contains(existingAspect)) - { - throw new InvalidDelegation("Cannot register two delegations with the same aspect. " + - "Existing: " + existingDelegation + - " New: " + delegation); - } - } - } - - this.delegations.add(delegation); - } - - public Set getDelegations() - { - return Collections.unmodifiableSet(delegations); - } - - public Delegation getDelegateForAssociation(QName assocType) - { - for (Delegation d : delegations) - { - if (d.getAssocType().equals(assocType)) - { - return d; - } - } - return null; - } -} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationService.java deleted file mode 100644 index b4048761c0..0000000000 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationService.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2005-2015 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; - -import static org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.DelegationNotFound; - -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.namespace.QName; - -import java.io.Serializable; -import java.util.Map; - -/** - * This service provides read-only access to delegated metadata. - * TODO complete. - * - * @author Neil Mc Erlean - * @since 3.0.a - */ -public interface DelegationService -{ - /** - * Checks if the specified nodeRef has an attached {@link Delegation} for the specified aspect. - * - * @param nodeRef the nodeRef which may or may not have a delegate node for the specified aspect. - * @param aspectName the name of the aspect for which the node may or may not have delegation. - * @return whether the node is delegating metadata reads for the specified aspect. - * @throws InvalidNodeRefException if the supplied nodeRef does not exist. - * @throws DelegationNotFound if no delegation for the specified aspect has been attached. - */ - boolean hasDelegateForAspect(NodeRef nodeRef, QName aspectName); - - /** - * Gets the delegate node for the specified aspect, if there is one. - * - * @param nodeRef the node with the delegate. - * @param aspectName the aspect name. - * @return the nodeRef of the delegate if there is one, else {@code null}. - * @throws DelegationNotFound if no delegation for the specified aspect has been attached. - */ - NodeRef getDelegateFor(NodeRef nodeRef, QName aspectName); - - /** - * Gets all the property values from the delegate node for the specified aspect. - * - * @param nodeRef the node with the delegate. - * @param aspectName the aspect name which holds the properties we want. - * @return the property values as obtained from the delegate node. - */ - Map getDelegateProperties(NodeRef nodeRef, QName aspectName); - - /** - * Gets the specified property value from the delegate node. - * - * @param nodeRef the node with the delegate. - * @param propertyName the property name which we want. - * @return the property value as obtained from the delegate node. - */ - Serializable getDelegateProperty(NodeRef nodeRef, QName propertyName); - - /** - * Determines if a given aspect is present on a node's delegates. - * - * @param nodeRef the node for which a delegate is sought. - * @param aspectName the aspect which is to be checked. - * @return Returns true if the aspect has been applied to one of the given node's delegates, - * otherwise false - */ - boolean hasAspectOnDelegate(NodeRef nodeRef, QName aspectName); - - /** - * Gets all {@link Delegation delegations} currently attached to the specified node. - * - * @param nodeRef the node whose delegations are sought. - * @return Returns a map of all {@link Delegation delegations} by NodeRef for the specified nodeRef. - */ - Map getDelegations(NodeRef nodeRef); -} - diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/Delegation.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/MetadataReferral.java similarity index 63% rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/Delegation.java rename to rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/MetadataReferral.java index 05a2e3caef..2b739e6a23 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/Delegation.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/MetadataReferral.java @@ -16,9 +16,9 @@ * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; -import org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.InvalidDelegation; +import org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.InvalidMetadataReferral; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.namespace.QName; @@ -27,27 +27,29 @@ import java.util.Objects; import java.util.Set; /** - * A Delegation is a definition of a {@link #aspects set of aspects} whose metadata are to be delegated. - * Using a Delegation, you can attach a delegate node to any node and {@code hasAspect} and - * {@code getPropert[y|ies]} calls can be delegated to the delegate node. + * A {@link MetadataReferral} is a definition of a {@link #aspects set of metadata} which are, in effect, shared + * between multiple nodes. + * Using a {@link MetadataReferral}, you can link two NodeRefs such that {@code hasAspect} and + * {@code getPropert[y|ies]} calls on one node can can be delegated to the other. In this way a defined set of + * metadata on one node can be made available for read access via another node. *

* The connection between the nodes is made with a specified {@link #assocType peer association}. *

- * Note that a Delegation is not an instance of a link between two nodes, but the definition of such a link. + * Note that a {@link MetadataReferral} is not an instance of a link between two nodes, but the definition of such a link. * * @author Neil Mc Erlean - * @since 3.0.a + * @since 2.4.a */ -public class Delegation +public class MetadataReferral { private DictionaryService dictionaryService; - private DelegationRegistry delegationRegistry; + private ReferralRegistry referralRegistry; private Set aspects; private QName assocType; - public Delegation() + public MetadataReferral() { - // Intentionally empty + // Intentionally empty. } public void setDictionaryService(DictionaryService service) @@ -55,9 +57,9 @@ public class Delegation this.dictionaryService = service; } - public void setDelegationRegistry(DelegationRegistry registry) + public void setReferralRegistry(ReferralRegistry registry) { - this.delegationRegistry = registry; + this.referralRegistry = registry; } public void setAssocType(QName assocType) @@ -74,25 +76,25 @@ public class Delegation { if (this.assocType == null) { - throw new InvalidDelegation("Illegal null assocType"); + throw new InvalidMetadataReferral("Illegal null assocType"); } if (aspects == null || aspects.isEmpty()) { - throw new InvalidDelegation("Illegal null or empty aspects set"); + throw new InvalidMetadataReferral("Illegal null or empty aspects set"); } if (dictionaryService.getAssociation(assocType) == null) { - throw new InvalidDelegation("Association not found: " + assocType); + throw new InvalidMetadataReferral("Association not found: " + assocType); } for (QName aspect : aspects) { if (dictionaryService.getAspect(aspect) == null) { - throw new InvalidDelegation("Aspect not found: " + aspect); + throw new InvalidMetadataReferral("Aspect not found: " + aspect); } } - this.delegationRegistry.register(this); + this.referralRegistry.register(this); } /** Gets the type of the peer association linking the node to its delegate. */ @@ -101,7 +103,7 @@ public class Delegation return assocType; } - /** Gets the set of aspects which are being delegated. */ + /** Gets the set of aspects which are being referred. */ public Set getAspects() { return Collections.unmodifiableSet(aspects); @@ -115,9 +117,9 @@ public class Delegation @Override public boolean equals(Object other) { boolean result = false; - if (other instanceof Delegation) + if (other instanceof MetadataReferral) { - Delegation that = (Delegation)other; + MetadataReferral that = (MetadataReferral)other; result = this.aspects.equals(that.aspects) && this.assocType.equals(that.assocType); } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralAdminService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralAdminService.java new file mode 100644 index 0000000000..cafad45b0e --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralAdminService.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; + +import static org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.ChainedMetadataReferralUnsupported; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; + +import java.util.Set; + +/** + * A service to manage the referral of aspect metadata. + * Using this service a node can be {@link #attachReferrer linked} to a referrer node for a specific set of aspects. + * (Note that this referrer node must already exist within the database.) + * Then any read request for relevant metadata such as hasAspect or getProperties can be delegated to the + * linked node. + *

+ * For a link to be made, there must be a {@link #getDefinedReferrals() defined MetadataReferral} already in the system. + * This means that a peer-association type will have to have been declared and that a spring bean will have to have + * defined which aspects are to be handled by this {@link MetadataReferral}. + * + * @author Neil Mc Erlean + * @since 2.4.a + */ +public interface ReferralAdminService +{ + /** + * Creates a link between two nodes such that the first {@code referrer} can 'inherit' or reuse some aspect + * metadata from another node - the {@code referrer}. + *

+ * Note that links can currently only extend between two pairs of nodes and cannot be chained. + * + * @param referrer the node which is to inherit additional metadata. + * @param referent the node which will provide the additional metadata. + * @param assocType the type of the peer association which will link the two nodes. + * @return a {@link MetadataReferral} object which defines the link type. + * @throws ChainedMetadataReferralUnsupported if an attempt is made to attach nodes such that a chain would be made. + */ + // FIXME Remove assocType entirely from the API + MetadataReferral attachReferrer(NodeRef referrer, NodeRef referent, QName assocType); + + /** + * Removes an existing metadata link between two nodes. + * + * @param referrer the node which has been linked to a metadata source. + * @param assocType the type of the peer association forming the link. + * @return the removed {@link MetadataReferral}. + */ + MetadataReferral detachReferrer(NodeRef referrer, QName assocType); + + /** + * Gets the set of defined {@link MetadataReferral}s. + * + * @return the set of defined {@link MetadataReferral}. + */ + Set getDefinedReferrals(); + + /** + * Gets the {@link MetadataReferral} which contains the specified {@code aspectName} if there is one. + * Note that only one {@link MetadataReferral} may declare that it handles any particular aspect. + * + * @param aspectName the name of the aspect whose {@link MetadataReferral} is sought. + * @return the {@link MetadataReferral} which handles the specified aspect, if there is one. + */ + MetadataReferral getReferralFor(QName aspectName); + + /** + * Gets the set of {@link MetadataReferral}s which are currently applied from the specified {@code referrer}. + * From these, the types of peer associations which are linked to the specified + * {@code referrer} as well as the aspect types that are handled can be retrieved. + * + * @param referrer the NodeRef whose {@link MetadataReferral}s are sought. + * @return the set of {@link MetadataReferral}s from the specified referrer. + */ + Set getAttachedReferralsFrom(NodeRef referrer); + + /** + * Gets the {@link MetadataReferral} from the specified {@code referrer} for the specified {@code aspectName}, + * if there is one. + * + * @param referrer the node whose {@link MetadataReferral} is sought. + * @param aspectName the aspect name for which a {@link MetadataReferral} is sought. + * @return the {@link MetadataReferral} which is attached to the specified node if there is one, else {@code null}. + */ + MetadataReferral getAttachedReferralFrom(NodeRef referrer, QName aspectName); +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralAdminServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralAdminServiceImpl.java new file mode 100644 index 0000000000..117261b990 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralAdminServiceImpl.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; + +import static org.alfresco.util.collections.CollectionUtils.transform; + +import org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.ChainedMetadataReferralUnsupported; +import org.alfresco.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.collections.Function; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Neil Mc Erlean + * @since 2.4.a + */ +public class ReferralAdminServiceImpl implements ReferralAdminService +{ + private ReferralRegistry registry; + private NodeService nodeService; + + public void setNodeService(NodeService service) + { + this.nodeService = service; + } + + public void setReferralRegistry(ReferralRegistry registry) + { + this.registry = registry; + } + + @Override public MetadataReferral attachReferrer(NodeRef referrer, NodeRef referent, QName assocType) + { + final MetadataReferral metadataReferral = getReferralForAssociation(assocType); + + // Prevent the creation of chains of metadata linking from node A to B to C. + + // If any nodes are already linked to referrer for the specified assoc, then we can't chain. + final List existingReferrerAssocs = nodeService.getSourceAssocs(referrer, assocType); + if ( !existingReferrerAssocs.isEmpty()) + { + final List existingReferrers = transform(existingReferrerAssocs, + new Function() + { + @Override public NodeRef apply(AssociationRef assocRef) + { + return assocRef.getSourceRef(); + } + }); + throw new ChainedMetadataReferralUnsupported("Cannot attach referrer", existingReferrers); + } + + // Likewise if this referent node is already itself linked elsewhere, we cannot chain. + final List existingReferentAssocs = nodeService.getTargetAssocs(referent, assocType); + if ( !existingReferentAssocs.isEmpty()) + { + // If it's not empty, it should only have one value in it, but just in case... + final List existingReferents = transform(existingReferentAssocs, + new Function() + { + @Override public NodeRef apply(AssociationRef assocRef) + { + return assocRef.getTargetRef(); + } + }); + throw new ChainedMetadataReferralUnsupported("Cannot attach referent", existingReferents); + } + + // OK. We're good to go. We're not making a chain here. + nodeService.createAssociation(referrer, referent, assocType); + + return metadataReferral; + } + + /** Gets the {@link MetadataReferral} which uses the specified {@code assocType}. */ + private MetadataReferral getReferralForAssociation(QName assocType) + { + final MetadataReferral metadataReferral = registry.getReferralForAssociation(assocType); + + if (metadataReferral == null) + { + throw new IllegalArgumentException("No " + MetadataReferral.class.getSimpleName() + + " configured for assocType " + assocType); + } + return metadataReferral; + } + + @Override public MetadataReferral detachReferrer(NodeRef referrer, QName assocType) + { + // Is the association there? + final List assocs = nodeService.getTargetAssocs(referrer, assocType); + + if (assocs == null || assocs.isEmpty()) + { + return null; + } + else + { + MetadataReferral result = getReferralForAssociation(assocType); + + // There should only be one such association... but we'll remove them all just in case + for (AssociationRef assocRef : assocs) + { + nodeService.removeAssociation(referrer, assocRef.getTargetRef(), assocType); + } + + return result; + } + } + + @Override public MetadataReferral getReferralFor(QName aspectName) + { + MetadataReferral metadataReferral = null; + + for (MetadataReferral d : getDefinedReferrals()) + { + if (d.getAspects().contains(aspectName)) + { + metadataReferral = d; + break; + } + } + return metadataReferral; + } + + @Override public Set getAttachedReferralsFrom(NodeRef referrer) + { + final Set allMetadataReferrals = getDefinedReferrals(); + + final Set result = new HashSet<>(); + for (MetadataReferral d : allMetadataReferrals) + { + final QName assocType = d.getAssocType(); + if ( !nodeService.getTargetAssocs(referrer, assocType).isEmpty()) + { + result.add(d); + } + } + + return result; + } + + @Override public MetadataReferral getAttachedReferralFrom(NodeRef referrer, QName aspectName) + { + final Set allMetadataReferrals = getAttachedReferralsFrom(referrer); + + for (MetadataReferral d : allMetadataReferrals) + { + if (d.getAspects().contains(aspectName)) return d; + } + return null; + } + + @Override public Set getDefinedReferrals() + { + return registry.getMetadataReferrals(); + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralRegistry.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralRegistry.java new file mode 100644 index 0000000000..2dacba8d45 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralRegistry.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; + +import org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.MetadataReferralAlreadyExists; +import org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.InvalidMetadataReferral; +import org.alfresco.service.namespace.QName; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * This is a registry of {@link MetadataReferral}s which have been defined in the system. + * + * @author Neil Mc Erlean + * @since 2.4.a + */ +public class ReferralRegistry +{ + private final Set metadataReferrals = new HashSet<>(); + + public void register(MetadataReferral metadataReferral) + { + // Various validation steps to do here to ensure we get consistent, sensible referrals registered. + if (metadataReferrals.contains(metadataReferral)) + { + throw new MetadataReferralAlreadyExists("Cannot register duplicate referral", metadataReferral); + } + for (MetadataReferral existingMetadataReferral : metadataReferrals) + { + if (existingMetadataReferral.getAssocType().equals(metadataReferral.getAssocType())) + { + throw new InvalidMetadataReferral("Cannot register two referrals with the same assocType. " + + "Existing: " + existingMetadataReferral + + " New: " + metadataReferral); + } + // Yes this is a for loop inside a for loop but we're assuming these sets will not be large. + for (QName existingAspect : existingMetadataReferral.getAspects()) + { + if (metadataReferral.getAspects().contains(existingAspect)) + { + throw new InvalidMetadataReferral("Cannot register two referrals with the same aspect. " + + "Existing: " + existingMetadataReferral + + " New: " + metadataReferral); + } + } + } + + this.metadataReferrals.add(metadataReferral); + } + + public Set getMetadataReferrals() + { + return Collections.unmodifiableSet(metadataReferrals); + } + + /** + * Gets the {@link MetadataReferral} which is defined to use the specified {@code assocType}. + * + * @param assocType the peer association type whose {@link MetadataReferral} is sought. + * @return the {@link MetadataReferral} defined to use the specified {@code assocType} if there is one, else {@code null}. + */ + public MetadataReferral getReferralForAssociation(QName assocType) + { + for (MetadataReferral d : metadataReferrals) + { + if (d.getAssocType().equals(assocType)) + { + return d; + } + } + return null; + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataException.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataException.java new file mode 100644 index 0000000000..83cbb83ed1 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataException.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.repository.NodeRef; + +import java.util.List; + +/** + * Generic class for any runtime exceptions related to metadata referrals. + * + * @author Neil Mc Erlean + * @since 2.4.a + */ +public class ReferredMetadataException extends AlfrescoRuntimeException +{ + public ReferredMetadataException(String msgId) { super(msgId); } + public ReferredMetadataException(String msgId, Throwable cause) { super(msgId, cause); } + + /** This exception may be thrown when a {@link MetadataReferral} was incorrectly initialised. */ + public static class InvalidMetadataReferral extends ReferredMetadataException + { + public InvalidMetadataReferral(String msgId) + { + super(msgId); + } + } + + /** This exception may be thrown when a {@link MetadataReferral} already exists. */ + public static class MetadataReferralAlreadyExists extends ReferredMetadataException + { + private final MetadataReferral metadataReferral; + + public MetadataReferralAlreadyExists(String msgId, MetadataReferral metadataReferral) + { + super(msgId); + this.metadataReferral = metadataReferral; + } + } + + /** A {@link MetadataReferral} has not been found. */ + public static class MetadataReferralNotFound extends ReferredMetadataException + { + public MetadataReferralNotFound(String msgId) + { + super(msgId); + } + } + + /** A referent Node has not been found. */ + public static class ReferentNodeNotFound extends ReferredMetadataException + { + public ReferentNodeNotFound(String msgId) + { + super(msgId); + } + } + + /** Exception to report that chains of metadata referral are not currently supported. */ + public static class ChainedMetadataReferralUnsupported extends ReferredMetadataException + { + private final List existingReferrers; + + public ChainedMetadataReferralUnsupported(String msgId, List existingReferrers) + { + super(msgId); + this.existingReferrers = existingReferrers; + } + + public List getExistingReferrers() + { + return this.existingReferrers; + } + + @Override public String toString() + { + StringBuilder msg = new StringBuilder(); + msg.append(this.getClass().getSimpleName()).append(" Already referring from: ") + .append(existingReferrers.toString()); + return msg.toString(); + } + } + + /** Exception to report that metadata referral is not supported for metadata defined on content types. */ + public static class TypeMetadataReferralUnsupported extends ReferredMetadataException + { + public TypeMetadataReferralUnsupported(String msgId) + { + super(msgId); + } + } +} diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataService.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataService.java new file mode 100644 index 0000000000..8e18c2bcf7 --- /dev/null +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataService.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; + +import static org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.MetadataReferralNotFound; +import static org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.TypeMetadataReferralUnsupported; + +import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; + +import java.io.Serializable; +import java.util.Map; + +/** + * This service provides read-only access to linked metadata. + * TODO complete! Include definition of referent etc or link to package.html + * + * @author Neil Mc Erlean + * @since 2.4.a + */ +public interface ReferredMetadataService +{ + /** + * Checks if the specified referrer has an attached {@link MetadataReferral} for the specified aspect. + * + * @param potentialReferrer the referrer which may or may not be linked to a referent node. + * @param aspectName the name of the aspect. + * @return whether the node is linked to a referent node for the specified aspect. + * @throws InvalidNodeRefException if the supplied referrer does not exist. + * @throws MetadataReferralNotFound if no {@link MetadataReferral} is defined for the specified aspect. + */ + boolean isReferringMetadata(NodeRef potentialReferrer, QName aspectName); + + /** + * Gets the referent node for the specified aspect, if there is one. + * + * @param referrer the node whose referent is sought. + * @param aspectName the aspect name. + * @return the referent of the provided referrer if there is one, else {@code null}. + * @throws InvalidNodeRefException if the supplied referrer does not exist. + * @throws MetadataReferralNotFound if no {@link MetadataReferral} is defined for the specified aspect. + */ + NodeRef getReferentNode(NodeRef referrer, QName aspectName); + + /** + * Gets all the property values from the referent node for the specified aspect. + * + * @param referrer the referring node. + * @param aspectName the aspect name which holds the properties we want. + * @return the property values as obtained from the referent node. + */ + Map getReferredProperties(NodeRef referrer, QName aspectName); + + /** + * Gets the specified property value from the referent node. + * + * @param referrer the referring node. + * @param propertyName the property name whose value is sought. + * @return the property value as obtained from the referent node. + * @throws IllegalArgumentException if the specified property is not defined. + * @throws TypeMetadataReferralUnsupported if the specified property is not defined on an aspect. + */ + Serializable getReferredProperty(NodeRef referrer, QName propertyName); + + /** + * Determines if the specified aspect is present on a node's referent. + * + * @param referrer the referring node. + * @param aspectName the aspect which is to be checked on the referent node. + * @return Returns true if the aspect has been applied to the referent node, + * otherwise false + */ + boolean hasReferredAspect(NodeRef referrer, QName aspectName); + + /** + * Gets all {@link MetadataReferral referrals} currently attached to the specified node. + * + * @param potentialReferrer the node whose attached {@link MetadataReferral referrals} are sought. + * @return Returns a map of all attached {@link MetadataReferral referrals} for the specified nodeRef. + * The map has the form {@code (key, value) = (MetadataReferral, referent Node for that Referral)} + * The map may be empty but will not be {@code null}. + */ + Map getAttachedReferrals(NodeRef potentialReferrer); +} + diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationServiceImpl.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataServiceImpl.java similarity index 51% rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationServiceImpl.java rename to rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataServiceImpl.java index 3b7190c7d5..add2c367c2 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationServiceImpl.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataServiceImpl.java @@ -16,10 +16,11 @@ * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; -import static org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.DelegateNotFound; -import static org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.DelegationNotFound; +import static org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.MetadataReferralNotFound; +import static org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.ReferentNodeNotFound; +import static org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.TypeMetadataReferralUnsupported; import static org.alfresco.util.collections.CollectionUtils.filterKeys; import org.alfresco.service.cmr.dictionary.ClassDefinition; @@ -40,17 +41,17 @@ import java.util.Set; /** * @author Neil Mc Erlean - * @since 3.0.a + * @since 2.4.a */ -public class DelegationServiceImpl implements DelegationService +public class ReferredMetadataServiceImpl implements ReferredMetadataService { - private DelegationAdminService delegationAdminService; - private DictionaryService dictionaryService; - private NodeService nodeService; + private ReferralAdminService referralAdminService; + private DictionaryService dictionaryService; + private NodeService nodeService; - public void setDelegationAdminService(DelegationAdminService service) + public void setReferralAdminService(ReferralAdminService service) { - this.delegationAdminService = service; + this.referralAdminService = service; } public void setDictionaryService(DictionaryService service) @@ -63,54 +64,60 @@ public class DelegationServiceImpl implements DelegationService this.nodeService = service; } - @Override public boolean hasDelegateForAspect(NodeRef nodeRef, QName aspectName) + @Override public boolean isReferringMetadata(NodeRef potentialReferrer, QName aspectName) { - final Delegation delegation = delegationAdminService.getDelegationFor(aspectName); - - if ( !nodeService.exists(nodeRef)) + if ( !nodeService.exists(potentialReferrer)) { - throw new InvalidNodeRefException(nodeRef); + throw new InvalidNodeRefException(potentialReferrer); } - else if (delegation == null) + + final MetadataReferral metadataReferral = referralAdminService.getReferralFor(aspectName); + + if (metadataReferral == null) { - throw new DelegationNotFound("No delegation found for aspect: " + aspectName); + throw new MetadataReferralNotFound("No defined referral found for aspect: " + aspectName); } else { - final List targetAssocs = nodeService.getTargetAssocs(nodeRef, delegation.getAssocType()); + final List targetAssocs = nodeService.getTargetAssocs(potentialReferrer, metadataReferral.getAssocType()); return !targetAssocs.isEmpty(); } } - @Override public NodeRef getDelegateFor(NodeRef nodeRef, QName aspectName) + @Override public NodeRef getReferentNode(NodeRef referrer, QName aspectName) { - final Delegation d = delegationAdminService.getDelegationFor(aspectName); + if ( !nodeService.exists(referrer)) + { + throw new InvalidNodeRefException(referrer); + } + + final MetadataReferral d = referralAdminService.getReferralFor(aspectName); if (d == null) { - throw new DelegationNotFound("No delegation found for aspect: " + aspectName); + throw new MetadataReferralNotFound("No defined referral found for aspect: " + aspectName); } else { final QName assocType = d.getAssocType(); - final List assocs = nodeService.getTargetAssocs(nodeRef, assocType); + final List assocs = nodeService.getTargetAssocs(referrer, assocType); return assocs.isEmpty() ? null : assocs.get(0).getTargetRef(); } } - @Override public Map getDelegateProperties(NodeRef nodeRef, final QName aspectName) + @Override public Map getReferredProperties(NodeRef referrer, final QName aspectName) { - final NodeRef delegateNode = getDelegateFor(nodeRef, aspectName); + final NodeRef referentNode = getReferentNode(referrer, aspectName); - if (delegateNode == null) + if (referentNode == null) { - throw new DelegateNotFound("No delegate node found for " + nodeRef + " " + aspectName); + throw new ReferentNodeNotFound("No referent node found for " + referrer + " " + aspectName); } else { - Map allProps = nodeService.getProperties(delegateNode); - Map aspectProps = filterKeys(allProps, + final Map allProps = nodeService.getProperties(referentNode); + final Map aspectProps = filterKeys(allProps, new Function() { @Override public Boolean apply(QName propName) @@ -125,7 +132,7 @@ public class DelegationServiceImpl implements DelegationService } } - @Override public Serializable getDelegateProperty(NodeRef nodeRef, QName propertyName) + @Override public Serializable getReferredProperty(NodeRef referrer, QName propertyName) { final PropertyDefinition propDefn = dictionaryService.getProperty(propertyName); @@ -141,38 +148,38 @@ public class DelegationServiceImpl implements DelegationService msg.append("Property '").append(propertyName).append("' is not defined on an aspect: ") .append(aspectDefn.getName()); - throw new IllegalArgumentException(msg.toString()); + throw new TypeMetadataReferralUnsupported(msg.toString()); } - Map allPropValues = getDelegateProperties(nodeRef, aspectDefn.getName()); + final Map allPropValues = getReferredProperties(referrer, aspectDefn.getName()); return allPropValues.get(propertyName); } - @Override public boolean hasAspectOnDelegate(NodeRef nodeRef, QName aspectName) + @Override public boolean hasReferredAspect(NodeRef referrer, QName aspectName) { - final NodeRef delegateNode = getDelegateFor(nodeRef, aspectName); + final NodeRef referentNode = getReferentNode(referrer, aspectName); - if (delegateNode == null) + if (referentNode == null) { - throw new DelegateNotFound("No delegate node found for " + nodeRef + " " + aspectName); + throw new ReferentNodeNotFound("No referent node found for " + referrer + " " + aspectName); } else { - return nodeService.hasAspect(delegateNode, aspectName); + return nodeService.hasAspect(referentNode, aspectName); } } - @Override public Map getDelegations(NodeRef nodeRef) + @Override public Map getAttachedReferrals(NodeRef potentialReferrer) { - Set delegations = delegationAdminService.getDelegationsFrom(nodeRef); + Set metadataReferrals = referralAdminService.getAttachedReferralsFrom(potentialReferrer); - Map result = new HashMap<>(); - for (Delegation d : delegations) + Map result = new HashMap<>(); + for (MetadataReferral mr : metadataReferrals) { - // We need only use the first aspect to get the Delegation object - if (!d.getAspects().isEmpty()) + // We need only use the first aspect to get the MetadataReferral object + if (!mr.getAspects().isEmpty()) { - result.put(d, getDelegateFor(nodeRef, d.getAspects().iterator().next())); + result.put(mr, getReferentNode(potentialReferrer, mr.getAspects().iterator().next())); } } diff --git a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/package-info.java b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/package-info.java similarity index 53% rename from rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/package-info.java rename to rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/package-info.java index b35ca04e74..7a1a00ae73 100644 --- a/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/package-info.java +++ b/rm-server/source/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/package-info.java @@ -17,30 +17,31 @@ * along with Alfresco. If not, see . */ /** - * This package contains the types that deliver the Metadata Delegation feature. - * Metadata delegation allows read-only aspect metadata for any given Alfresco node to - * be sourced from another node, the delegate. + * This package contains the types that deliver the Metadata Referral feature. + * Metadata referral allows node metadata to be shared between multiple Alfresco nodes. *

* In this way nodes can 'inherit' some of their metadata from another node which may * have benefits when more than one node is required to share some of the same metadata. *

- * Multiple nodes may share the same delegate node and one node may be linked to multiple - * delegates. + * Only aspect metadata can be shared and it is only shared as read-only data to the other nodes. + * The node which contains the metadata values is the 'referent' node and any nodes which have been + * linked to the referent and share the metadata are known as referrers. *

- * The linking of nodes to their metadata delegates is done with Alfresco peer associations. + * Multiple nodes may share the same referent node and one node may be linked to multiple referrers. + *

+ * The linking of nodes to their metadata referents is done with Alfresco peer associations. * Association types must be declared in an Alfresco content model in the normal way. * Spring configuration is used to assign each association type a set of aspects which will - * be available from the delegate via the association. + * be available from the referent via the association. *

- * See {@link org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationAdminService} - * for details on how to create and destroy delegation links between nodes. + * See {@link org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferralAdminService} + * for details on how to create and destroy metadata links between nodes. *

- * The read-only access to delegated metadat is made available via the - * See {@link org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationService} + * See {@link org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataService} * for details on how the data access is performed. *

- * See {@link org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationRegistry} - * for details on what {@link org.alfresco.module.org_alfresco_module_rm.metadatadelegation.Delegation}s + * See {@link org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferralRegistry} + * for details on what {@link org.alfresco.module.org_alfresco_module_rm.referredmetadata.MetadataReferral}s * are defined in the system. */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; \ No newline at end of file +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; \ No newline at end of file diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationServiceImplUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationServiceImplUnitTest.java deleted file mode 100644 index b28fae5de4..0000000000 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationServiceImplUnitTest.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2005-2015 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * 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 . - */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; - -import static java.util.Collections.emptyMap; -import static java.util.Arrays.asList; -import static org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.DelegateNotFound; -import static org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.DelegationNotFound; -import static org.alfresco.module.org_alfresco_module_rm.test.util.ExceptionUtils.expectedException; -import static org.alfresco.module.org_alfresco_module_rm.test.util.FPUtils.asSet; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.when; - -import org.alfresco.service.cmr.dictionary.ClassDefinition; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.dictionary.PropertyDefinition; -import org.alfresco.service.cmr.repository.AssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.namespace.QName; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -/** - * Unit tests for {@link DelegationServiceImpl}. - * - * @author Neil Mc Erlean - * @since 3.0.a - */ -public class DelegationServiceImplUnitTest -{ - @InjectMocks private final DelegationServiceImpl delegationService = new DelegationServiceImpl(); - - @Mock DictionaryService mockDictionaryService; - @Mock NodeService mockNodeService; - @Mock DelegationAdminServiceImpl mockDelegationAdminService; - - /** This node has a delegate node. */ - private final NodeRef nodeWithDelegate = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "nodeWithDelegate"); - /** This is the delgate for {@link #nodeWithDelegate}. */ - private final NodeRef delegateNode = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "delegateNode"); - /** This node has no delegate node. */ - private final NodeRef nodeWithoutDelegate = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "nodeWithoutDelegate"); - - /** The type of the peer association that links the delegate to its source. */ - private final QName delegateAssocType = QName.createQName("test", "delegateAssocType"); - /** The instance of the association between {@link #nodeWithDelegate} and {@link #delegateNode}. */ - private final AssociationRef delegateAssocRef = new AssociationRef(nodeWithDelegate, delegateAssocType, delegateNode); - - /** Name of an aspect that has been delegated. */ - private final QName delegatedAspect1 = QName.createQName("test", "delegatedAspect1"); - /** Name of an aspect that has been delegated. */ - private final QName delegatedAspect2 = QName.createQName("test", "delegatedAspect2"); - /** Name of a content class (a type in this case) that has not been delegated. - * N.B. Types can't be delegated currently. */ - private final QName undelegatedType = QName.createQName("test", "undelegatedType"); - - private final QName delegatedProp = QName.createQName("test", "delegatedProp"); - private final Serializable delegatedPropValue = "hello"; - private final QName undelegatedProp = QName.createQName("test", "undelegatedProp"); - - private final Delegation delegate = new Delegation() - {{ - this.setAssocType(delegateAssocType); - this.setAspects(asSet(delegatedAspect1, delegatedAspect2)); - }}; - - @Before public void setUp() - { - MockitoAnnotations.initMocks(this); - - final PropertyDefinition aspectProp = mock(PropertyDefinition.class); - final ClassDefinition aspectDefn = mock(ClassDefinition.class); - when(aspectDefn.getName()).thenReturn(delegatedAspect1); - when(aspectProp.getContainerClass()).thenReturn(aspectDefn); - when(aspectDefn.isAspect()).thenReturn(true); - - final PropertyDefinition typeProp = mock(PropertyDefinition.class); - final ClassDefinition typeDefn = mock(ClassDefinition.class); - when(typeDefn.getName()).thenReturn(undelegatedType); - when(typeProp.getContainerClass()).thenReturn(typeDefn); - when(typeDefn.isAspect()).thenReturn(false); - - when(mockDictionaryService.getProperty(delegatedProp)).thenReturn(aspectProp); - - when(mockDelegationAdminService.getDelegationsFrom(nodeWithDelegate)).thenReturn(asSet(delegate)); - for (QName delegatedAspect : asSet(delegatedAspect1, delegatedAspect2)) - { - when(mockDelegationAdminService.getDelegationFor(delegatedAspect)).thenReturn(delegate); - when(mockNodeService.hasAspect(delegateNode, delegatedAspect)).thenReturn(true); - } - when(mockNodeService.getSourceAssocs(delegateNode, delegateAssocType)).thenReturn(asList(delegateAssocRef)); - when(mockNodeService.getTargetAssocs(nodeWithDelegate, delegateAssocType)).thenReturn(asList(delegateAssocRef)); - when(mockNodeService.exists(any(NodeRef.class))).thenReturn(true); - when(mockNodeService.getProperties(delegateNode)) - .thenReturn(new HashMap() - {{ - this.put(delegatedProp, delegatedPropValue); - }}); - } - - @Test public void hasDelegateForAspect() - { - assertTrue(delegationService.hasDelegateForAspect(nodeWithDelegate, delegatedAspect1)); - expectedException(DelegationNotFound.class, () -> delegationService.hasDelegateForAspect(nodeWithoutDelegate, undelegatedType)); - assertFalse(delegationService.hasDelegateForAspect(nodeWithoutDelegate, delegatedAspect1)); - } - - @Test public void getDelegateFor() - { - assertEquals(delegateNode, delegationService.getDelegateFor(nodeWithDelegate, delegatedAspect1)); - expectedException(DelegationNotFound.class, () -> - { - delegationService.getDelegateFor(nodeWithDelegate, undelegatedType); - return null; - }); - assertNull(delegationService.getDelegateFor(nodeWithoutDelegate, delegatedAspect1)); - } - - @Test public void getDelegateProperties() - { - final Map expectedProps = new HashMap<>(); - expectedProps.put(delegatedProp, delegatedPropValue); - - assertEquals(expectedProps, delegationService.getDelegateProperties(nodeWithDelegate, delegatedAspect1)); - - expectedException(DelegationNotFound.class, - () -> delegationService.getDelegateProperties(nodeWithDelegate, undelegatedType)); - - expectedException(DelegateNotFound.class, - () -> delegationService.getDelegateProperties(nodeWithoutDelegate, delegatedAspect1)); - } - - @Test public void getDelegateProperty() - { - assertEquals(delegatedPropValue, delegationService.getDelegateProperty(nodeWithDelegate, delegatedProp)); - - expectedException(IllegalArgumentException.class, - () -> delegationService.getDelegateProperty(nodeWithDelegate, undelegatedProp)); - - expectedException(DelegationNotFound.class, - () -> delegationService.getDelegateProperties(nodeWithoutDelegate, delegatedProp)); - } - - @Test public void hasAspectOnDelegate() - { - assertTrue(delegationService.hasAspectOnDelegate(nodeWithDelegate, delegatedAspect1)); - - expectedException(DelegationNotFound.class, - () -> delegationService.hasAspectOnDelegate(nodeWithDelegate, undelegatedType)); - - expectedException(DelegateNotFound.class, - () -> delegationService.hasAspectOnDelegate(nodeWithoutDelegate, delegatedAspect1)); - } - - @Test public void getDelegations() - { - final Map expectedDelegations = new HashMap<>(); - expectedDelegations.put(delegate, delegateNode); - - assertEquals(expectedDelegations, delegationService.getDelegations(nodeWithDelegate)); - assertEquals(emptyMap(), delegationService.getDelegations(nodeWithoutDelegate)); - } -} diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/MetadataReferralUnitTest.java similarity index 67% rename from rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationUnitTest.java rename to rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/MetadataReferralUnitTest.java index d63e6409d4..847f64f0d1 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/MetadataReferralUnitTest.java @@ -16,10 +16,10 @@ * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; import static java.util.Collections.emptySet; -import static org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.InvalidDelegation; +import static org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.InvalidMetadataReferral; import static org.alfresco.module.org_alfresco_module_rm.test.util.ExceptionUtils.expectedException; import static org.alfresco.module.org_alfresco_module_rm.test.util.FPUtils.asListFrom; import static org.alfresco.module.org_alfresco_module_rm.test.util.FPUtils.asSet; @@ -41,17 +41,17 @@ import org.mockito.MockitoAnnotations; import java.util.List; /** - * Unit tests for {@link Delegation}. + * Unit tests for {@link MetadataReferral}. * * @author Neil Mc Erlean * @since 3.0.a */ -public class DelegationUnitTest +public class MetadataReferralUnitTest { @Mock DictionaryService mockDictionaryService; @Mock NodeService mockNodeService; - private final DelegationAdminServiceImpl metadataDelegationService = new DelegationAdminServiceImpl(); + private final ReferralAdminServiceImpl referralAdminService = new ReferralAdminServiceImpl(); private final NodeRef node1 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "node1"); private final NodeRef node2 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "node2"); @@ -63,66 +63,66 @@ public class DelegationUnitTest { MockitoAnnotations.initMocks(this); - metadataDelegationService.setNodeService(mockNodeService); + referralAdminService.setNodeService(mockNodeService); } - @Test public void nullOrEmptyDelegatesAreForbidden() + @Test public void nullOrEmptyReferralsAreForbidden() { - List invalidDelegations = asListFrom(() -> new Delegation(), + List invalidMetadataReferrals = asListFrom(() -> new MetadataReferral(), () -> { - Delegation d = new Delegation(); - d.setAssocType(assoc1); - d.setAspects(null); - d.setDictionaryService(mockDictionaryService); - return d; + MetadataReferral mr = new MetadataReferral(); + mr.setAssocType(assoc1); + mr.setAspects(null); + mr.setDictionaryService(mockDictionaryService); + return mr; }, () -> { - Delegation d = new Delegation(); - d.setAssocType(assoc1); - d.setAspects(emptySet()); - d.setDictionaryService(mockDictionaryService); - return d; + MetadataReferral mr = new MetadataReferral(); + mr.setAssocType(assoc1); + mr.setAspects(emptySet()); + mr.setDictionaryService(mockDictionaryService); + return mr; }, () -> { - Delegation d = new Delegation(); - d.setAssocType(null); - d.setAspects(asSet(aspect1, aspect2)); - d.setDictionaryService(mockDictionaryService); - return d; + MetadataReferral mr = new MetadataReferral(); + mr.setAssocType(null); + mr.setAspects(asSet(aspect1, aspect2)); + mr.setDictionaryService(mockDictionaryService); + return mr; }); - invalidDelegations.stream() - .forEach(d -> expectedException(InvalidDelegation.class, () -> { - d.validateAndRegister(); + invalidMetadataReferrals.stream() + .forEach(mr -> expectedException(InvalidMetadataReferral.class, () -> { + mr.validateAndRegister(); return null; } )); } - @Test(expected=InvalidDelegation.class) - public void delegateMustHaveAssocThatExists() + @Test(expected=InvalidMetadataReferral.class) + public void referralMustHaveAssocThatExists() { when(mockDictionaryService.getAssociation(assoc1)).thenReturn(null); when(mockDictionaryService.getAspect(aspect1)).thenReturn(mock(AspectDefinition.class)); - Delegation d = new Delegation(); - d.setAssocType(assoc1); - d.setAspects(asSet(aspect1)); - d.setDictionaryService(mockDictionaryService); - d.validateAndRegister(); + MetadataReferral mr = new MetadataReferral(); + mr.setAssocType(assoc1); + mr.setAspects(asSet(aspect1)); + mr.setDictionaryService(mockDictionaryService); + mr.validateAndRegister(); } - @Test(expected=InvalidDelegation.class) - public void delegateMustHaveAspectsAllOfWhichExist() + @Test(expected=InvalidMetadataReferral.class) + public void referralMustHaveAspectsAllOfWhichExist() { when(mockDictionaryService.getAssociation(assoc1)).thenReturn(mock(AssociationDefinition.class)); when(mockDictionaryService.getAspect(aspect1)).thenReturn(mock(AspectDefinition.class)); when(mockDictionaryService.getAspect(aspect2)).thenReturn(null); - Delegation d = new Delegation(); - d.setAssocType(assoc1); - d.setAspects(asSet(aspect1, aspect2)); - d.setDictionaryService(mockDictionaryService); - d.validateAndRegister(); + MetadataReferral mr = new MetadataReferral(); + mr.setAssocType(assoc1); + mr.setAspects(asSet(aspect1, aspect2)); + mr.setDictionaryService(mockDictionaryService); + mr.validateAndRegister(); } } diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationAdminServiceImplUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralAdminServiceImplUnitTest.java similarity index 60% rename from rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationAdminServiceImplUnitTest.java rename to rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralAdminServiceImplUnitTest.java index 1cd6a81caf..6e31f011df 100644 --- a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/metadatadelegation/DelegationAdminServiceImplUnitTest.java +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferralAdminServiceImplUnitTest.java @@ -16,10 +16,10 @@ * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ -package org.alfresco.module.org_alfresco_module_rm.metadatadelegation; +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; import static java.util.Arrays.asList; -import static org.alfresco.module.org_alfresco_module_rm.metadatadelegation.DelegationException.ChainedDelegationUnsupported; +import static org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.ChainedMetadataReferralUnsupported; import static org.alfresco.module.org_alfresco_module_rm.test.util.ExceptionUtils.expectedException; import static org.alfresco.module.org_alfresco_module_rm.test.util.FPUtils.asSet; import static org.junit.Assert.assertEquals; @@ -40,37 +40,37 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** - * Unit tests for {@link DelegationAdminServiceImpl}. + * Unit tests for {@link ReferralAdminServiceImpl}. * * @author Neil Mc Erlean - * @since 3.0.a + * @since 2.4.a */ -public class DelegationAdminServiceImplUnitTest +public class ReferralAdminServiceImplUnitTest { - @InjectMocks private final DelegationAdminServiceImpl delegationAdminService = new DelegationAdminServiceImpl(); + @InjectMocks private final ReferralAdminServiceImpl referralAdminService = new ReferralAdminServiceImpl(); - @Mock DictionaryService mockDictionaryService; - @Mock NodeService mockNodeService; - @Mock DelegationRegistry mockRegistry; - @Mock DelegationServiceImpl mockDelegationService; + @Mock DictionaryService mockDictionaryService; + @Mock NodeService mockNodeService; + @Mock ReferralRegistry mockRegistry; + @Mock ReferredMetadataServiceImpl mockReferredMetadataService; private final NodeRef node1 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "node1"); private final NodeRef node2 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "node2"); private final NodeRef node3 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "node3"); private final QName assoc1 = QName.createQName("test", "assoc1"); - private final QName assoc2 = QName.createQName("test", "assoc2"); - private final QName aspect1 = QName.createQName("test", "aspect1"); private final QName aspect2 = QName.createQName("test", "aspect2"); + + private final QName assoc2 = QName.createQName("test", "assoc2"); private final QName aspect3 = QName.createQName("test", "aspect3"); - private final Delegation delegate1 = new Delegation() + private final MetadataReferral referral1 = new MetadataReferral() {{ this.setAssocType(assoc1); this.setAspects(asSet(aspect1, aspect2)); }}; - private final Delegation delegate2 = new Delegation() + private final MetadataReferral referral2 = new MetadataReferral() {{ this.setAssocType(assoc2); this.setAspects(asSet(aspect3)); @@ -80,61 +80,61 @@ public class DelegationAdminServiceImplUnitTest { MockitoAnnotations.initMocks(this); - when(mockRegistry.getDelegations()).thenReturn(asSet(delegate1, delegate2)); + when(mockRegistry.getMetadataReferrals()).thenReturn(asSet(referral1, referral2)); } @Test(expected=IllegalArgumentException.class) - public void attachingDelegateWithNoAssociationConfiguredShouldFail() + public void attachingReferrerWithNoAssociationConfiguredShouldFail() { - delegationAdminService.attachDelegate(node1, node2, assoc1); + referralAdminService.attachReferrer(node2, node1, assoc1); } @Test public void attachDetach() { - when(mockRegistry.getDelegateForAssociation(assoc1)).thenReturn(delegate1); + when(mockRegistry.getReferralForAssociation(assoc1)).thenReturn(referral1); // attach - Delegation d = attachDelegate(node1, node2, assoc1); + MetadataReferral d = attachReferrer(node1, node2, assoc1); // validate assertEquals(assoc1, d.getAssocType()); assertEquals(asSet(aspect1, aspect2), d.getAspects()); - assertTrue(mockDelegationService.hasDelegateForAspect(node1, aspect1)); - assertFalse(mockDelegationService.hasDelegateForAspect(node1, aspect3)); + assertTrue(mockReferredMetadataService.isReferringMetadata(node1, aspect1)); + assertFalse(mockReferredMetadataService.isReferringMetadata(node1, aspect3)); // detach - assertEquals(d, delegationAdminService.detachDelegate(node1, assoc1)); + assertEquals(d, referralAdminService.detachReferrer(node1, assoc1)); } - private Delegation attachDelegate(NodeRef from, NodeRef to, QName assocType) + private MetadataReferral attachReferrer(NodeRef referrer, NodeRef referent, QName assocType) { - Delegation d = delegationAdminService.attachDelegate(from, to, assocType); - when(mockNodeService.getSourceAssocs(to, assocType)).thenReturn(asList(new AssociationRef(from, assocType, to))); - when(mockNodeService.getTargetAssocs(from, assocType)).thenReturn(asList(new AssociationRef(from, assocType, to))); + MetadataReferral d = referralAdminService.attachReferrer(referrer, referent, assocType); + when(mockNodeService.getSourceAssocs(referent, assocType)).thenReturn(asList(new AssociationRef(referrer, assocType, referent))); + when(mockNodeService.getTargetAssocs(referrer, assocType)).thenReturn(asList(new AssociationRef(referrer, assocType, referent))); for (QName aspect : d.getAspects()) { - when(mockDelegationService.hasDelegateForAspect(from, aspect)).thenReturn(true); + when(mockReferredMetadataService.isReferringMetadata(referrer, aspect)).thenReturn(true); } return d; } @Test public void chainsOfDelegationShouldBePrevented() { - when(mockRegistry.getDelegateForAssociation(assoc1)).thenReturn(delegate1); + when(mockRegistry.getReferralForAssociation(assoc1)).thenReturn(referral1); // The node already has a delegation in place: node1 -> node2. We're trying to add to the // end of the chain: node2 -> node3 when(mockNodeService.getSourceAssocs(node2, assoc1)).thenReturn(asList(new AssociationRef(node1, assoc1, node2))); when(mockNodeService.getTargetAssocs(node1, assoc1)).thenReturn(asList(new AssociationRef(node1, assoc1, node2))); - expectedException(ChainedDelegationUnsupported.class, () -> { - delegationAdminService.attachDelegate(node2, node3, assoc1); + expectedException(ChainedMetadataReferralUnsupported.class, () -> { + referralAdminService.attachReferrer(node2, node3, assoc1); return null; }); // Now try to add to the start of the chain: node3 -> node1 - expectedException(ChainedDelegationUnsupported.class, () -> { - delegationAdminService.attachDelegate(node3, node1, assoc1); + expectedException(ChainedMetadataReferralUnsupported.class, () -> { + referralAdminService.attachReferrer(node3, node1, assoc1); return null; }); } diff --git a/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataServiceImplUnitTest.java b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataServiceImplUnitTest.java new file mode 100644 index 0000000000..e04a96d087 --- /dev/null +++ b/rm-server/unit-test/java/org/alfresco/module/org_alfresco_module_rm/referredmetadata/ReferredMetadataServiceImplUnitTest.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2005-2015 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * 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 . + */ +package org.alfresco.module.org_alfresco_module_rm.referredmetadata; + +import static java.util.Collections.emptyMap; +import static java.util.Arrays.asList; +import static org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.ReferentNodeNotFound; +import static org.alfresco.module.org_alfresco_module_rm.referredmetadata.ReferredMetadataException.MetadataReferralNotFound; +import static org.alfresco.module.org_alfresco_module_rm.test.util.ExceptionUtils.expectedException; +import static org.alfresco.module.org_alfresco_module_rm.test.util.FPUtils.asSet; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.when; + +import org.alfresco.service.cmr.dictionary.ClassDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.QName; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * Unit tests for {@link ReferredMetadataServiceImpl}. + * + * @author Neil Mc Erlean + * @since 3.0.a + */ +public class ReferredMetadataServiceImplUnitTest +{ + @InjectMocks private final ReferredMetadataServiceImpl referredMetadataService = new ReferredMetadataServiceImpl(); + + @Mock DictionaryService mockDictionaryService; + @Mock NodeService mockNodeService; + @Mock ReferralAdminServiceImpl mockReferralAdminService; + + /** This node has a referent node. */ + private final NodeRef referringNode = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "referringNode"); + /** This is the referent for {@link #referringNode}. */ + private final NodeRef referentNode = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "referentNode"); + /** This node has no referent node. */ + private final NodeRef nodeWithoutReferent = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "nodeWithoutReferent"); + + /** The type of the peer association that links the referringNode to its source. */ + private final QName referralAssocType = QName.createQName("test", "referralAssocType"); + /** The instance of the association between {@link #referringNode} and {@link #referentNode}. */ + private final AssociationRef attachedReferralAssocRef = new AssociationRef(referringNode, referralAssocType, referentNode); + + /** Name of an aspect that has been referred. */ + private final QName referredAspect1 = QName.createQName("test", "referredAspect1"); + /** Name of an aspect that has been referred. */ + private final QName referredAspect2 = QName.createQName("test", "referredAspect2"); + /** Name of a content class (a type in this case) that has not been referred. + * N.B. Types can't be referred currently. */ + private final QName unreferredType = QName.createQName("test", "unreferredType"); + + private final QName referredProp = QName.createQName("test", "referredProp"); + private final Serializable referredPropValue = "hello"; + private final QName unreferredProp = QName.createQName("test", "unreferredProp"); + + private final MetadataReferral referral = new MetadataReferral() + {{ + this.setAssocType(referralAssocType); + this.setAspects(asSet(referredAspect1, referredAspect2)); + }}; + + @Before public void setUp() + { + MockitoAnnotations.initMocks(this); + + final PropertyDefinition aspectProp = mock(PropertyDefinition.class); + final ClassDefinition aspectDefn = mock(ClassDefinition.class); + when(aspectDefn.getName()).thenReturn(referredAspect1); + when(aspectProp.getContainerClass()).thenReturn(aspectDefn); + when(aspectDefn.isAspect()).thenReturn(true); + + final PropertyDefinition typeProp = mock(PropertyDefinition.class); + final ClassDefinition typeDefn = mock(ClassDefinition.class); + when(typeDefn.getName()).thenReturn(unreferredType); + when(typeProp.getContainerClass()).thenReturn(typeDefn); + when(typeDefn.isAspect()).thenReturn(false); + + when(mockDictionaryService.getProperty(referredProp)).thenReturn(aspectProp); + + when(mockReferralAdminService.getAttachedReferralsFrom(referringNode)).thenReturn(asSet(referral)); + for (QName referredAspect : asSet(referredAspect1, referredAspect2)) + { + when(mockReferralAdminService.getReferralFor(referredAspect)).thenReturn(referral); + when(mockNodeService.hasAspect(referentNode, referredAspect)).thenReturn(true); + } + when(mockNodeService.getSourceAssocs(referentNode, referralAssocType)).thenReturn(asList(attachedReferralAssocRef)); + when(mockNodeService.getTargetAssocs(referringNode, referralAssocType)).thenReturn(asList(attachedReferralAssocRef)); + when(mockNodeService.exists(any(NodeRef.class))).thenReturn(true); + when(mockNodeService.getProperties(referentNode)) + .thenReturn(new HashMap() + {{ + this.put(referredProp, referredPropValue); + }}); + } + + @Test public void isReferringMetadata() + { + assertTrue(referredMetadataService.isReferringMetadata(referringNode, referredAspect1)); + expectedException(MetadataReferralNotFound.class, + () -> referredMetadataService.isReferringMetadata(nodeWithoutReferent, unreferredType)); + assertFalse(referredMetadataService.isReferringMetadata(nodeWithoutReferent, referredAspect1)); + } + + @Test public void getReferentNode() + { + assertEquals(referentNode, referredMetadataService.getReferentNode(referringNode, referredAspect1)); + expectedException(MetadataReferralNotFound.class, + () -> { + referredMetadataService.getReferentNode(referringNode, unreferredType); + return null; + }); + assertNull(referredMetadataService.getReferentNode(nodeWithoutReferent, referredAspect1)); + } + + @Test public void getReferredProperties() + { + final Map expectedProps = new HashMap<>(); + expectedProps.put(referredProp, referredPropValue); + + assertEquals(expectedProps, referredMetadataService.getReferredProperties(referringNode, referredAspect1)); + + expectedException(MetadataReferralNotFound.class, + () -> referredMetadataService.getReferredProperties(referringNode, unreferredType)); + + expectedException(ReferentNodeNotFound.class, + () -> referredMetadataService.getReferredProperties(nodeWithoutReferent, referredAspect1)); + } + + @Test public void getReferredProperty() + { + assertEquals(referredPropValue, referredMetadataService.getReferredProperty(referringNode, referredProp)); + + expectedException(IllegalArgumentException.class, + () -> referredMetadataService.getReferredProperty(referringNode, unreferredProp)); + + expectedException(MetadataReferralNotFound.class, + () -> referredMetadataService.getReferredProperties(nodeWithoutReferent, referredProp)); + } + + @Test public void hasReferredAspect() + { + assertTrue(referredMetadataService.hasReferredAspect(referringNode, referredAspect1)); + + expectedException(MetadataReferralNotFound.class, + () -> referredMetadataService.hasReferredAspect(referringNode, unreferredType)); + + expectedException(ReferentNodeNotFound.class, + () -> referredMetadataService.hasReferredAspect(nodeWithoutReferent, referredAspect1)); + } + + @Test public void getAttachedReferrals() + { + final Map expectedReferrals = new HashMap<>(); + expectedReferrals.put(referral, referentNode); + + assertEquals(expectedReferrals, referredMetadataService.getAttachedReferrals(referringNode)); + assertEquals(emptyMap(), referredMetadataService.getAttachedReferrals(nodeWithoutReferent)); + } +}