KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > repo > copy > CopyServiceImpl


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.repo.copy;
18
19 import java.io.Serializable JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Set JavaDoc;
25
26 import org.alfresco.model.ContentModel;
27 import org.alfresco.repo.policy.ClassPolicyDelegate;
28 import org.alfresco.repo.policy.JavaBehaviour;
29 import org.alfresco.repo.policy.PolicyComponent;
30 import org.alfresco.repo.policy.PolicyScope;
31 import org.alfresco.service.cmr.dictionary.AspectDefinition;
32 import org.alfresco.service.cmr.dictionary.AssociationDefinition;
33 import org.alfresco.service.cmr.dictionary.ClassDefinition;
34 import org.alfresco.service.cmr.dictionary.DictionaryService;
35 import org.alfresco.service.cmr.dictionary.InvalidTypeException;
36 import org.alfresco.service.cmr.dictionary.PropertyDefinition;
37 import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
38 import org.alfresco.service.cmr.dictionary.TypeDefinition;
39 import org.alfresco.service.cmr.repository.AssociationRef;
40 import org.alfresco.service.cmr.repository.ChildAssociationRef;
41 import org.alfresco.service.cmr.repository.CopyService;
42 import org.alfresco.service.cmr.repository.CopyServiceException;
43 import org.alfresco.service.cmr.repository.NodeRef;
44 import org.alfresco.service.cmr.repository.NodeService;
45 import org.alfresco.service.cmr.repository.StoreRef;
46 import org.alfresco.service.cmr.rule.RuleService;
47 import org.alfresco.service.namespace.NamespaceService;
48 import org.alfresco.service.namespace.QName;
49 import org.alfresco.service.namespace.RegexQNamePattern;
50 import org.alfresco.util.ParameterCheck;
51
52 /**
53  * Node operations service implmentation.
54  *
55  * @author Roy Wetherall
56  */

