1 17 package org.alfresco.repo.copy; 18 19 import java.io.Serializable ; 20 import java.util.Collection ; 21 import java.util.HashMap ; 22 import java.util.List ; 23 import java.util.Map ; 24 import java.util.Set ; 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 57 public class CopyServiceImpl implements CopyService 58 { 59 62 private NodeService nodeService; 63 64 67 private DictionaryService dictionaryService; 68 69 72 private PolicyComponent policyComponent; 73 74 77 private RuleService ruleService; 78 79 82 private ClassPolicyDelegate<CopyServicePolicies.OnCopyNodePolicy> onCopyNodeDelegate; 83 private ClassPolicyDelegate<CopyServicePolicies.OnCopyCompletePolicy> onCopyCompleteDelegate; 84 85 90 public void setNodeService(NodeService nodeService) 91 { 92 this.nodeService = nodeService; 93 } 94 95 100 public void setDictionaryService(DictionaryService dictionaryService) 101 { 102 this.dictionaryService = dictionaryService; 103 } 104 105 110 public void setPolicyComponent(PolicyComponent policyComponent) 111 { 112 this.policyComponent = policyComponent; 113 } 114 115 120 public void setRuleService(RuleService ruleService) 121 { 122 this.ruleService = ruleService; 123 } 124 125 128 public void init() 129 { 130 this.onCopyNodeDelegate = this.policyComponent.registerClassPolicy(CopyServicePolicies.OnCopyNodePolicy.class); 132 this.onCopyCompleteDelegate = this.policyComponent.registerClassPolicy(CopyServicePolicies.OnCopyCompletePolicy.class); 133 134 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 156 public NodeRef copy( 157 NodeRef sourceNodeRef, 158 NodeRef destinationParent, 159 QName destinationAssocTypeQName, 160 QName destinationQName, 161 boolean copyChildren) 162 { 163 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 172 throw new UnsupportedOperationException ("Copying nodes across stores is not currently supported."); 174 } 175 176 Map <NodeRef, NodeRef> copiedChildren = new HashMap <NodeRef, NodeRef>(); 178 NodeRef copy = recursiveCopy(sourceNodeRef, destinationParent, destinationAssocTypeQName, destinationQName, copyChildren, copiedChildren); 179 180 for (Map.Entry <NodeRef, NodeRef> entry : copiedChildren.entrySet()) 182 { 183 invokeCopyComplete(entry.getKey(), entry.getValue(), true, copiedChildren); 184 } 185 186 return copy; 187 } 188 189 196 private void invokeCopyComplete( 197 NodeRef sourceNodeRef, 198 NodeRef destinationNodeRef, 199 boolean copyToNewNode, 200 Map <NodeRef, NodeRef> copiedNodeRefs) 201 { 202 QName sourceClassRef = this.nodeService.getType(sourceNodeRef); 203 invokeCopyComplete(sourceClassRef, sourceNodeRef, destinationNodeRef, copyToNewNode, copiedNodeRefs); 204 205 Set <QName> sourceAspects = this.nodeService.getAspects(sourceNodeRef); 207 for (QName sourceAspect : sourceAspects) 208 { 209 invokeCopyComplete(sourceAspect, sourceNodeRef, destinationNodeRef, copyToNewNode, copiedNodeRefs); 210 } 211 } 212 213 220 private void invokeCopyComplete( 221 QName typeQName, 222 NodeRef sourceNodeRef, 223 NodeRef destinationNodeRef, 224 boolean copyToNewNode, 225 Map <NodeRef, NodeRef> copiedNodeRefs) 226 { 227 Collection <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 248 private void defaultOnCopyComplete( 249 QName typeQName, 250 NodeRef sourceNodeRef, 251 NodeRef destinationNodeRef, 252 Map <NodeRef, NodeRef> copiedNodeRefs) 253 { 254 ClassDefinition classDefinition = this.dictionaryService.getClass(typeQName); 255 if (classDefinition != null) 256 { 257 Map <QName,PropertyDefinition> propertyDefinitions = classDefinition.getProperties(); 259 for (Map.Entry <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 Serializable 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 Map <QName, AssociationDefinition> assocDefs = classDefinition.getAssociations(); 281 282 List <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 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 List <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 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 333 private NodeRef recursiveCopy( 334 NodeRef sourceNodeRef, 335 NodeRef destinationParent, 336 QName destinationAssocTypeQName, 337 QName destinationQName, 338 boolean copyChildren, 339 Map <NodeRef, NodeRef> copiedChildren) 340 { 341 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 PolicyScope copyDetails = getCopyDetails(sourceNodeRef, destinationParent.getStoreRef(), true); 351 352 Map <QName, Serializable > typeProps = copyDetails.getProperties(); 354 Map <QName, Serializable > properties = new HashMap <QName, Serializable >(); 355 if (typeProps != null) 356 { 357 properties.putAll(typeProps); 358 } 359 for (AspectDefinition aspectDef : typeDef.getDefaultAspects()) 360 { 361 Map <QName, Serializable > aspectProps = copyDetails.getProperties(aspectDef.getName()); 362 if (aspectProps != null) 363 { 364 properties.putAll(aspectProps); 365 } 366 } 367 368 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 this.ruleService.disableRules(destinationNodeRef); 380 try 381 { 382 Map <QName, Serializable > copyProperties = new HashMap <QName, Serializable >(); 384 copyProperties.put(ContentModel.PROP_COPY_REFERENCE, sourceNodeRef); 385 this.nodeService.addAspect(destinationNodeRef, ContentModel.ASPECT_COPIEDFROM, copyProperties); 386 387 copyAspects(destinationNodeRef, copyDetails); 389 390 copyAssociations(destinationNodeRef, copyDetails, copyChildren, copiedChildren); 392 } 393 finally 394 { 395 this.ruleService.enableRules(destinationNodeRef); 396 } 397 398 return destinationNodeRef; 399 } 400 401 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 invokeOnCopy(sourceClassRef, sourceNodeRef, destinationStoreRef, copyToNewNode, copyDetails); 418 419 421 Set <QName> sourceAspects = this.nodeService.getAspects(sourceNodeRef); 423 for (QName sourceAspect : sourceAspects) 424 { 425 invokeOnCopy(sourceAspect, sourceNodeRef, destinationStoreRef, copyToNewNode, copyDetails); 427 } 428 429 return copyDetails; 430 } 431 432 439 private void invokeOnCopy( 440 QName sourceClassRef, 441 NodeRef sourceNodeRef, 442 StoreRef destinationStoreRef, 443 boolean copyToNewNode, 444 PolicyScope copyDetails) 445 { 446 Collection <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 467 private void defaultOnCopy(QName classRef, NodeRef sourceNodeRef, PolicyScope copyDetails) 468 { 469 ClassDefinition classDefinition = this.dictionaryService.getClass(classRef); 470 if (classDefinition != null) 471 { 472 Map <QName,PropertyDefinition> propertyDefinitions = classDefinition.getProperties(); 474 for (QName propertyName : propertyDefinitions.keySet()) 475 { 476 Serializable propValue = this.nodeService.getProperty(sourceNodeRef, propertyName); 477 copyDetails.addProperty(classDefinition.getName(), propertyName, propValue); 478 } 479 480 Map <QName, AssociationDefinition> assocDefs = classDefinition.getAssociations(); 482 483 if (classDefinition.isContainer()) 485 { 486 List <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 List <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 514 private void copyProperties(NodeRef destinationNodeRef, PolicyScope copyDetails) 515 { 516 Map <QName, Serializable > 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 532 private void copyAspects(NodeRef destinationNodeRef, PolicyScope copyDetails) 533 { 534 Set <QName> apects = copyDetails.getAspects(); 535 for (QName aspect : apects) 536 { 537 if (this.nodeService.hasAspect(destinationNodeRef, aspect) == false) 538 { 539 this.nodeService.addAspect( 541 destinationNodeRef, 542 aspect, 543 copyDetails.getProperties(aspect)); 544 } 545 else 546 { 547 Map <QName, Serializable > aspectProps = copyDetails.getProperties(aspect); 549 if (aspectProps != null) 550 { 551 for (Map.Entry <QName, Serializable > entry : aspectProps.entrySet()) 552 { 553 this.nodeService.setProperty(destinationNodeRef, entry.getKey(), entry.getValue()); 554 } 555 } 556 } 557 } 558 } 559 560 572 private void copyAssociations( 573 NodeRef destinationNodeRef, 574 PolicyScope copyDetails, 575 boolean copyChildren, 576 Map <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 <QName> apects = copyDetails.getAspects(); 583 for (QName aspect : apects) 584 { 585 if (this.nodeService.hasAspect(destinationNodeRef, aspect) == false) 586 { 587 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 603 private void copyTargetAssociations(QName classRef, NodeRef destinationNodeRef, PolicyScope copyDetails) 604 { 605 List <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 this.nodeService.createAssociation(destinationNodeRef, targetRef, assocRef.getTypeQName()); 626 } 627 } 628 } 629 } 630 631 642 private void copyChildAssociations( 643 QName classRef, 644 NodeRef destinationNodeRef, 645 PolicyScope copyDetails, 646 boolean copyChildren, 647 Map <NodeRef, NodeRef> copiedChildren) 648 { 649 List <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 if (copiedChildren.containsKey(childAssoc.getChildRef()) == false && 660 copiedChildren.containsValue(childAssoc.getChildRef()) == false) 661 { 662 recursiveCopy( 664 childAssoc.getChildRef(), 665 destinationNodeRef, 666 childAssoc.getTypeQName(), 667 childAssoc.getQName(), 668 copyChildren, 669 copiedChildren); 670 } 671 } 672 else 673 { 674 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 if (this.dictionaryService.isSubClass(childType, ContentModel.TYPE_CONFIGURATIONS) == true || 686 copyDetails.isChildAssociationRefAlwaysTraversed(classRef, childAssoc) == true) 687 { 688 if (copiedChildren.containsKey(childRef) == false) 689 { 690 recursiveCopy( 692 childRef, 693 destinationNodeRef, 694 childAssoc.getTypeQName(), 695 childAssoc.getQName(), 696 true, 697 copiedChildren); 698 } 699 } 700 else 701 { 702 this.nodeService.addChild(destinationNodeRef, childRef, childAssoc.getTypeQName(), childAssoc.getQName()); 704 } 705 } 706 } 707 } 708 } 709 710 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 732 public void copy( 733 NodeRef sourceNodeRef, 734 NodeRef destinationNodeRef) 735 { 736 if (this.nodeService.getType(sourceNodeRef).equals(this.nodeService.getType(destinationNodeRef)) == false) 738 { 739 throw new CopyServiceException("The source and destination node must be the same type."); 741 } 742 743 PolicyScope copyDetails = getCopyDetails(sourceNodeRef, destinationNodeRef.getStoreRef(), false); 745 746 copyProperties(destinationNodeRef, copyDetails); 748 copyAspects(destinationNodeRef, copyDetails); 749 copyAssociations(destinationNodeRef, copyDetails, false, new HashMap <NodeRef, NodeRef>()); 750 751 Map <NodeRef, NodeRef> copiedNodes = new HashMap <NodeRef, NodeRef>(1); 753 copiedNodes.put(sourceNodeRef, destinationNodeRef); 754 invokeCopyComplete(sourceNodeRef, destinationNodeRef, false, copiedNodes); 755 } 756 757 767 public void copyAspectOnCopy( 768 QName classRef, 769 NodeRef sourceNodeRef, 770 StoreRef destinationStoreRef, 771 boolean copyToNewNode, 772 PolicyScope copyDetails) 773 { 774 } 777 778 public void onCopyOwnable( 779 QName classRef, 780 NodeRef sourceNodeRef, 781 StoreRef destinationStoreRef, 782 boolean copyToNewNode, 783 PolicyScope copyDetails) 784 { 785 } 787 788 public void onCopyAuthor( 789 QName classRef, 790 NodeRef sourceNodeRef, 791 StoreRef destinationStoreRef, 792 boolean copyToNewNode, 793 PolicyScope copyDetails) 794 { 795 } 797 798 public void onCopyComplete( 799 QName classRef, 800 NodeRef sourceNodeRef, 801 NodeRef destinationRef, 802 boolean copyToNew, 803 Map <NodeRef, NodeRef> copyMap) 804 { 805 } 807 } 808 | Popular Tags |