1 17 package org.alfresco.repo.exporter; 18 19 import java.io.IOException ; 20 import java.io.InputStream ; 21 import java.io.OutputStream ; 22 import java.io.Serializable ; 23 import java.io.UnsupportedEncodingException ; 24 import java.util.Collection ; 25 import java.util.Date ; 26 import java.util.HashMap ; 27 import java.util.List ; 28 import java.util.Map ; 29 import java.util.Set ; 30 31 import org.alfresco.service.cmr.dictionary.DataTypeDefinition; 32 import org.alfresco.service.cmr.dictionary.DictionaryService; 33 import org.alfresco.service.cmr.dictionary.PropertyDefinition; 34 import org.alfresco.service.cmr.repository.AssociationRef; 35 import org.alfresco.service.cmr.repository.ChildAssociationRef; 36 import org.alfresco.service.cmr.repository.ContentReader; 37 import org.alfresco.service.cmr.repository.ContentService; 38 import org.alfresco.service.cmr.repository.NodeRef; 39 import org.alfresco.service.cmr.repository.NodeService; 40 import org.alfresco.service.cmr.repository.Path; 41 import org.alfresco.service.cmr.repository.datatype.TypeConversionException; 42 import org.alfresco.service.cmr.search.SearchService; 43 import org.alfresco.service.cmr.security.AccessPermission; 44 import org.alfresco.service.cmr.security.AccessStatus; 45 import org.alfresco.service.cmr.security.AuthenticationService; 46 import org.alfresco.service.cmr.security.PermissionService; 47 import org.alfresco.service.cmr.view.ExportPackageHandler; 48 import org.alfresco.service.cmr.view.Exporter; 49 import org.alfresco.service.cmr.view.ExporterContext; 50 import org.alfresco.service.cmr.view.ExporterCrawlerParameters; 51 import org.alfresco.service.cmr.view.ExporterException; 52 import org.alfresco.service.cmr.view.ExporterService; 53 import org.alfresco.service.cmr.view.ImporterException; 54 import org.alfresco.service.cmr.view.Location; 55 import org.alfresco.service.descriptor.DescriptorService; 56 import org.alfresco.service.namespace.NamespaceService; 57 import org.alfresco.service.namespace.QName; 58 import org.alfresco.service.namespace.RegexQNamePattern; 59 import org.alfresco.util.ParameterCheck; 60 import org.dom4j.io.OutputFormat; 61 import org.dom4j.io.XMLWriter; 62 63 64 69 public class ExporterComponent 70 implements ExporterService 71 { 72 private NamespaceService namespaceService; 74 private DictionaryService dictionaryService; 75 private NodeService nodeService; 76 private SearchService searchService; 77 private ContentService contentService; 78 private DescriptorService descriptorService; 79 private AuthenticationService authenticationService; 80 private PermissionService permissionService; 81 82 83 84 private int indentSize = 2; 85 86 87 90 public void setNodeService(NodeService nodeService) 91 { 92 this.nodeService = nodeService; 93 } 94 95 98 public void setSearchService(SearchService searchService) 99 { 100 this.searchService = searchService; 101 } 102 103 106 public void setContentService(ContentService contentService) 107 { 108 this.contentService = contentService; 109 } 110 111 114 public void setDictionaryService(DictionaryService dictionaryService) 115 { 116 this.dictionaryService = dictionaryService; 117 } 118 119 122 public void setNamespaceService(NamespaceService namespaceService) 123 { 124 this.namespaceService = namespaceService; 125 } 126 127 130 public void setDescriptorService(DescriptorService descriptorService) 131 { 132 this.descriptorService = descriptorService; 133 } 134 135 138 public void setAuthenticationService(AuthenticationService authenticationService) 139 { 140 this.authenticationService = authenticationService; 141 } 142 143 146 public void setPermissionService(PermissionService permissionService) 147 { 148 this.permissionService = permissionService; 149 } 150 151 152 155 public void exportView(OutputStream viewWriter, ExporterCrawlerParameters parameters, Exporter progress) 156 { 157 ParameterCheck.mandatory("View Writer", viewWriter); 158 159 Exporter xmlExporter = createXMLExporter(viewWriter); 161 162 exportView(xmlExporter, parameters, progress); 164 } 165 166 169 public void exportView(ExportPackageHandler exportHandler, ExporterCrawlerParameters parameters, Exporter progress) 170 { 171 ParameterCheck.mandatory("Stream Handler", exportHandler); 172 173 exportHandler.startExport(); 175 OutputStream dataFile = exportHandler.createDataStream(); 176 Exporter xmlExporter = createXMLExporter(dataFile); 177 URLExporter urlExporter = new URLExporter(xmlExporter, exportHandler); 178 179 exportView(urlExporter, parameters, progress); 181 182 exportHandler.endExport(); 184 } 185 186 189 public void exportView(Exporter exporter, ExporterCrawlerParameters parameters, Exporter progress) 190 { 191 ParameterCheck.mandatory("Exporter", exporter); 192 193 ChainedExporter chainedExporter = new ChainedExporter(new Exporter[] {exporter, progress}); 194 DefaultCrawler crawler = new DefaultCrawler(); 195 crawler.export(parameters, chainedExporter); 196 } 197 198 205 private Exporter createXMLExporter(OutputStream viewWriter) 206 { 207 OutputFormat format = OutputFormat.createPrettyPrint(); 209 format.setNewLineAfterDeclaration(false); 210 format.setIndentSize(indentSize); 211 format.setEncoding("UTF-8"); 212 213 try 215 { 216 XMLWriter writer = new XMLWriter(viewWriter, format); 217 return new ViewXMLExporter(namespaceService, nodeService, dictionaryService, permissionService, writer); 218 } 219 catch (UnsupportedEncodingException e) 220 { 221 throw new ExporterException("Failed to create XML Writer for export", e); 222 } 223 } 224 225 226 232 private class DefaultCrawler implements ExporterCrawler 233 { 234 private ExporterContext context; 235 private Map <NodeRef, NodeRef> nodesWithSecondaryLinks = new HashMap <NodeRef, NodeRef>(); 236 private Map <NodeRef, NodeRef> nodesWithAssociations = new HashMap <NodeRef, NodeRef>(); 237 238 239 242 public void export(ExporterCrawlerParameters parameters, Exporter exporter) 243 { 244 nodesWithSecondaryLinks.clear(); 246 nodesWithAssociations.clear(); 247 context = new ExporterContextImpl(parameters); 248 exporter.start(context); 249 250 254 NodeRef nodeRef = context.getExportOf(); 256 boolean rootNode = nodeService.getRootNode(nodeRef.getStoreRef()).equals(nodeRef); 257 if (parameters.isCrawlSelf() && !rootNode) 258 { 259 walkStartNamespaces(parameters, exporter); 261 walkNode(nodeRef, parameters, exporter); 262 walkEndNamespaces(parameters, exporter); 263 } 264 else if (parameters.isCrawlChildNodes()) 265 { 266 List <ChildAssociationRef> childAssocs = nodeService.getChildAssocs(nodeRef); 268 for (ChildAssociationRef childAssoc : childAssocs) 269 { 270 walkStartNamespaces(parameters, exporter); 271 walkNode(childAssoc.getChildRef(), parameters, exporter); 272 walkEndNamespaces(parameters, exporter); 273 } 274 } 275 276 280 for (NodeRef nodeWithAssociations : nodesWithSecondaryLinks.keySet()) 281 { 282 walkStartNamespaces(parameters, exporter); 283 walkNodeSecondaryLinks(nodeWithAssociations, parameters, exporter); 284 walkEndNamespaces(parameters, exporter); 285 } 286 287 291 for (NodeRef nodeWithAssociations : nodesWithAssociations.keySet()) 292 { 293 walkStartNamespaces(parameters, exporter); 294 walkNodeAssociations(nodeWithAssociations, parameters, exporter); 295 walkEndNamespaces(parameters, exporter); 296 } 297 298 exporter.end(); 299 } 300 301 304 private void walkStartNamespaces(ExporterCrawlerParameters parameters, Exporter exporter) 305 { 306 Collection <String > prefixes = namespaceService.getPrefixes(); 307 for (String prefix : prefixes) 308 { 309 if (!prefix.equals("xml")) 310 { 311 String uri = namespaceService.getNamespaceURI(prefix); 312 exporter.startNamespace(prefix, uri); 313 } 314 } 315 } 316 317 320 private void walkEndNamespaces(ExporterCrawlerParameters parameters, Exporter exporter) 321 { 322 Collection <String > prefixes = namespaceService.getPrefixes(); 323 for (String prefix : prefixes) 324 { 325 if (!prefix.equals("xml")) 326 { 327 exporter.endNamespace(prefix); 328 } 329 } 330 } 331 332 337 private void walkNode(NodeRef nodeRef, ExporterCrawlerParameters parameters, Exporter exporter) 338 { 339 QName type = nodeService.getType(nodeRef); 341 if (isExcludedURI(parameters.getExcludeNamespaceURIs(), type.getNamespaceURI())) 342 { 343 return; 344 } 345 346 exporter.startNode(nodeRef); 347 348 exporter.startAspects(nodeRef); 350 Set <QName> aspects = nodeService.getAspects(nodeRef); 351 for (QName aspect : aspects) 352 { 353 if (!isExcludedURI(parameters.getExcludeNamespaceURIs(), aspect.getNamespaceURI())) 354 { 355 exporter.startAspect(nodeRef, aspect); 356 exporter.endAspect(nodeRef, aspect); 357 } 358 } 359 exporter.endAspects(nodeRef); 360 361 AccessStatus readPermission = permissionService.hasPermission(nodeRef, PermissionService.READ_PERMISSIONS); 363 if (readPermission.equals(AccessStatus.ALLOWED)) 364 { 365 Set <AccessPermission> permissions = permissionService.getAllSetPermissions(nodeRef); 366 boolean inheritPermissions = permissionService.getInheritParentPermissions(nodeRef); 367 if (permissions.size() > 0 || !inheritPermissions) 368 { 369 exporter.startACL(nodeRef); 370 for (AccessPermission permission : permissions) 371 { 372 exporter.permission(nodeRef, permission); 373 } 374 exporter.endACL(nodeRef); 375 } 376 } 377 378 exporter.startProperties(nodeRef); 380 Map <QName, Serializable > properties = nodeService.getProperties(nodeRef); 381 for (QName property : properties.keySet()) 382 { 383 if (isExcludedURI(parameters.getExcludeNamespaceURIs(), property.getNamespaceURI())) 385 { 386 continue; 387 } 388 389 Object value = properties.get(property); 391 if (!parameters.isCrawlNullProperties() && value == null) 392 { 393 continue; 394 } 395 396 exporter.startProperty(nodeRef, property); 398 399 PropertyDefinition propertyDef = dictionaryService.getProperty(property); 401 boolean isContentProperty = (propertyDef == null) ? false : propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT); 402 403 if (isContentProperty) 404 { 405 ContentReader reader = contentService.getReader(nodeRef, property); 407 if (reader == null || reader.exists() == false) 408 { 409 exporter.warning("Failed to read content for property " + property + " on node " + nodeRef); 410 } 411 else 412 { 413 if (parameters.isCrawlContent()) 415 { 416 InputStream inputStream = reader.getContentInputStream(); 417 try 418 { 419 exporter.content(nodeRef, property, inputStream, reader.getContentData()); 420 } 421 finally 422 { 423 try 424 { 425 inputStream.close(); 426 } 427 catch(IOException e) 428 { 429 throw new ExporterException("Failed to export node content for node " + nodeRef, e); 430 } 431 } 432 } 433 else 434 { 435 exporter.content(nodeRef, property, null, null); 437 } 438 } 439 } 440 else 441 { 442 try 444 { 445 if (value instanceof Collection ) 446 { 447 exporter.value(nodeRef, property, (Collection )value); 448 } 449 else 450 { 451 exporter.value(nodeRef, property, value); 452 } 453 } 454 catch(TypeConversionException e) 455 { 456 exporter.warning("Value of property " + property + " could not be converted to xml string"); 457 exporter.value(nodeRef, property, properties.get(property).toString()); 458 } 459 } 460 461 exporter.endProperty(nodeRef, property); 463 } 464 exporter.endProperties(nodeRef); 465 466 if (parameters.isCrawlChildNodes()) 468 { 469 exporter.startAssocs(nodeRef); 470 List <ChildAssociationRef> childAssocs = nodeService.getChildAssocs(nodeRef); 471 for (int i = 0; i < childAssocs.size(); i++) 472 { 473 ChildAssociationRef childAssoc = childAssocs.get(i); 474 QName childAssocType = childAssoc.getTypeQName(); 475 if (isExcludedURI(parameters.getExcludeNamespaceURIs(), childAssocType.getNamespaceURI())) 476 { 477 continue; 478 } 479 if (childAssoc.isPrimary() == false) 480 { 481 nodesWithSecondaryLinks.put(nodeRef, nodeRef); 482 continue; 483 } 484 if (i == 0 || childAssocs.get(i - 1).getTypeQName().equals(childAssocType) == false) 485 { 486 exporter.startAssoc(nodeRef, childAssocType); 487 } 488 if (!isExcludedURI(parameters.getExcludeNamespaceURIs(), childAssoc.getQName().getNamespaceURI())) 489 { 490 walkNode(childAssoc.getChildRef(), parameters, exporter); 491 } 492 if (i == childAssocs.size() - 1 || childAssocs.get(i + 1).getTypeQName().equals(childAssocType) == false) 493 { 494 exporter.endAssoc(nodeRef, childAssocType); 495 } 496 } 497 exporter.endAssocs(nodeRef); 498 } 499 500 if (parameters.isCrawlAssociations()) 502 { 503 List <AssociationRef> associations = nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL); 504 if (associations.size() > 0) 505 { 506 nodesWithAssociations.put(nodeRef, nodeRef); 507 } 508 } 509 510 exporter.endNode(nodeRef); 512 } 513 514 521 private void walkNodeSecondaryLinks(NodeRef nodeRef, ExporterCrawlerParameters parameters, Exporter exporter) 522 { 523 exporter.startReference(nodeRef, null); 524 exporter.startAssocs(nodeRef); 525 List <ChildAssociationRef> childAssocs = nodeService.getChildAssocs(nodeRef); 526 for (int i = 0; i < childAssocs.size(); i++) 527 { 528 ChildAssociationRef childAssoc = childAssocs.get(i); 529 530 QName childAssocType = childAssoc.getTypeQName(); 532 if (isExcludedURI(parameters.getExcludeNamespaceURIs(), childAssocType.getNamespaceURI())) 533 { 534 continue; 535 } 536 if (childAssoc.isPrimary()) 537 { 538 continue; 539 } 540 if (!isWithinExport(childAssoc.getChildRef(), parameters)) 541 { 542 continue; 543 } 544 545 if (i == 0 || childAssocs.get(i - 1).getTypeQName().equals(childAssocType) == false) 547 { 548 exporter.startAssoc(nodeRef, childAssocType); 549 } 550 QName childName = childAssoc.getQName(); 551 if (!isExcludedURI(parameters.getExcludeNamespaceURIs(), childName.getNamespaceURI())) 552 { 553 exporter.startReference(childAssoc.getChildRef(), childName); 554 exporter.endReference(childAssoc.getChildRef()); 555 } 556 if (i == childAssocs.size() - 1 || childAssocs.get(i + 1).getTypeQName().equals(childAssocType) == false) 557 { 558 exporter.endAssoc(nodeRef, childAssocType); 559 } 560 } 561 exporter.endAssocs(nodeRef); 562 exporter.endReference(nodeRef); 563 } 564 565 572 private void walkNodeAssociations(NodeRef nodeRef, ExporterCrawlerParameters parameters, Exporter exporter) 573 { 574 exporter.startReference(nodeRef, null); 575 exporter.startAssocs(nodeRef); 576 List <AssociationRef> assocs = nodeService.getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL); 577 for (int i = 0; i < assocs.size(); i++) 578 { 579 AssociationRef assoc = assocs.get(i); 580 581 QName assocType = assoc.getTypeQName(); 583 if (isExcludedURI(parameters.getExcludeNamespaceURIs(), assocType.getNamespaceURI())) 584 { 585 continue; 586 } 587 if (!isWithinExport(assoc.getTargetRef(), parameters)) 588 { 589 continue; 590 } 591 592 if (i == 0 || assocs.get(i - 1).getTypeQName().equals(assocType) == false) 594 { 595 exporter.startAssoc(nodeRef, assocType); 596 } 597 exporter.startReference(assoc.getTargetRef(), null); 598 exporter.endReference(assoc.getTargetRef()); 599 if (i == assocs.size() - 1 || assocs.get(i + 1).getTypeQName().equals(assocType) == false) 600 { 601 exporter.endAssoc(nodeRef, assocType); 602 } 603 } 604 exporter.endAssocs(nodeRef); 605 exporter.endReference(nodeRef); 606 } 607 608 614 private boolean isExcludedURI(String [] excludeNamespaceURIs, String uri) 615 { 616 for (String excludedURI : excludeNamespaceURIs) 617 { 618 if (uri.equals(excludedURI)) 619 { 620 return true; 621 } 622 } 623 return false; 624 } 625 626 632 private boolean isWithinExport(NodeRef nodeRef, ExporterCrawlerParameters parameters) 633 { 634 boolean isWithin = false; 635 636 NodeRef exportRoot = context.getExportOf(); 638 if (nodeRef.equals(exportRoot) && parameters.isCrawlSelf() == true) 639 { 640 isWithin = true; 642 } 643 else 644 { 645 Path nodePath = nodeService.getPath(nodeRef); 647 for (int i = nodePath.size() -1; i >= 0; i--) 648 { 649 Path.ChildAssocElement pathElement = (Path.ChildAssocElement)nodePath.get(i); 650 if (pathElement.getRef().getChildRef().equals(exportRoot)) 651 { 652 isWithin = true; 653 break; 654 } 655 } 656 } 657 658 return isWithin; 659 } 660 } 661 662 663 666 private class ExporterContextImpl implements ExporterContext 667 { 668 private NodeRef exportOf; 669 private NodeRef parent; 670 private String exportedBy; 671 private Date exportedDate; 672 private String exporterVersion; 673 674 679 public ExporterContextImpl(ExporterCrawlerParameters parameters) 680 { 681 String currentUserName = authenticationService.getCurrentUserName(); 683 exportedBy = (currentUserName == null) ? "unknown" : currentUserName; 684 685 exportedDate = new Date (System.currentTimeMillis()); 687 688 exportOf = getNodeRef(parameters.getExportFrom()); 690 691 parent = getParent(exportOf, parameters.isCrawlSelf()); 693 694 exporterVersion = descriptorService.getServerDescriptor().getVersion(); 696 } 697 698 701 public String getExportedBy() 702 { 703 return exportedBy; 704 } 705 706 709 public Date getExportedDate() 710 { 711 return exportedDate; 712 } 713 714 717 public String getExporterVersion() 718 { 719 return exporterVersion; 720 } 721 722 725 public NodeRef getExportOf() 726 { 727 return exportOf; 728 } 729 730 734 public NodeRef getExportParent() 735 { 736 return parent; 737 } 738 739 745 private NodeRef getNodeRef(Location location) 746 { 747 ParameterCheck.mandatory("Location", location); 748 749 NodeRef nodeRef = (location == null) ? null : location.getNodeRef(); 751 if (nodeRef == null) 752 { 753 nodeRef = nodeService.getRootNode(location.getStoreRef()); 755 } 756 757 String path = (location == null) ? null : location.getPath(); 759 if (path != null && path.length() >0) 760 { 761 List <NodeRef> nodeRefs = searchService.selectNodes(nodeRef, path, null, namespaceService, false); 763 if (nodeRefs.size() == 0) 764 { 765 throw new ImporterException("Path " + path + " within node " + nodeRef + " does not exist - the path must resolve to a valid location"); 766 } 767 if (nodeRefs.size() > 1) 768 { 769 throw new ImporterException("Path " + path + " within node " + nodeRef + " found too many locations - the path must resolve to one location"); 770 } 771 nodeRef = nodeRefs.get(0); 772 } 773 774 776 return nodeRef; 777 } 778 779 786 private NodeRef getParent(NodeRef exportOf, boolean exportSelf) 787 { 788 NodeRef parent = null; 789 790 if (exportSelf) 791 { 792 NodeRef rootNode = nodeService.getRootNode(exportOf.getStoreRef()); 793 if (rootNode.equals(exportOf)) 794 { 795 parent = exportOf; 796 } 797 else 798 { 799 ChildAssociationRef parentRef = nodeService.getPrimaryParent(exportOf); 800 parent = parentRef.getParentRef(); 801 } 802 } 803 else 804 { 805 parent = exportOf; 806 } 807 808 return parent; 809 } 810 811 } 812 813 } 814 | Popular Tags |