57 public class CopyServiceImpl implements CopyService
58 {
59     /**
60      * The node service
61      */

62     private NodeService nodeService;
63     
64     /**
65      * The dictionary service
66      */

67     private DictionaryService dictionaryService;
68     
69     /**
70      * Policy component
71      */

72     private PolicyComponent policyComponent;
73     
74     /**
75      * Rule service
76      */

77     private RuleService ruleService;
78
79     /**
80      * Policy delegates
81      */

82     private ClassPolicyDelegate<CopyServicePolicies.OnCopyNodePolicy> onCopyNodeDelegate;
83     private ClassPolicyDelegate<CopyServicePolicies.OnCopyCompletePolicy> onCopyCompleteDelegate;
84     
85     /**
86      * Set the node service
87      *
88      * @param nodeService the node service
89      */

90     public void setNodeService(NodeService nodeService)
91     {
92         this.nodeService = nodeService;
93     }
94     
95     /**
96      * Sets the dictionary service
97      *
98      * @param dictionaryService the dictionary service
99      */

100     public void setDictionaryService(DictionaryService dictionaryService)
101     {
102         this.dictionaryService = dictionaryService;
103     }
104     
105     /**
106      * Sets the policy component
107      *
108      * @param policyComponent the policy component
109      */

110     public void setPolicyComponent(PolicyComponent policyComponent)
111     {
112         this.policyComponent = policyComponent;
113     }
114     
115     /**
116      * Set the rule service
117      *
118      * @param ruleService the rule service
119      */

120     public void setRuleService(RuleService ruleService)
121     {
122         this.ruleService = ruleService;
123     }
124     
125     /**
126      * Initialise method
127      */

128     public void init()
129     {
130         // Register the policies
131
this.onCopyNodeDelegate = this.policyComponent.registerClassPolicy(CopyServicePolicies.OnCopyNodePolicy.class);
132         this.onCopyCompleteDelegate = this.policyComponent.registerClassPolicy(CopyServicePolicies.OnCopyCompletePolicy.class);
133         
134         // Register policy behaviours
135
this.policyComponent.bindClassBehaviour(
136                 QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyNode"),
137                 ContentModel.ASPECT_COPIEDFROM,
138                 new JavaBehaviour(this, "copyAspectOnCopy"));
139         this.policyComponent.bindClassBehaviour(
140                 QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyNode"),
141                 ContentModel.ASPECT_OWNABLE,
142                 new JavaBehaviour(this, "onCopyOwnable"));
143         this.policyComponent.bindClassBehaviour(
144                 QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyNode"),
145                 ContentModel.ASPECT_AUTHOR,
146                 new JavaBehaviour(this, "onCopyAuthor"));
147         this.policyComponent.bindClassBehaviour(
148                 QName.createQName(NamespaceService.ALFRESCO_URI, "onCopyComplete"),
149                 ContentModel.ASPECT_COPIEDFROM,
150                 new JavaBehaviour(this, "onCopyComplete"));
151     }
152     
153     /**
154      * @see com.activiti.repo.node.copy.NodeCopyService#copy(com.activiti.repo.ref.NodeRef, com.activiti.repo.ref.NodeRef, com.activiti.repo.ref.QName, QName, boolean)
155      */

156     public NodeRef copy(
157             NodeRef sourceNodeRef,
158             NodeRef destinationParent,
159             QName destinationAssocTypeQName,
160             QName destinationQName,
161             boolean copyChildren)
162     {
163         // Check that all the passed values are not null
164
ParameterCheck.mandatory("Source Node", sourceNodeRef);
165         ParameterCheck.mandatory("Destination Parent", destinationParent);
166         ParameterCheck.mandatory("Destination Association Name", destinationQName);
167
168         if (sourceNodeRef.getStoreRef().equals(destinationParent.getStoreRef()) == false)
169         {
170             // TODO We need to create a new node in the other store with the same id as the source
171

172             // Error - since at the moment we do not support cross store copying
173
throw new UnsupportedOperationException JavaDoc("Copying nodes across stores is not currently supported.");
174         }
175
176         // Recursively copy node
177
Map JavaDoc<NodeRef, NodeRef> copiedChildren = new HashMap JavaDoc<NodeRef, NodeRef>();
178         NodeRef copy = recursiveCopy(sourceNodeRef, destinationParent, destinationAssocTypeQName, destinationQName, copyChildren, copiedChildren);
179         
180         // Foreach of the newly created copies call the copy complete policy
181
for (Map.Entry JavaDoc<NodeRef, NodeRef> entry : copiedChildren.entrySet())
182         {
183             invokeCopyComplete(entry.getKey(), entry.getValue(), true, copiedChildren);
184         }
185         
186         return copy;
187     }
188     
189     /**
190      * Invokes the copy complete policy for the node reference provided
191      *
192      * @param sourceNodeRef the source node reference
193      * @param destinationNodeRef the destination node reference
194      * @param copiedNodeRefs the map of copied node references
195      */

196     private void invokeCopyComplete(
197             NodeRef sourceNodeRef,
198             NodeRef destinationNodeRef,
199             boolean copyToNewNode,
200             Map JavaDoc<NodeRef, NodeRef> copiedNodeRefs)
201     {
202         QName sourceClassRef = this.nodeService.getType(sourceNodeRef);
203         invokeCopyComplete(sourceClassRef, sourceNodeRef, destinationNodeRef, copyToNewNode, copiedNodeRefs);
204         
205         // Get the source aspects
206
Set JavaDoc<QName> sourceAspects = this.nodeService.getAspects(sourceNodeRef);
207         for (QName sourceAspect : sourceAspects)
208         {
209             invokeCopyComplete(sourceAspect, sourceNodeRef, destinationNodeRef, copyToNewNode, copiedNodeRefs);
210         }
211     }
212
213     /**
214      *
215      * @param typeQName
216      * @param sourceNodeRef
217      * @param destinationNodeRef
218      * @param copiedNodeRefs
219      */

220     private void invokeCopyComplete(
221             QName typeQName,
222             NodeRef sourceNodeRef,
223             NodeRef destinationNodeRef,
224             boolean copyToNewNode,
225             Map JavaDoc<NodeRef, NodeRef> copiedNodeRefs)
226     {
227         Collection JavaDoc<CopyServicePolicies.OnCopyCompletePolicy> policies = this.onCopyCompleteDelegate.getList(typeQName);
228         if (policies.isEmpty() == true)
229         {
230             defaultOnCopyComplete(typeQName, sourceNodeRef, destinationNodeRef, copiedNodeRefs);
231         }
232         else
233         {
234             for (CopyServicePolicies.OnCopyCompletePolicy policy : policies)
235             {
236                 policy.onCopyComplete(typeQName, sourceNodeRef, destinationNodeRef, copyToNewNode, copiedNodeRefs);
237             }
238         }
239     }
240
241     /**
242      *
243      * @param typeQName
244      * @param sourceNodeRef
245      * @param destinationNodeRef
246      * @param copiedNodeRefs
247      */

248     private void defaultOnCopyComplete(
249             QName typeQName,
250             NodeRef sourceNodeRef,
251             NodeRef destinationNodeRef,
252             Map JavaDoc<NodeRef, NodeRef> copiedNodeRefs)
253     {
254         ClassDefinition classDefinition = this.dictionaryService.getClass(typeQName);
255         if (classDefinition != null)
256         {
257              // Check the properties
258
Map JavaDoc<QName,PropertyDefinition> propertyDefinitions = classDefinition.getProperties();
259             for (Map.Entry JavaDoc<QName,PropertyDefinition> entry : propertyDefinitions.entrySet())
260             {
261                 QName propertyTypeDefinition = entry.getValue().getDataType().getName();
262                 if (DataTypeDefinition.NODE_REF.equals(propertyTypeDefinition) == true ||
263                     DataTypeDefinition.ANY.equals(propertyTypeDefinition) == true)
264                 {
265                     // Re-set the node ref so that it is still relative (if appropriate)
266
Serializable JavaDoc value = this.nodeService.getProperty(destinationNodeRef, entry.getKey());
267                     if (value != null && value instanceof NodeRef)
268                     {
269                         NodeRef nodeRef = (NodeRef)value;
270                         if (copiedNodeRefs.containsKey(nodeRef) == true)
271                         {
272                             NodeRef copiedNodeRef = copiedNodeRefs.get(nodeRef);
273                             this.nodeService.setProperty(destinationNodeRef, entry.getKey(), copiedNodeRef);
274                         }
275                     }
276                 }
277             }
278
279             // Copy the associations (child and target)
280
Map JavaDoc<QName, AssociationDefinition> assocDefs = classDefinition.getAssociations();
281
282             // TODO: Need way of getting child assocs of a given type
283
List JavaDoc<ChildAssociationRef> childAssocRefs = this.nodeService.getChildAssocs(destinationNodeRef);
284             for (ChildAssociationRef childAssocRef : childAssocRefs)
285             {
286                 if (assocDefs.containsKey(childAssocRef.getTypeQName()) &&
287                     childAssocRef.isPrimary() == false &&
288                     copiedNodeRefs.containsKey(childAssocRef.getChildRef()) == true)
289                 {
290                     // Remove the assoc and re-point to the new node
291
this.nodeService.removeChild(destinationNodeRef, childAssocRef.getChildRef());
292                     this.nodeService.addChild(
293                             destinationNodeRef,
294                             copiedNodeRefs.get(childAssocRef.getChildRef()) ,
295                             childAssocRef.getTypeQName(),
296                             childAssocRef.getQName());
297                 }
298             }
299             
300             // TODO: Need way of getting assocs of a given type
301
List JavaDoc<AssociationRef> nodeAssocRefs = this.nodeService.getTargetAssocs(destinationNodeRef, RegexQNamePattern.MATCH_ALL);
302             for (AssociationRef nodeAssocRef : nodeAssocRefs)
303             {
304                 if (assocDefs.containsKey(nodeAssocRef.getTypeQName()) &&
305                     copiedNodeRefs.containsKey(nodeAssocRef.getTargetRef()) == true)
306                 {
307                     // Remove the assoc and re-point to the new node
308
this.nodeService.removeAssociation(
309                             destinationNodeRef,
310                             nodeAssocRef.getTargetRef(),
311                             nodeAssocRef.getTypeQName());
312                     this.nodeService.createAssociation(
313                             destinationNodeRef,
314                             copiedNodeRefs.get(nodeAssocRef.getTargetRef()),
315                             nodeAssocRef.getTypeQName());
316                 }
317             }
318         }
319         
320     }
321
322     /**
323      * Recursive copy algorithm
324      *
325      * @param sourceNodeRef
326      * @param destinationParent
327      * @param destinationAssocTypeQName
328      * @param destinationQName
329      * @param copyChildren
330      * @param copiedChildren
331      * @return
332      */

333     private NodeRef recursiveCopy(
334               NodeRef sourceNodeRef,
335               NodeRef destinationParent,
336               QName destinationAssocTypeQName,
337               QName destinationQName,
338               boolean copyChildren,
339               Map JavaDoc<NodeRef, NodeRef> copiedChildren)
340     {
341         // Extract Type Definition
342
QName sourceTypeRef = this.nodeService.getType(sourceNodeRef);
343         TypeDefinition typeDef = dictionaryService.getType(sourceTypeRef);
344         if (typeDef == null)
345         {
346             throw new InvalidTypeException(sourceTypeRef);
347         }
348         
349         // Establish the scope of the copy
350
PolicyScope copyDetails = getCopyDetails(sourceNodeRef, destinationParent.getStoreRef(), true);
351         
352         // Create collection of properties for type and mandatory aspects
353
Map JavaDoc<QName, Serializable JavaDoc> typeProps = copyDetails.getProperties();
354         Map JavaDoc<QName, Serializable JavaDoc> properties = new HashMap JavaDoc<QName, Serializable JavaDoc>();
355         if (typeProps != null)
356         {
357             properties.putAll(typeProps);
358         }
359         for (AspectDefinition aspectDef : typeDef.getDefaultAspects())
360         {
361             Map JavaDoc<QName, Serializable JavaDoc> aspectProps = copyDetails.getProperties(aspectDef.getName());
362             if (aspectProps != null)
363             {
364                 properties.putAll(aspectProps);
365             }
366         }
367         
368         // Create the new node
369
ChildAssociationRef destinationChildAssocRef = this.nodeService.createNode(
370                 destinationParent,
371                 destinationAssocTypeQName,
372                 destinationQName,
373                 sourceTypeRef,
374                 properties);
375         NodeRef destinationNodeRef = destinationChildAssocRef.getChildRef();
376         copiedChildren.put(sourceNodeRef, destinationNodeRef);
377         
378         // Prevent any rules being fired on the new destination node
379
this.ruleService.disableRules(destinationNodeRef);
380         try
381         {
382             // Apply the copy aspect to the new node
383
Map JavaDoc<QName, Serializable JavaDoc> copyProperties = new HashMap JavaDoc<QName, Serializable JavaDoc>();
384             copyProperties.put(ContentModel.PROP_COPY_REFERENCE, sourceNodeRef);
385             this.nodeService.addAspect(destinationNodeRef, ContentModel.ASPECT_COPIEDFROM, copyProperties);
386             
387             // Copy the aspects
388
copyAspects(destinationNodeRef, copyDetails);
389             
390             // Copy the associations
391
copyAssociations(destinationNodeRef, copyDetails, copyChildren, copiedChildren);
392         }
393         finally
394         {
395             this.ruleService.enableRules(destinationNodeRef);
396         }
397         
398         return destinationNodeRef;
399     }
400     
401     /**
402      * Gets the copy details. This calls the appropriate policies that have been registered
403      * against the node and aspect types in order to pick-up any type specific copy behaviour.
404      * <p>
405      * If no policies for a type are registered then the default copy takes place which will
406      * copy all properties and associations in the ususal manner.
407      *
408      * @param sourceNodeRef the source node reference
409      * @return the copy details
410      */

411     private PolicyScope getCopyDetails(NodeRef sourceNodeRef, StoreRef destinationStoreRef, boolean copyToNewNode)
412     {
413         QName sourceClassRef = this.nodeService.getType(sourceNodeRef);
414         PolicyScope copyDetails = new PolicyScope(sourceClassRef);
415         
416         // Invoke the onCopy behaviour
417
invokeOnCopy(sourceClassRef, sourceNodeRef, destinationStoreRef, copyToNewNode, copyDetails);
418         
419         // TODO What do we do aboout props and assocs that are on the node node but not part of the type definition?
420

421         // Get the source aspects
422
Set JavaDoc<QName> sourceAspects = this.nodeService.getAspects(sourceNodeRef);
423         for (QName sourceAspect : sourceAspects)
424         {
425             // Invoke the onCopy behaviour
426
invokeOnCopy(sourceAspect, sourceNodeRef, destinationStoreRef, copyToNewNode, copyDetails);
427         }
428         
429         return copyDetails;
430     }
431     
432     /**
433      * Invoke the correct onCopy behaviour
434      *
435      * @param sourceClassRef source class reference
436      * @param sourceNodeRef source node reference
437      * @param copyDetails the copy details
438      */

439     private void invokeOnCopy(
440             QName sourceClassRef,
441             NodeRef sourceNodeRef,
442             StoreRef destinationStoreRef,
443             boolean copyToNewNode,
444             PolicyScope copyDetails)
445     {
446         Collection JavaDoc<CopyServicePolicies.OnCopyNodePolicy> policies = this.onCopyNodeDelegate.getList(sourceClassRef);
447         if (policies.isEmpty() == true)
448         {
449             defaultOnCopy(sourceClassRef, sourceNodeRef, copyDetails);
450         }
451         else
452         {
453             for (CopyServicePolicies.OnCopyNodePolicy policy : policies)
454             {
455                 policy.onCopyNode(sourceClassRef, sourceNodeRef, destinationStoreRef, copyToNewNode, copyDetails);
456             }
457         }
458     }
459     
460     /**
461      * Default implementation of on copy, used when there is no policy specified for a class.
462      *
463      * @param classRef the class reference of the node being copied
464      * @param sourceNodeRef the source node reference
465      * @param copyDetails details of the state being copied
466      */

467     private void defaultOnCopy(QName classRef, NodeRef sourceNodeRef, PolicyScope copyDetails)
468     {
469         ClassDefinition classDefinition = this.dictionaryService.getClass(classRef);
470         if (classDefinition != null)
471         {
472              // Copy the properties
473
Map JavaDoc<QName,PropertyDefinition> propertyDefinitions = classDefinition.getProperties();
474             for (QName propertyName : propertyDefinitions.keySet())
475             {
476                 Serializable JavaDoc propValue = this.nodeService.getProperty(sourceNodeRef, propertyName);
477                 copyDetails.addProperty(classDefinition.getName(), propertyName, propValue);
478             }
479
480             // Copy the associations (child and target)
481
Map JavaDoc<QName, AssociationDefinition> assocDefs = classDefinition.getAssociations();
482
483             // TODO: Need way of getting child assocs of a given type
484
if (classDefinition.isContainer())
485             {
486                 List JavaDoc<ChildAssociationRef> childAssocRefs = this.nodeService.getChildAssocs(sourceNodeRef);
487                 for (ChildAssociationRef childAssocRef : childAssocRefs)
488                 {
489                     if (assocDefs.containsKey(childAssocRef.getTypeQName()))
490                     {
491                         copyDetails.addChildAssociation(classDefinition.getName(), childAssocRef);
492                     }
493                 }
494             }
495             
496             // TODO: Need way of getting assocs of a given type
497
List JavaDoc<AssociationRef> nodeAssocRefs = this.nodeService.getTargetAssocs(sourceNodeRef, RegexQNamePattern.MATCH_ALL);
498             for (AssociationRef nodeAssocRef : nodeAssocRefs)
499             {
500                 if (assocDefs.containsKey(nodeAssocRef.getTypeQName()))
501                 {
502                     copyDetails.addAssociation(classDefinition.getName(), nodeAssocRef);
503                 }
504             }
505         }
506     }
507     
508     /**
509      * Copies the properties for the node type onto the destination node.
510      *
511      * @param destinationNodeRef the destintaion node reference
512      * @param copyDetails the copy details
513      */

514     private void copyProperties(NodeRef destinationNodeRef, PolicyScope copyDetails)
515     {
516         Map JavaDoc<QName, Serializable JavaDoc> props = copyDetails.getProperties();
517         if (props != null)
518         {
519             for (QName propName : props.keySet())
520             {
521                 this.nodeService.setProperty(destinationNodeRef, propName, props.get(propName));
522             }
523         }
524     }
525     
526     /**
527      * Applies the aspects (thus copying the associated properties) onto the destination node
528      *
529      * @param destinationNodeRef the destination node reference
530      * @param copyDetails the copy details
531      */

532     private void copyAspects(NodeRef destinationNodeRef, PolicyScope copyDetails)
533     {
534         Set JavaDoc<QName> apects = copyDetails.getAspects();
535         for (QName aspect : apects)
536         {
537             if (this.nodeService.hasAspect(destinationNodeRef, aspect) == false)
538             {
539                 // Add the aspect to the node
540
this.nodeService.addAspect(
541                         destinationNodeRef,
542                         aspect,
543                         copyDetails.getProperties(aspect));
544             }
545             else
546             {
547                 // Set each property on the destination node since the aspect has already been applied
548
Map JavaDoc<QName, Serializable JavaDoc> aspectProps = copyDetails.getProperties(aspect);
549                 if (aspectProps != null)
550                 {
551                     for (Map.Entry JavaDoc<QName, Serializable JavaDoc> entry : aspectProps.entrySet())
552                     {
553                         this.nodeService.setProperty(destinationNodeRef, entry.getKey(), entry.getValue());
554                     }
555                 }
556             }
557         }
558     }
559     
560     /**
561      * Copies the associations (child and target) for the node type and aspects onto the
562      * destination node.
563      * <p>
564      * If copyChildren is true then all child nodes of primary child associations are copied
565      * before they are associatied with the destination node.
566      *
567      * @param destinationNodeRef the destination node reference
568      * @param copyDetails the copy details
569      * @param copyChildren indicates whether the primary children are copied or not
570      * @param copiedChildren set of children already copied
571      */

572     private void copyAssociations(
573             NodeRef destinationNodeRef,
574             PolicyScope copyDetails,
575             boolean copyChildren,
576             Map JavaDoc<NodeRef, NodeRef> copiedChildren)
577     {
578         QName classRef = this.nodeService.getType(destinationNodeRef);
579         copyChildAssociations(classRef, destinationNodeRef, copyDetails, copyChildren, copiedChildren);
580         copyTargetAssociations(classRef, destinationNodeRef, copyDetails);
581         
582         Set JavaDoc<QName> apects = copyDetails.getAspects();
583         for (QName aspect : apects)
584         {
585             if (this.nodeService.hasAspect(destinationNodeRef, aspect) == false)
586             {
587                 // Error since the aspect has not been added to the destination node (should never happen)
588
throw new CopyServiceException("The aspect has not been added to the destination node.");
589             }
590             
591             copyChildAssociations(aspect, destinationNodeRef, copyDetails, copyChildren, copiedChildren);
592             copyTargetAssociations(aspect, destinationNodeRef, copyDetails);
593         }
594     }
595     
596     /**
597      * Copies the target associations onto the destination node reference.
598      *
599      * @param classRef the class reference
600      * @param destinationNodeRef the destination node reference
601      * @param copyDetails the copy details
602      */

603     private void copyTargetAssociations(QName classRef, NodeRef destinationNodeRef, PolicyScope copyDetails)
604     {
605         List JavaDoc<AssociationRef> nodeAssocRefs = copyDetails.getAssociations(classRef);
606         if (nodeAssocRefs != null)
607         {
608             for (AssociationRef assocRef : nodeAssocRefs)
609             {
610                 NodeRef targetRef = assocRef.getTargetRef();
611                 
612                 boolean exists = false;
613                 for (AssociationRef assocRef2 : this.nodeService.getTargetAssocs(destinationNodeRef, assocRef.getTypeQName()))
614                 {
615                     if (targetRef.equals(assocRef2.getTargetRef()) == true)
616                     {
617                         exists = true;
618                         break;
619                     }
620                 }
621                 
622                 if (exists == false)
623                 {
624                     // Add the association
625
this.nodeService.createAssociation(destinationNodeRef, targetRef, assocRef.getTypeQName());
626                 }
627             }
628         }
629     }
630
631     /**
632      * Copies the child associations onto the destiantion node reference.
633      * <p>
634      * If copyChildren is true then the nodes at the end of a primary assoc will be copied before they
635      * are associated.
636      *
637      * @param classRef the class reference
638      * @param destinationNodeRef the destination node reference
639      * @param copyDetails the copy details
640      * @param copyChildren indicates whether to copy the primary children
641      */

642     private void copyChildAssociations(
643             QName classRef,
644             NodeRef destinationNodeRef,
645             PolicyScope copyDetails,
646             boolean copyChildren,
647             Map JavaDoc<NodeRef, NodeRef> copiedChildren)
648     {
649         List JavaDoc<ChildAssociationRef> childAssocs = copyDetails.getChildAssociations(classRef);
650         if (childAssocs != null)
651         {
652             for (ChildAssociationRef childAssoc : childAssocs)
653             {
654                 if (copyChildren == true)
655                 {
656                     if (childAssoc.isPrimary() == true)
657                     {
658                         // Do not recurse further, if we've already copied this node
659
if (copiedChildren.containsKey(childAssoc.getChildRef()) == false &&
660                             copiedChildren.containsValue(childAssoc.getChildRef()) == false)
661                         {
662                             // Copy the child
663
recursiveCopy(
664                                     childAssoc.getChildRef(),
665                                     destinationNodeRef,
666                                     childAssoc.getTypeQName(),
667                                     childAssoc.getQName(),
668                                     copyChildren,
669                                     copiedChildren);
670                         }
671                     }
672                     else
673                     {
674                         // Add the child
675
NodeRef childRef = childAssoc.getChildRef();
676                         this.nodeService.addChild(destinationNodeRef, childRef, childAssoc.getTypeQName(), childAssoc.getQName());
677                     }
678                 }
679                 else
680                 {
681                     NodeRef childRef = childAssoc.getChildRef();
682                     QName childType = this.nodeService.getType(childRef);
683                     
684                     // TODO will need to remove this reference to the configurations association
685
if (this.dictionaryService.isSubClass(childType, ContentModel.TYPE_CONFIGURATIONS) == true ||
686                         copyDetails.isChildAssociationRefAlwaysTraversed(classRef, childAssoc) == true)
687                     {
688                         if (copiedChildren.containsKey(childRef) == false)
689                         {
690                             // Always recursivly copy configuration folders
691
recursiveCopy(
692                                     childRef,
693                                     destinationNodeRef,
694                                     childAssoc.getTypeQName(),
695                                     childAssoc.getQName(),
696                                     true,
697                                     copiedChildren);
698                         }
699                     }
700                     else
701                     {
702                         // Add the child (will not be primary reguardless of its origional state)
703
this.nodeService.addChild(destinationNodeRef, childRef, childAssoc.getTypeQName(), childAssoc.getQName());
704                     }
705                 }
706             }
707         }
708     }
709
710     /**
711      * Defer to the standard implementation with copyChildren set to false
712      *
713      * @see com.activiti.repo.node.copy.NodeCopyService#copy(com.activiti.repo.ref.NodeRef, com.activiti.repo.ref.NodeRef, com.activiti.repo.ref.QName)
714      */

715     public NodeRef copy(
716             NodeRef sourceNodeRef,
717             NodeRef destinationParent,
718             QName destinationAssocTypeQName,
719             QName destinationQName)
720     {
721         return copy(
722                 sourceNodeRef,
723                 destinationParent,
724                 destinationAssocTypeQName,
725                 destinationQName,
726                 false);
727     }
728
729     /**
730      * @see com.activiti.repo.node.copy.NodeCopyService#copy(com.activiti.repo.ref.NodeRef, com.activiti.repo.ref.NodeRef)
731      */

732     public void copy(
733             NodeRef sourceNodeRef,
734             NodeRef destinationNodeRef)
735     {
736         // Check that the source and destination node are the same type
737
if (this.nodeService.getType(sourceNodeRef).equals(this.nodeService.getType(destinationNodeRef)) == false)
738         {
739             // Error - can not copy objects that are of different types
740
throw new CopyServiceException("The source and destination node must be the same type.");
741         }
742         
743         // Get the copy details
744
PolicyScope copyDetails = getCopyDetails(sourceNodeRef, destinationNodeRef.getStoreRef(), false);
745         
746         // Copy over the top of the destination node
747
copyProperties(destinationNodeRef, copyDetails);
748         copyAspects(destinationNodeRef, copyDetails);
749         copyAssociations(destinationNodeRef, copyDetails, false, new HashMap JavaDoc<NodeRef, NodeRef>());
750         
751         // invoke the copy complete policy
752
Map JavaDoc<NodeRef, NodeRef> copiedNodes = new HashMap JavaDoc<NodeRef, NodeRef>(1);
753         copiedNodes.put(sourceNodeRef, destinationNodeRef);
754         invokeCopyComplete(sourceNodeRef, destinationNodeRef, false, copiedNodes);
755     }
756     
757     /**
758      * OnCopy behaviour registered for the copy aspect.
759      * <p>
760      * Doing nothing in this behaviour ensures that the copy aspect found on the source node does not get
761      * copied onto the destination node.
762      *
763      * @param sourceClassRef the source class reference
764      * @param sourceNodeRef the source node reference
765      * @param copyDetails the copy details
766      */

767     public void copyAspectOnCopy(
768             QName classRef,
769             NodeRef sourceNodeRef,
770             StoreRef destinationStoreRef,
771             boolean copyToNewNode,
772             PolicyScope copyDetails)
773     {
774         // Do nothing. This will ensure that copy aspect on the source node does not get copied onto
775
// the destination node.
776
}
777     
778     public void onCopyOwnable(
779             QName classRef,
780             NodeRef sourceNodeRef,
781             StoreRef destinationStoreRef,
782             boolean copyToNewNode,
783             PolicyScope copyDetails)
784     {
785         // Do nothing since the ownable aspect should not be copied
786
}
787     
788     public void onCopyAuthor(
789             QName classRef,
790             NodeRef sourceNodeRef,
791             StoreRef destinationStoreRef,
792             boolean copyToNewNode,
793             PolicyScope copyDetails)
794     {
795         // Do nothing since the author aspect should not be copied
796
}
797     
798     public void onCopyComplete(
799             QName classRef,
800             NodeRef sourceNodeRef,
801             NodeRef destinationRef,
802             boolean copyToNew,
803             Map JavaDoc<NodeRef, NodeRef> copyMap)
804     {
805         // Do nothing since we do not want the copy from aspect to be relative to the copied nodes
806
}
807 }
808
Popular Tags