001/* 002 * Copyright 2011 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.web.repository.page; 017 018import java.io.InputStream; 019import java.io.OutputStream; 020import java.util.ArrayList; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Properties; 025import java.util.Set; 026 027import javax.jcr.Node; 028import javax.jcr.RepositoryException; 029import javax.xml.transform.OutputKeys; 030import javax.xml.transform.TransformerFactory; 031import javax.xml.transform.sax.SAXTransformerFactory; 032import javax.xml.transform.sax.TransformerHandler; 033import javax.xml.transform.stream.StreamResult; 034 035import org.apache.avalon.framework.component.Component; 036import org.apache.avalon.framework.logger.AbstractLogEnabled; 037import org.apache.avalon.framework.service.ServiceException; 038import org.apache.avalon.framework.service.ServiceManager; 039import org.apache.avalon.framework.service.Serviceable; 040import org.apache.excalibur.xml.sax.SAXParser; 041import org.apache.xml.serializer.OutputPropertiesFactory; 042import org.xml.sax.ContentHandler; 043import org.xml.sax.InputSource; 044 045import org.ametys.cms.content.references.OutgoingReferences; 046import org.ametys.cms.content.references.OutgoingReferencesExtractor; 047import org.ametys.cms.contenttype.ContentType; 048import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 049import org.ametys.cms.contenttype.ContentTypesHelper; 050import org.ametys.cms.contenttype.MetadataDefinition; 051import org.ametys.cms.contenttype.RichTextUpdater; 052import org.ametys.cms.repository.Content; 053import org.ametys.cms.repository.ModifiableContent; 054import org.ametys.cms.repository.WorkflowAwareContent; 055import org.ametys.cms.repository.WorkflowAwareContentHelper; 056import org.ametys.plugins.repository.AmetysObject; 057import org.ametys.plugins.repository.AmetysObjectIterable; 058import org.ametys.plugins.repository.AmetysObjectResolver; 059import org.ametys.plugins.repository.AmetysRepositoryException; 060import org.ametys.plugins.repository.ModifiableAmetysObject; 061import org.ametys.plugins.repository.RepositoryConstants; 062import org.ametys.plugins.repository.TraversableAmetysObject; 063import org.ametys.plugins.repository.UnknownAmetysObjectException; 064import org.ametys.plugins.repository.data.UnknownDataException; 065import org.ametys.plugins.repository.data.holder.DataHolder; 066import org.ametys.plugins.repository.data.holder.ModelAwareDataHolder; 067import org.ametys.plugins.repository.data.holder.ModelLessDataHolder; 068import org.ametys.plugins.repository.data.holder.ModifiableDataHolder; 069import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 070import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder; 071import org.ametys.plugins.repository.data.holder.group.Repeater; 072import org.ametys.plugins.repository.data.holder.group.RepeaterEntry; 073import org.ametys.plugins.repository.data.type.ModelItemTypeConstants; 074import org.ametys.plugins.repository.metadata.CompositeMetadata; 075import org.ametys.plugins.repository.metadata.CompositeMetadata.MetadataType; 076import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata; 077import org.ametys.plugins.repository.metadata.ModifiableRichText; 078import org.ametys.plugins.repository.version.VersionableAmetysObject; 079import org.ametys.plugins.workflow.support.WorkflowProvider; 080import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 081import org.ametys.runtime.model.exception.NotUniqueTypeException; 082import org.ametys.runtime.model.exception.UndefinedItemPathException; 083import org.ametys.runtime.model.exception.UnknownTypeException; 084import org.ametys.web.repository.ModifiableSiteAwareAmetysObject; 085import org.ametys.web.repository.content.WebContent; 086import org.ametys.web.repository.page.ZoneItem.ZoneType; 087import org.ametys.web.repository.site.Site; 088import org.ametys.web.repository.sitemap.Sitemap; 089import org.ametys.web.site.CopyUpdaterExtensionPoint; 090 091import com.opensymphony.workflow.spi.Step; 092 093/** 094 * Component for copying site or pages 095 * 096 */ 097public class CopySiteComponent extends AbstractLogEnabled implements Component, Serviceable 098{ 099 /** Avalon Role */ 100 public static final String ROLE = CopySiteComponent.class.getName(); 101 102 /** The service manager. */ 103 protected ServiceManager _manager; 104 105 private AmetysObjectResolver _resolver; 106 private WorkflowProvider _workflowProvider; 107 private ContentTypeExtensionPoint _cTypeEP; 108 private ContentTypesHelper _contentTypesHelper; 109 110 private CopyUpdaterExtensionPoint _updaterEP; 111 private OutgoingReferencesExtractor _outgoingReferencesExtractor; 112 113 @Override 114 public void service(ServiceManager serviceManager) throws ServiceException 115 { 116 _manager = serviceManager; 117 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 118 _contentTypesHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE); 119 _workflowProvider = (WorkflowProvider) serviceManager.lookup(WorkflowProvider.ROLE); 120 _cTypeEP = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE); 121 _updaterEP = (CopyUpdaterExtensionPoint) serviceManager.lookup(CopyUpdaterExtensionPoint.ROLE); 122 _outgoingReferencesExtractor = (OutgoingReferencesExtractor) serviceManager.lookup(OutgoingReferencesExtractor.ROLE); 123 } 124 125 /** 126 * This methods must be used after calling <code>copyTo</code> on a Page. 127 * Its updates references to ametys objects for metadata of new created pages and contents 128 * @param originalPage the original page 129 * @param createdPage the created page after a copy 130 * @throws AmetysRepositoryException if an error occurs 131 */ 132 public void updateReferencesAfterCopy (Page originalPage, Page createdPage) throws AmetysRepositoryException 133 { 134 // Update references to ametys object on metadata 135 _updateReferencesToAmetysObjects (createdPage, originalPage, createdPage); 136 137 for (Zone zone : createdPage.getZones()) 138 { 139 _updateReferencesToAmetysObjects (zone, originalPage, createdPage); 140 141 for (ZoneItem zoneItem : zone.getZoneItems()) 142 { 143 _updateReferencesToAmetysObjects (zoneItem, originalPage, createdPage); 144 145 if (zoneItem.getType().equals(ZoneType.SERVICE)) 146 { 147 _updateReferencesToAmetysObjects (zoneItem, originalPage, createdPage); 148 } 149 else 150 { 151 Content content = zoneItem.getContent(); 152 // TODO NEWATTRIBUTEAPI_CONTENT: when all types are implemented, use the method that uses the new API 153 _updateReferencesToAmetysObjects (content.getMetadataHolder(), originalPage, createdPage); 154 } 155 } 156 } 157 158 // Browse child pages 159 for (Page childPage : createdPage.getChildrenPages()) 160 { 161 updateReferencesAfterCopy ((Page) originalPage.getChild(childPage.getName()), childPage); 162 } 163 } 164 165 /** 166 * This method must be used after calling <code>copyTo</code> on a Site. 167 * Its updates contents and pages after a site copy 168 * @param originalSite the original site 169 * @param createdSite the created site after copy 170 * @throws AmetysRepositoryException if an error occurs 171 */ 172 public void updateSiteAfterCopy (Site originalSite, Site createdSite) throws AmetysRepositoryException 173 { 174 updateContentsAfterCopy (originalSite, createdSite); 175 updatePagesAfterCopy (originalSite, createdSite); 176 177 Set<String> ids = _updaterEP.getExtensionsIds(); 178 for (String id : ids) 179 { 180 _updaterEP.getExtension(id).updateSite(originalSite, createdSite); 181 } 182 } 183 184 /** 185 * This method re-initializes workflow, updates the site name for web content and updates references to ametys objects on metadata after a site copy 186 * @param initialSite the original site 187 * @param createdSite the created site after copy 188 * @throws AmetysRepositoryException if an error occurs 189 */ 190 public void updateContentsAfterCopy (Site initialSite, Site createdSite) throws AmetysRepositoryException 191 { 192 AmetysObjectIterable<Content> contents = createdSite.getContents(); 193 for (Content content : contents) 194 { 195 String relPath = content.getPath().substring(createdSite.getPath().length() + 1); 196 WebContent initialContent = initialSite.getChild(relPath); 197 198 try 199 { 200 // Re-init workflow 201 if (content instanceof WorkflowAwareContent) 202 { 203 _reinitWorkflow ((WorkflowAwareContent) content); 204 } 205 206 // Update site name 207 if (content instanceof ModifiableSiteAwareAmetysObject) 208 { 209 ((ModifiableSiteAwareAmetysObject) content).setSiteName(createdSite.getName()); 210 } 211 212 // Update references to ametys object on metadata 213 // TODO NEWATTRIBUTEAPI_CONTENT: when all types are implemented, use the method that uses the new API 214 _updateReferencesToAmetysObjects (content.getMetadataHolder(), initialSite, createdSite); 215 216 // Update links in RichText 217 updateLinksInRichText (initialSite, createdSite, initialContent, content); 218 219 // Updaters 220 Set<String> ids = _updaterEP.getExtensionsIds(); 221 for (String id : ids) 222 { 223 _updaterEP.getExtension(id).updateContent(initialSite, createdSite, initialContent, content); 224 } 225 226 // save 227 if (content instanceof ModifiableAmetysObject) 228 { 229 ((ModifiableAmetysObject) content).saveChanges(); 230 } 231 232 // Creates the first version 233 if (content instanceof VersionableAmetysObject) 234 { 235 ((VersionableAmetysObject) content).checkpoint(); 236 } 237 } 238 catch (Exception e) 239 { 240 // Do not make the copy fail. 241 getLogger().warn("[Site copy] An error occured while updating content '" + content.getId() + " after copy from initial content '" + initialContent.getId() + "'", e); 242 } 243 } 244 245 if (createdSite.needsSave()) 246 { 247 createdSite.saveChanges(); 248 } 249 } 250 251 /** 252 * Updates references all references in a content to another one. 253 * @param initialContent the initial content. 254 * @param destContent the destination content. 255 */ 256 public void updateSharedContent(WebContent initialContent, WebContent destContent) 257 { 258 updateSharedContent(initialContent, destContent, true); 259 } 260 261 /** 262 * Updates references all references in a content to another one. 263 * @param initialContent the initial content. 264 * @param destContent the destination content. 265 * @param reinitWorkflow set to 'true' to reinitialize the workflow 266 */ 267 public void updateSharedContent(WebContent initialContent, WebContent destContent, boolean reinitWorkflow) 268 { 269 Site initialSite = initialContent.getSite(); 270 Site createdSite = destContent.getSite(); 271 272 // Re-init workflow 273 if (reinitWorkflow && destContent instanceof WorkflowAwareContent) 274 { 275 _reinitWorkflow((WorkflowAwareContent) destContent); 276 } 277 278 // Update references to ametys object on metadata 279 // TODO NEWATTRIBUTEAPI_CONTENT: when all types are implemented, use the method that uses the new API 280 _updateReferencesToAmetysObjects(destContent.getMetadataHolder(), initialContent, destContent); 281 282 // Update links in RichText 283 updateLinksInRichText(initialContent, destContent, initialContent, destContent); 284 285 // Updaters 286 Set<String> ids = _updaterEP.getExtensionsIds(); 287 for (String id : ids) 288 { 289 _updaterEP.getExtension(id).updateContent(initialSite, createdSite, initialContent, destContent); 290 } 291 292 // save 293 if (destContent instanceof ModifiableAmetysObject) 294 { 295 ((ModifiableAmetysObject) destContent).saveChanges(); 296 } 297 298 // Creates the first version 299 if (destContent instanceof VersionableAmetysObject) 300 { 301 ((VersionableAmetysObject) destContent).checkpoint(); 302 } 303 } 304 305 /** 306 * This method analyzes content rich texts and update links if necessary 307 * @param initialAO The initial object copied 308 * @param createdAO The target object 309 * @param initialContent The initial content 310 * @param createdContent The created content after copy to update 311 * @throws AmetysRepositoryException if an error occurs 312 */ 313 public void updateLinksInRichText (TraversableAmetysObject initialAO, TraversableAmetysObject createdAO, Content initialContent, Content createdContent) throws AmetysRepositoryException 314 { 315 SAXParser saxParser = null; 316 try 317 { 318 saxParser = (SAXParser) _manager.lookup(SAXParser.ROLE); 319 320 Map<String, Object> params = new HashMap<>(); 321 params.put("initialContent", initialContent); 322 params.put("createdContent", createdContent); 323 params.put("initialAO", initialAO); 324 params.put("createdAO", createdAO); 325 326 CompositeMetadata metadataHolder = createdContent.getMetadataHolder(); 327 String[] metadataNames = metadataHolder.getMetadataNames(); 328 for (String metadataName : metadataNames) 329 { 330 if (metadataHolder.hasMetadata(metadataName) && metadataHolder.getType(metadataName).equals(MetadataType.RICHTEXT)) 331 { 332 MetadataDefinition metadataDef = _contentTypesHelper.getMetadataDefinition(metadataName, createdContent); 333 334 ModifiableRichText richText = (ModifiableRichText) metadataHolder.getRichText(metadataName); 335 336 String referenceContentType = metadataDef.getReferenceContentType(); 337 ContentType contentType = _cTypeEP.getExtension(referenceContentType); 338 RichTextUpdater richTextUpdater = contentType.getRichTextUpdater(); 339 340 if (richTextUpdater != null) 341 { 342 try (InputStream is = richText.getInputStream(); OutputStream os = richText.getOutputStream()) 343 { 344 // create a transformer for saving sax into a file 345 TransformerHandler th = ((SAXTransformerFactory) TransformerFactory.newInstance()).newTransformerHandler(); 346 347 // create the result where to write 348 StreamResult result = new StreamResult(os); 349 th.setResult(result); 350 351 // create the format of result 352 Properties format = new Properties(); 353 format.put(OutputKeys.METHOD, "xml"); 354 format.put(OutputKeys.INDENT, "yes"); 355 format.put(OutputKeys.ENCODING, "UTF-8"); 356 format.put(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "2"); 357 th.getTransformer().setOutputProperties(format); 358 359 ContentHandler richTextHandler = richTextUpdater.getContentHandler(th, th, params); 360 saxParser.parse(new InputSource(is), richTextHandler); 361 } 362 } 363 364 } 365 } 366 367 // Outgoing references 368 if (createdContent instanceof ModifiableContent) 369 { 370 Map<String, OutgoingReferences> outgoingReferencesByPath = _outgoingReferencesExtractor.getOutgoingReferences(createdContent); 371 ((ModifiableContent) createdContent).setOutgoingReferences(outgoingReferencesByPath); 372 373 } 374 } 375 catch (Exception e) 376 { 377 // Do not failed the copy 378 getLogger().warn("An error occured while updating links in RichText for content '" + createdContent.getId() + " after copy from initial content '" + initialContent.getId() + "'", e); 379 } 380 finally 381 { 382 _manager.release(saxParser); 383 } 384 } 385 386 /** 387 * This method updates the site name of pages and updates references to ametys objects on page's metadata after a site copy 388 * @param originalSite the original site 389 * @param createdSite the created site after copy 390 * @throws AmetysRepositoryException if an error occurs 391 */ 392 public void updatePagesAfterCopy (Site originalSite, Site createdSite) throws AmetysRepositoryException 393 { 394 AmetysObjectIterable<Sitemap> sitemaps = createdSite.getSitemaps(); 395 396 for (Sitemap sitemap : sitemaps) 397 { 398 for (Page page : sitemap.getChildrenPages()) 399 { 400 _updatePageAfterCopy (originalSite, createdSite, page); 401 } 402 } 403 } 404 405 private void _updatePageAfterCopy (Site originalSite, Site createdSite, Page page) throws AmetysRepositoryException 406 { 407 try 408 { 409 // Update site name 410 if (page instanceof ModifiablePage) 411 { 412 ((ModifiablePage) page).setSiteName(createdSite.getName()); 413 } 414 415 // Update references to ametys object on metadata 416 _updateReferencesToAmetysObjects (page, originalSite, createdSite); 417 418 for (Zone zone : page.getZones()) 419 { 420 _updateReferencesToAmetysObjects (zone, originalSite, createdSite); 421 422 for (ZoneItem zoneItem : zone.getZoneItems()) 423 { 424 _updateReferencesToAmetysObjects (zoneItem, originalSite, createdSite); 425 426 if (zoneItem.getType().equals(ZoneType.SERVICE)) 427 { 428 _updateReferencesToAmetysObjects (zoneItem.getServiceParameters(), originalSite, createdSite); 429 } 430 else if (zoneItem.getType().equals(ZoneType.CONTENT) && zoneItem instanceof ModifiableZoneItem) 431 { 432 Content content = zoneItem.getContent(); 433 String path = content.getPath(); 434 435 String originalPath = originalSite.getPath(); 436 if (path.startsWith(originalPath)) 437 { 438 String relPath = path.substring(originalPath.length() + 1); 439 try 440 { 441 // Find symmetric object on copied sub-tree 442 Content child = createdSite.getChild(relPath); 443 ((ModifiableZoneItem) zoneItem).setContent(child); 444 } 445 catch (UnknownAmetysObjectException e) 446 { 447 // Nothing 448 } 449 } 450 } 451 } 452 } 453 } 454 catch (AmetysRepositoryException e) 455 { 456 // Do not failed the copy 457 getLogger().warn("An error occured while updating page '" + page.getId() + "' (" + page.getPathInSitemap() + ") after copy", e); 458 } 459 460 // Browse child pages 461 for (Page childPage : page.getChildrenPages()) 462 { 463 _updatePageAfterCopy (originalSite, createdSite, childPage); 464 } 465 466 // Updaters 467 Set<String> ids = _updaterEP.getExtensionsIds(); 468 for (String id : ids) 469 { 470 _updaterEP.getExtension(id).updatePage(originalSite, createdSite, page); 471 } 472 } 473 474 private void _updateReferencesToAmetysObjects (DataHolder dataHolder, TraversableAmetysObject originalAO, TraversableAmetysObject createdAO) 475 { 476 try 477 { 478 for (String dataName : dataHolder.getDataNames()) 479 { 480 if (ModelItemTypeConstants.COMPOSITE_TYPE_ID.equals(_getDataTypeID(dataHolder, dataName))) 481 { 482 _updateReferencesToAmetysObjects(dataHolder.getComposite(dataName), originalAO, createdAO); 483 } 484 else if (ModelItemTypeConstants.REPEATER_TYPE_ID.equals(_getDataTypeID(dataHolder, dataName))) 485 { 486 Repeater repeater = dataHolder.getRepeater(dataName); 487 for (RepeaterEntry entry : repeater.getEntries()) 488 { 489 _updateReferencesToAmetysObjects(entry, originalAO, createdAO); 490 } 491 } 492 else if (_isAmetysObject(dataHolder, dataName)) 493 { 494 _updateReferenceToAmetysObject(dataHolder, dataName, originalAO, createdAO); 495 } 496 } 497 } 498 catch (UndefinedItemPathException | UnknownDataException | UnknownTypeException | NotUniqueTypeException e) 499 { 500 // The type of the data has not been determined so there is no way to determine if it is a reference to an ametys object 501 } 502 503 } 504 505 private void _updateReferenceToAmetysObject (DataHolder dataHolder, String dataName, TraversableAmetysObject originalAO, TraversableAmetysObject createdAO) throws AmetysRepositoryException 506 { 507 if (dataHolder instanceof ModifiableDataHolder) 508 { 509 if (_isDataMultiple(dataHolder, dataName)) 510 { 511 String[] ids = _getStringValue(dataHolder, dataName); 512 List<String> newReferences = new ArrayList<>(); 513 for (String id : ids) 514 { 515 String newReference = _getNewReferenceToAmetysObject(originalAO, createdAO, id); 516 if (newReference != null) 517 { 518 newReferences.add(newReference); 519 } 520 else 521 { 522 newReferences.add(id); 523 } 524 } 525 526 _setStringValue((ModifiableDataHolder) dataHolder, dataName, newReferences.toArray(new String[newReferences.size()])); 527 } 528 else 529 { 530 String id = _getStringValue(dataHolder, dataName); 531 String newReference = _getNewReferenceToAmetysObject(originalAO, createdAO, id); 532 if (newReference != null) 533 { 534 _setStringValue((ModifiableDataHolder) dataHolder, dataName, newReference); 535 } 536 } 537 } 538 } 539 540 private String _getNewReferenceToAmetysObject(TraversableAmetysObject originalAO, TraversableAmetysObject createdAO, String id) 541 { 542 AmetysObject ametysObject = _resolver.resolveById(id); 543 String path = ametysObject.getPath(); 544 545 String originalPath = originalAO.getPath(); 546 if (path.startsWith(originalPath + "/")) 547 { 548 String relPath = path.substring(originalPath.length() + 1); 549 try 550 { 551 // Find symmetric object on copied sub-tree 552 AmetysObject child = createdAO.getChild(relPath); 553 return child.getId(); 554 } 555 catch (UnknownAmetysObjectException e) 556 { 557 getLogger().warn("Object of path " + relPath + " was not found on copied sub-tree " + createdAO.getPath(), e); 558 return null; 559 } 560 catch (AmetysRepositoryException e) 561 { 562 getLogger().error("Unable to retrieve object of path " + relPath + " on copied sub-tree " + createdAO.getPath(), e); 563 return null; 564 } 565 } 566 else 567 { 568 return null; 569 } 570 } 571 572 @SuppressWarnings("static-access") 573 private boolean _isAmetysObject (DataHolder dataHolder, String dataName) 574 { 575 try 576 { 577 if (ModelItemTypeConstants.STRING_TYPE_ID.equals(_getDataTypeID(dataHolder, dataName))) 578 { 579 if (_isDataMultiple(dataHolder, dataName)) 580 { 581 String[] values = _getStringValue(dataHolder, dataName); 582 for (String value : values) 583 { 584 if (_resolver.hasAmetysObjectForId(value)) 585 { 586 return true; 587 } 588 } 589 590 // None of the value of the multiple data is a reference 591 return false; 592 } 593 else 594 { 595 String value = _getStringValue(dataHolder, dataName); 596 return _resolver.hasAmetysObjectForId(value); 597 } 598 } 599 else 600 { 601 return false; 602 } 603 } 604 catch (AmetysRepositoryException | UndefinedItemPathException | UnknownTypeException | NotUniqueTypeException e) 605 { 606 return false; 607 } 608 } 609 610 private String _getDataTypeID(DataHolder dataHolder, String dataName) throws UndefinedItemPathException, UnknownDataException, UnknownTypeException, NotUniqueTypeException 611 { 612 return dataHolder instanceof ModelAwareDataHolder ? ((ModelAwareDataHolder) dataHolder).getType(dataName).getId() : ((ModelLessDataHolder) dataHolder).getType(dataName).getId(); 613 } 614 615 private boolean _isDataMultiple(DataHolder dataHolder, String dataName) 616 { 617 return dataHolder instanceof ModelAwareDataHolder ? ((ModelAwareDataHolder) dataHolder).isMultiple(dataName) : ((ModelLessDataHolder) dataHolder).isMultiple(dataName); 618 } 619 620 private <T> T _getStringValue(DataHolder dataHolder, String dataName) 621 { 622 return dataHolder instanceof ModelAwareDataHolder ? ((ModelAwareDataHolder) dataHolder).getValue(dataName) : ((ModelLessDataHolder) dataHolder).getValue(dataName); 623 } 624 625 private void _setStringValue(ModifiableDataHolder dataHolder, String dataName, Object value) 626 { 627 if (dataHolder instanceof ModifiableModelAwareDataHolder) 628 { 629 ((ModifiableModelAwareDataHolder) dataHolder).setValue(dataName, value); 630 } 631 else 632 { 633 ((ModifiableModelLessDataHolder) dataHolder).setValue(dataName, value); 634 } 635 } 636 637 @Deprecated 638 private void _updateReferencesToAmetysObjects (CompositeMetadata metadataHolder, TraversableAmetysObject originalAO, TraversableAmetysObject createdAO) 639 { 640 String[] metadataNames = metadataHolder.getMetadataNames(); 641 for (String metadataName : metadataNames) 642 { 643 if (MetadataType.COMPOSITE.equals(metadataHolder.getType(metadataName))) 644 { 645 _updateReferencesToAmetysObjects (metadataHolder.getCompositeMetadata(metadataName), originalAO, createdAO); 646 } 647 else if (_isAmetysObject(metadataHolder, metadataName)) 648 { 649 _updateReferenceToAmetysObject (metadataHolder, metadataName, originalAO, createdAO); 650 } 651 } 652 } 653 654 @Deprecated 655 private void _updateReferenceToAmetysObject (CompositeMetadata metadataHolder, String metadataName, TraversableAmetysObject originalAO, TraversableAmetysObject createdAO) throws AmetysRepositoryException 656 { 657 if (metadataHolder instanceof ModifiableCompositeMetadata) 658 { 659 String id = metadataHolder.getString(metadataName); 660 661 AmetysObject ametysObject = _resolver.resolveById(id); 662 String path = ametysObject.getPath(); 663 664 String originalPath = originalAO.getPath(); 665 if (path.startsWith(originalPath + "/")) 666 { 667 String relPath = path.substring(originalPath.length() + 1); 668 try 669 { 670 // Find symmetric object on copied sub-tree 671 AmetysObject child = createdAO.getChild(relPath); 672 ((ModifiableCompositeMetadata) metadataHolder).setMetadata(metadataName, child.getId()); 673 } 674 catch (UnknownAmetysObjectException e) 675 { 676 getLogger().warn("Object of path " + relPath + " was not found on copied sub-tree " + createdAO.getPath(), e); 677 } 678 catch (AmetysRepositoryException e) 679 { 680 getLogger().error("Unable to retrieve object of path " + relPath + " on copied sub-tree " + createdAO.getPath(), e); 681 } 682 } 683 } 684 } 685 686 @Deprecated 687 private boolean _isAmetysObject (CompositeMetadata metadataHolder, String metadataName) 688 { 689 try 690 { 691 if (metadataHolder.getType(metadataName).equals(MetadataType.STRING)) 692 { 693 if (metadataHolder.isMultiple(metadataName)) 694 { 695 String[] values = metadataHolder.getStringArray(metadataName); 696 for (String value : values) 697 { 698 if (_resolver.hasAmetysObjectForId(value)) 699 { 700 return true; 701 } 702 } 703 } 704 else 705 { 706 String value = metadataHolder.getString(metadataName); 707 if (_resolver.hasAmetysObjectForId(value)) 708 { 709 return true; 710 } 711 } 712 } 713 714 return false; 715 } 716 catch (AmetysRepositoryException e) 717 { 718 return false; 719 } 720 } 721 722 private void _reinitWorkflow (WorkflowAwareContent content) throws AmetysRepositoryException 723 { 724 try 725 { 726 long wId = content.getWorkflowId(); 727 728 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content); 729 String workflowName = workflow.getWorkflowName(wId); 730 731 // 1 - Delete the cloned workflow 732 WorkflowAwareContentHelper.removeWorkflowId(content); 733 734 // For legacy purpose, delete the workflow reference property if exists (only for contents created on 3.x versions) 735 Node node = content.getNode(); 736 try 737 { 738 if (node.hasProperty(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":workflowRef")) 739 { 740 node.getProperty(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":workflowRef").remove(); 741 } 742 } 743 catch (RepositoryException e) 744 { 745 throw new AmetysRepositoryException("Unable to remove workflowId property", e); 746 } 747 748 workflow.removeWorkflow(wId); 749 750 // 2 - Initialize new workflow instance 751 HashMap<String, Object> inputs = new HashMap<>(); 752 long workflowId = workflow.initialize(workflowName, 0, inputs); 753 content.setWorkflowId(workflowId); 754 755 // Update current step property 756 Step currentStep = (Step) workflow.getCurrentSteps(workflowId).iterator().next(); 757 content.setCurrentStepId(currentStep.getStepId()); 758 } 759 catch (Exception e) 760 { 761 throw new AmetysRepositoryException("Unable to initialize workflow for content " + content.getId(), e); 762 } 763 764 } 765}