/* * Copyright (C) 2005-2010 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.repo.copy; import java.io.Serializable; import java.util.Map; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; import org.alfresco.util.Pair; /** * A callback to modify copy behaviour associated with a given type or aspect. This * callback is called per type and per aspect. * * @author Derek Hulley * @since 3.2 */ public interface CopyBehaviourCallback { /** * Description of how the copy process should handle multiplicity of peer associations * at the source end of the association.
* The order of this enum denotes the priority when mixing behaviour as well; * that is to say that a 'ignore' behaviour will occur even if an 'copy' is * also provided by the registered behaviour callbacks. * * @author Derek Hulley * @since 3.3SP3 */ public enum AssocCopySourceAction implements Comparable { /** * Always copy the association. *
* Note that this can cause duplicate associations when copying over * {@link CopyAssociationDetails#isTargetNodeIsNew() existing target nodes}. */ COPY, /** * Always copy the association but remove the copy-target's matching associations * when copying over an existing node. *
* This is akin to the original CopyService behaviour * (see ALF-958). */ COPY_REMOVE_EXISTING, /** * Ignore the association */ IGNORE, } /** * Description of how the copy process should handle multiplicity of peer associations * at the target end of the association.
* The order of this enum denotes the priority when mixing behaviour as well; * that is to say that a 'ignore' behaviour will occur even if an 'copy' is * also provided by the registered behaviour callbacks. * * @author Derek Hulley * @since 3.3SP3 */ public enum AssocCopyTargetAction implements Comparable { /** * The copied association will use, as target, the original association's target * i.e. the target of the association will remain as it was. */ USE_ORIGINAL_TARGET, /** * The copied association will use, as target, the node copied from the * original target; if the original association's target is not copied * in the process, then nothing is done. */ USE_COPIED_TARGET, /** * The copied association will use, as target, the node copied from the * original target; if the original association's target is not copied * in the original target is used. */ USE_COPIED_OTHERWISE_ORIGINAL_TARGET, } /** * Description of how the copy process should traverse a child association. * The order of this enum denotes the priority when mixing behaviour as well; * that is to say that a 'forced recursion' will occur even if an 'ignore' is * also provided by the registered behaviour callbacks. * * @author Derek Hulley * @since 3.2 */ public enum ChildAssocCopyAction implements Comparable { /** * Ignore the child association */ IGNORE, /** * Copy the association only, keeping the existing child node */ COPY_ASSOC, /** * Traverse the child association and copy the child node */ COPY_CHILD, } /** * Description of how the copy process should behave when copying an association. * * @author Derek Hulley * @since 3.2 */ public enum ChildAssocRecurseAction implements Comparable { /** * Respect the client's recursion decision */ RESPECT_RECURSE_FLAG, /** * Force all further copies of the source hierarchy to recurse into children. * This allows behaviour to force a copy of a subtree that it expects to * exist. *

* NOTE: Any part of the source subtree can still terminate the recursion, * so this is mainly useful where the subtree contains the default * behaviour. */ FORCE_RECURSE, } /** * A simple bean class to convey information to the callback methods dealing with * copying of associations. * * @see CopyBehaviourCallback#getAssociationCopyAction(QName, CopyDetails, CopyAssociationDetails) * * @author Derek Hulley * @since 3.3SP3 */ public static final class CopyAssociationDetails { private final AssociationRef assocRef; private final NodeRef copyTarget; private final boolean copyTargetIsNew; public CopyAssociationDetails( AssociationRef assocRef, NodeRef copyTarget, boolean copyTargetIsNew) { this.assocRef = assocRef; this.copyTarget = copyTarget; this.copyTargetIsNew = copyTargetIsNew; } @Override public String toString() { StringBuilder sb = new StringBuilder(256); sb.append("CopyChildAssociationDetails ") .append("[ assocRef=").append(assocRef) .append(", copyTarget=").append(copyTarget) .append(", copyTargetIsNew=").append(copyTargetIsNew) .append("]"); return sb.toString(); } /** * @return Returns the association being examined */ public final AssociationRef getAssocRef() { return assocRef; } /** * @return Returns the node that will be the * new source if the association is copied */ public final NodeRef getCopyTarget() { return copyTarget; } /** * * @return Returns true if the {@link #getCopyTarget() copy target node} * has been newly created by the copy process or false if it * is a node that existed prior to the copy */ public final boolean getCopyTargetIsNew() { return copyTargetIsNew; } } /** * A simple bean class to convey information to the callback methods dealing with * copying of child associations. * * @see CopyBehaviourCallback#getChildAssociationCopyAction(QName, CopyDetails, CopyChildAssociationDetails) * @see CopyBehaviourCallback#getChildAssociationRecurseAction(QName, CopyDetails, CopyChildAssociationDetails) * * @author Derek Hulley * @since 3.2 */ public static final class CopyChildAssociationDetails { private final ChildAssociationRef childAssocRef; private final NodeRef copyTarget; private final boolean copyTargetIsNew; private final boolean copyChildren; public CopyChildAssociationDetails( ChildAssociationRef childAssocRef, NodeRef copyTarget, boolean copyTargetIsNew, boolean copyChildren) { this.childAssocRef = childAssocRef; this.copyTarget = copyTarget; this.copyTargetIsNew = copyTargetIsNew; this.copyChildren = copyChildren; } @Override public String toString() { StringBuilder sb = new StringBuilder(256); sb.append("CopyChildAssociationDetails ") .append("[ childAssocRef=").append(childAssocRef) .append(", copyTarget=").append(copyTarget) .append(", copyTargetIsNew=").append(copyTargetIsNew) .append(", copyChildren=").append(copyChildren) .append("]"); return sb.toString(); } /** * @return Returns the association being examined */ public final ChildAssociationRef getChildAssocRef() { return childAssocRef; } /** * @return Returns the node that will be the * new parent if the association is copied */ public final NodeRef getCopyTarget() { return copyTarget; } /** * * @return Returns true if the {@link #getCopyTarget() target node} * has been newly created by the copy process or false if it * is a node that existed prior to the copy */ public final boolean getCopyTargetIsNew() { return copyTargetIsNew; } /** * Get the current recursion behaviour. This can be ignored and even altered, if required. * * @return Returns true if the copy process is currently recursing to * child associations or false if not. */ public final boolean isCopyChildren() { return copyChildren; } } /** * Determine if this type or aspect must be copied. If the callback is for a type * (not aspect) then this determines if the node is copied at all. If the callback * is for an aspect, then this determines if the aspect is copied. * * @param classQName the name of the class that this is being invoked for * @param copyDetails the source node's copy details for quick reference * @return true if the type or aspect that this behaviour * represents must be copied. */ boolean getMustCopy(QName classQName, CopyDetails copyDetails); /** * Determine if this top-level node with type or aspect can be renamed during copy. * * @param classQName the name of the class that this is being invoked for * @param copyDetails the source node's copy details for quick reference * @return true if the top-level node with type or aspect * can be renamed during copy. */ boolean isTopLevelCanBeRenamed(QName classQName, CopyDetails copyDetails); /** * Determine the copy behaviour associated with a given peer association. * * @param classQName the name of the class that this is being invoked for * @param copyDetails the source node's copy details for quick reference * @param assocCopyDetails all other details relating to the association * @return Returns the copy actions * ({@link AssocCopySourceAction source} and {@link AssocCopySourceAction target}) * to take with the given association */ Pair getAssociationCopyAction( QName classQName, CopyDetails copyDetails, CopyAssociationDetails assocCopyDetails); /** * Determine if a copy should copy the child, the association only or do nothing with * the given association. *

* This is called regardless of whether 'cascade' copy has been selected by the client * of the copy. Some type and aspect behaviour will mandate a copy of the child * associations regardless of whether recursion is on. * * @param classQName the name of the class that this is being invoked for * @param copyDetails the source node's copy details for quick reference * @param childAssocCopyDetails all other details relating to the child association * @return Returns the copy {@link ChildAssocCopyAction action} to take * with the given child association */ ChildAssocCopyAction getChildAssociationCopyAction( QName classQName, CopyDetails copyDetails, CopyChildAssociationDetails childAssocCopyDetails); /** * Once the child association copy action has been chosen, the policy callback can * dictate whether or not to force further recursion. This cannot prevent * behaviour further down the hierarchy from stopping the copy. * * @param classQName the name of the class that this is being invoked for * @param copyDetails the source node's copy details for quick reference * @param childAssocCopyDetails all other details relating to the child association * @return Returns the type of {@link ChildAssocRecurseAction recursion} * to perform after having copied the child association * * @see #getChildAssociationCopyAction(QName, CopyDetails, ChildAssociationRef, boolean) */ ChildAssocRecurseAction getChildAssociationRecurseAction( QName classQName, CopyDetails copyDetails, CopyChildAssociationDetails childAssocCopyDetails); /** * Modify the properties that are copied across. * * @param classQName the name of the class that this is being invoked for * @param copyDetails the source node's copy details for quick reference * @param properties the type- or aspect-specific properties that can be copied. * The map can be manipulated and returned as required. * @return Returns the type or aspect properties that should be copied. */ Map getCopyProperties( QName classQName, CopyDetails copyDetails, Map properties); }