001/* 002 * Copyright 2010 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.cms.workflow; 017 018import java.io.IOException; 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.Date; 022import java.util.HashMap; 023import java.util.LinkedHashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.commons.io.IOUtils; 031import org.apache.commons.lang.StringUtils; 032 033import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 034import org.ametys.cms.contenttype.ContentTypesHelper; 035import org.ametys.cms.contenttype.MetadataDefinition; 036import org.ametys.cms.contenttype.MetadataManager; 037import org.ametys.cms.contenttype.RepeaterDefinition; 038import org.ametys.cms.repository.Content; 039import org.ametys.cms.repository.ModifiableWorkflowAwareContent; 040import org.ametys.cms.repository.WorkflowAwareContent; 041import org.ametys.core.user.UserIdentity; 042import org.ametys.core.util.DateUtils; 043import org.ametys.core.util.JSONUtils; 044import org.ametys.plugins.repository.AmetysObjectResolver; 045import org.ametys.plugins.repository.lock.LockHelper; 046import org.ametys.plugins.repository.lock.LockableAmetysObject; 047import org.ametys.plugins.repository.metadata.BinaryMetadata; 048import org.ametys.plugins.repository.metadata.CompositeMetadata; 049import org.ametys.plugins.repository.metadata.File; 050import org.ametys.plugins.repository.metadata.Folder; 051import org.ametys.plugins.repository.metadata.MultilingualString; 052import org.ametys.plugins.repository.metadata.MultilingualStringHelper; 053import org.ametys.plugins.repository.metadata.Resource; 054import org.ametys.plugins.repository.metadata.RichText; 055import org.ametys.plugins.repository.metadata.UnknownMetadataException; 056import org.ametys.plugins.repository.version.VersionableAmetysObject; 057 058import com.opensymphony.module.propertyset.PropertySet; 059import com.opensymphony.workflow.WorkflowException; 060 061/** 062 * OSWorkflow function to restore an old revision of a content. 063 * Builds a Map with the old content's metadata values, and passes it to the 064 * {@link EditContentFunction}, which does the real job. 065 */ 066public class RestoreRevisionFunction extends AbstractContentFunction 067{ 068 069 /** The ametys object resolver. */ 070 protected AmetysObjectResolver _resolver; 071 072 /** The content type extension point. */ 073 protected ContentTypeExtensionPoint _cTypeEP; 074 075 /** The content type helper. */ 076 protected ContentTypesHelper _cTypeHelper; 077 078 /** The JSON conversion utilities. */ 079 protected JSONUtils _jsonUtils; 080 081 @Override 082 public void service(ServiceManager manager) throws ServiceException 083 { 084 super.service(manager); 085 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 086 _cTypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 087 _cTypeHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 088 _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE); 089 } 090 091 @Override 092 public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException 093 { 094 WorkflowAwareContent content = getContent(transientVars); 095 UserIdentity user = getUser(transientVars); 096 097 if (!(content instanceof ModifiableWorkflowAwareContent)) 098 { 099 throw new IllegalArgumentException("The provided content " + content.getId() + " is not a ModifiableWorkflowAwareContent."); 100 } 101 102 ModifiableWorkflowAwareContent modifiableContent = (ModifiableWorkflowAwareContent) content; 103 104 if (content instanceof LockableAmetysObject) 105 { 106 LockableAmetysObject lockableContent = (LockableAmetysObject) content; 107 if (lockableContent.isLocked() && !LockHelper.isLockOwner(lockableContent, user)) 108 { 109 throw new WorkflowException ("The user '" + user + "' try to restore the content '" + content.getId() + "', but this content is locked by the user '" + user + "'"); 110 } 111 else if (lockableContent.isLocked()) 112 { 113 lockableContent.unlock(); 114 } 115 } 116 117 String contentVersion = (String) getContextParameters(transientVars).get("contentVersion"); 118 119 Content oldContent = _resolver.resolveById(content.getId()); 120 if (oldContent instanceof VersionableAmetysObject) 121 { 122 ((VersionableAmetysObject) oldContent).switchToRevision(contentVersion); 123 } 124 125 Map<String, Object> results = getResultsMap(transientVars); 126 Map<String, Object> brokenReferences = new HashMap<>(); 127 results.put("brokenReferences", brokenReferences); 128 129 Map<String, Object> parameters = getContextParameters(transientVars); 130 Map<String, Object> newValues = new HashMap<>(); 131 parameters.put(EditContentFunction.FORM_RAW_VALUES, newValues); 132 133 parameters.put(EditContentFunction.QUIT, Boolean.TRUE); 134 135 // Recursively get the old content's metadata values, and fill the "new values" map with them. 136 // Additionally, detect broken references. 137 processMetadatas(content, oldContent, newValues, brokenReferences); 138 139 modifiableContent.setLastContributor(user); 140 modifiableContent.setLastModified(new Date()); 141 // Remove the proposal date. 142 modifiableContent.setProposalDate(null); 143 144 // Commit changes 145 modifiableContent.saveChanges(); 146 } 147 148 /** 149 * Process the old content metadatas. 150 * @param content the current content (the one being modified). 151 * @param oldContent the old content. 152 * @param newValues the Map to fill with the old content's values. 153 * @param brokenReferences the Map of broken references (which could not be restored). 154 * @throws WorkflowException if an error occurs. 155 */ 156 protected void processMetadatas(Content content, Content oldContent, Map<String, Object> newValues, Map<String, Object> brokenReferences) throws WorkflowException 157 { 158 CompositeMetadata metaHolder = oldContent.getMetadataHolder(); 159 160 // Browse the current content's model. 161 Set<String> metadataNames = _cTypeHelper.getMetadataNames(content); 162 for (String metaName : metadataNames) 163 { 164 MetadataDefinition metaDef = _cTypeHelper.getMetadataDefinition(metaName, content); 165 166 processMetadata(metaHolder, metaName, metaDef, metaName, newValues, brokenReferences); 167 } 168 } 169 170 /** 171 * Process the old content metadatas. 172 * @param metaHolder the source metadata holder. 173 * @param metaDef the metadata definition. 174 * @param metaPath the metadata path. 175 * @param newValues the Map to fill with the old content's values. 176 * @param brokenReferences the Map of broken references (which could not be restored). 177 * @throws WorkflowException if an error occurs. 178 */ 179 protected void processMetadatas(CompositeMetadata metaHolder, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues, Map<String, Object> brokenReferences) throws WorkflowException 180 { 181 Set<String> subMetadataNames = metaDef.getMetadataNames(); 182 for (String subMetaName : subMetadataNames) 183 { 184 MetadataDefinition subMetaDef = metaDef.getMetadataDefinition(subMetaName); 185 String subMetaPath = metaPath + "." + subMetaName; 186 187 processMetadata(metaHolder, subMetaName, subMetaDef, subMetaPath, newValues, brokenReferences); 188 } 189 } 190 191 /** 192 * Process a metadata from the old content. 193 * @param metaHolder the source metadata holder. 194 * @param metaName the metadata name. 195 * @param metaDef the metadata definition. 196 * @param metaPath the metadata path. 197 * @param newValues the Map to fill with the old content's values. 198 * @param brokenReferences the Map of broken references (which could not be restored). 199 * @throws WorkflowException if an error occurs. 200 */ 201 protected void processMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues, Map<String, Object> brokenReferences) throws WorkflowException 202 { 203 if (metaDef != null) 204 { 205 switch (metaDef.getType()) 206 { 207 case STRING: 208 case LONG: 209 case DOUBLE: 210 case BOOLEAN: 211 processStringMetadata(metaHolder, metaName, metaDef, metaPath, newValues); 212 break; 213 case MULTILINGUAL_STRING: 214 processMultilingualStringMetadata(metaHolder, metaName, metaDef, metaPath, newValues); 215 break; 216 case USER: 217 processUserMetadata(metaHolder, metaName, metaDef, metaPath, newValues); 218 break; 219 case DATE: 220 processDateMetadata(metaHolder, metaName, metaDef, metaPath, newValues); 221 break; 222 case DATETIME: 223 processDatetimeMetadata(metaHolder, metaName, metaDef, metaPath, newValues); 224 break; 225 case GEOCODE: 226 processGeocodeMetadata(metaHolder, metaName, metaDef, metaPath, newValues); 227 break; 228 case RICH_TEXT: 229 processRichtextMetadata(metaHolder, metaName, metaDef, metaPath, newValues); 230 break; 231 case BINARY: 232 processBinaryMetadata(metaHolder, metaName, metaDef, metaPath, newValues); 233 break; 234 case FILE: 235 processFileMetadata(metaHolder, metaName, metaDef, metaPath, newValues); 236 break; 237 case REFERENCE: 238 processReferenceMetadata(metaHolder, metaName, metaDef, metaPath, newValues, brokenReferences); 239 break; 240 case CONTENT: 241 processContentMetadata(metaHolder, metaName, metaDef, metaPath, newValues, brokenReferences); 242 break; 243 case SUB_CONTENT: 244 break; 245 case COMPOSITE: 246 processCompositeMetadata(metaHolder, metaName, metaDef, metaPath, newValues, brokenReferences); 247 break; 248 default: 249 break; 250 } 251 } 252 } 253 254 /** 255 * Get the value from a String old content metadata and put it in the new values map. 256 * @param metaHolder the source metadata holder. 257 * @param metaName the metadata name. 258 * @param metaDef the metadata definition. 259 * @param metaPath the metadata path. 260 * @param newValues the Map to fill with the old content's values. 261 */ 262 protected void processStringMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues) 263 { 264 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 265 266 if (metaDef.isMultiple()) 267 { 268 String[] valuesArr = metaHolder.getStringArray(metaName, new String[0]); 269 newValues.put(valueKey, Arrays.asList(valuesArr)); 270 } 271 else 272 { 273 String value = metaHolder.getString(metaName, null); 274 newValues.put(valueKey, value); 275 } 276 } 277 278 /** 279 * Get the value from a Date old content metadata and put it in the new values map. 280 * @param metaHolder the source metadata holder. 281 * @param metaName the metadata name. 282 * @param metaDef the metadata definition. 283 * @param metaPath the metadata path. 284 * @param newValues the Map to fill with the old content's values. 285 */ 286 protected void processDateMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues) 287 { 288 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 289 290 if (metaDef.isMultiple()) 291 { 292 Date[] valuesArr = metaHolder.getDateArray(metaName, new Date[0]); 293 List<String> values = new ArrayList<>(); 294 for (Date value : valuesArr) 295 { 296 values.add(DateUtils.dateToString(value)); 297 } 298 299 newValues.put(valueKey, values); 300 } 301 else 302 { 303 Date value = metaHolder.getDate(metaName, null); 304 newValues.put(valueKey, StringUtils.trimToEmpty(DateUtils.dateToString(value))); 305 } 306 } 307 308 /** 309 * Get the value from a DateTime old content metadata and put it in the new values map. 310 * @param metaHolder the source metadata holder. 311 * @param metaName the metadata name. 312 * @param metaDef the metadata definition. 313 * @param metaPath the metadata path. 314 * @param newValues the Map to fill with the old content's values. 315 */ 316 protected void processDatetimeMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues) 317 { 318 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 319 320 if (metaDef.isMultiple()) 321 { 322 Date[] valuesArr = metaHolder.getDateArray(metaName, new Date[0]); 323 List<String> values = new ArrayList<>(); 324 for (Date value : valuesArr) 325 { 326 values.add(DateUtils.dateToString(value)); 327 } 328 329 newValues.put(valueKey, values); 330 } 331 else 332 { 333 Date value = metaHolder.getDate(metaName, null); 334 newValues.put(valueKey, StringUtils.trimToEmpty(DateUtils.dateToString(value))); 335 } 336 } 337 338 /** 339 * Get the value from a geocode old content metadata and put it in the new values map. 340 * @param metaHolder the source metadata holder. 341 * @param metaName the metadata name. 342 * @param metaDef the metadata definition. 343 * @param metaPath the metadata path. 344 * @param newValues the Map to fill with the old content's values. 345 */ 346 protected void processGeocodeMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues) 347 { 348 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 349 350 Map<String, Object> values = new HashMap<>(); 351 352 try 353 { 354 CompositeMetadata meta = metaHolder.getCompositeMetadata(metaName); 355 356 values.put("longitude", meta.getDouble("longitude")); 357 values.put("latitude", meta.getDouble("latitude")); 358 359 String jsonValues = _jsonUtils.convertObjectToJson(values); 360 361 newValues.put(valueKey, jsonValues); 362 } 363 catch (UnknownMetadataException e) 364 { 365 // The composite metadata doesn't exist: store null 366 newValues.put(valueKey, null); 367 } 368 } 369 370 /** 371 * Get the value from a user old content metadata and put it in the new values map. 372 * @param metaHolder the source metadata holder. 373 * @param metaName the metadata name. 374 * @param metaDef the metadata definition. 375 * @param metaPath the metadata path. 376 * @param newValues the Map to fill with the old content's values. 377 */ 378 protected void processUserMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues) 379 { 380 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 381 382 Map<String, Object> values = new HashMap<>(); 383 384 try 385 { 386 CompositeMetadata meta = metaHolder.getCompositeMetadata(metaName); 387 388 values.put("login", meta.getString("login")); 389 values.put("populationId", meta.getString("populationId")); 390 391 String jsonValues = _jsonUtils.convertObjectToJson(values); 392 393 newValues.put(valueKey, jsonValues); 394 } 395 catch (UnknownMetadataException e) 396 { 397 // The composite metadata doesn't exist: store null 398 newValues.put(valueKey, null); 399 } 400 } 401 402 /** 403 * Get the value from a {@link MultilingualString} old content metadata and put it in the new values map. 404 * @param metaHolder the source metadata holder. 405 * @param metaName the metadata name. 406 * @param metaDef the metadata definition. 407 * @param metaPath the metadata path. 408 * @param newValues the Map to fill with the old content's values. 409 */ 410 protected void processMultilingualStringMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues) 411 { 412 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 413 414 try 415 { 416 MultilingualString meta = metaHolder.getMultilingualString(metaName); 417 418 Map<String, Object> json = MultilingualStringHelper.toJson(meta); 419 420 String jsonValues = _jsonUtils.convertObjectToJson(json); 421 422 newValues.put(valueKey, jsonValues); 423 } 424 catch (UnknownMetadataException e) 425 { 426 // The composite metadata doesn't exist: store null 427 newValues.put(valueKey, null); 428 } 429 } 430 431 /** 432 * Get the value from a RichText old content metadata and put it in the new values map. 433 * @param metaHolder the source metadata holder. 434 * @param metaName the metadata name. 435 * @param metaDef the metadata definition. 436 * @param metaPath the metadata path. 437 * @param newValues the Map to fill with the old content's values. 438 * @throws WorkflowException if an error occurs. 439 */ 440 protected void processRichtextMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues) throws WorkflowException 441 { 442 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 443 String formatKey = EditContentFunction.INTERNAL_FORM_ELEMENTS_PREFIX + metaPath + ".format"; 444 String addDataKey = EditContentFunction.INTERNAL_FORM_ELEMENTS_PREFIX + metaPath + ".additionalData"; 445 446 try 447 { 448 RichText richText = metaHolder.getRichText(metaName); 449 String docbookContent = IOUtils.toString(richText.getInputStream(), "UTF-8"); 450 451 Folder dataFolder = richText.getAdditionalDataFolder(); 452 Map<String, Resource> datas = new LinkedHashMap<>(); 453 for (File file : dataFolder.getFiles()) 454 { 455 datas.put(file.getName(), file.getResource()); 456 } 457 458 newValues.put(valueKey, docbookContent); 459 newValues.put(formatKey, "docbook"); 460 newValues.put(addDataKey, datas); 461 } 462 catch (UnknownMetadataException e) 463 { 464 // The rich-text metadata doesn't exist: store null 465 newValues.put(valueKey, null); 466 } 467 catch (IOException e) 468 { 469 // Error reading the rich-text content. 470 throw new WorkflowException("Error reading the rich-text content for metadata " + metaPath, e); 471 } 472 } 473 474 /** 475 * Get the value from a binary old content metadata and put it in the new values map. 476 * @param metaHolder the source metadata holder. 477 * @param metaName the metadata name. 478 * @param metaDef the metadata definition. 479 * @param metaPath the metadata path. 480 * @param newValues the Map to fill with the old content's values. 481 */ 482 protected void processBinaryMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues) 483 { 484 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 485 String rawValueKey = EditContentFunction.INTERNAL_FORM_ELEMENTS_PREFIX + metaPath + ".rawValue"; 486 487 if (metaHolder.hasMetadata(metaName)) 488 { 489 BinaryMetadata value = metaHolder.getBinaryMetadata(metaName); 490 491 newValues.put(valueKey, EditContentFunction.UNTOUCHED_BINARY); 492 newValues.put(rawValueKey, value); 493 } 494 else 495 { 496 newValues.put(valueKey, null); 497 } 498 } 499 500 /** 501 * Get the value from a File old content metadata and put it in the new values map. 502 * @param metaHolder the source metadata holder. 503 * @param metaName the metadata name. 504 * @param metaDef the metadata definition. 505 * @param metaPath the metadata path. 506 * @param newValues the Map to fill with the old content's values. 507 */ 508 protected void processFileMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues) 509 { 510 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 511 512 if (metaHolder.hasMetadata(metaName)) 513 { 514 Map<String, Object> values = new HashMap<>(); 515 516 if (org.ametys.plugins.repository.metadata.CompositeMetadata.MetadataType.BINARY.equals(metaHolder.getType(metaName))) 517 { 518 BinaryMetadata value = metaHolder.getBinaryMetadata(metaName); 519 values.put("type", "metadata"); 520 values.put("id", "modified"); 521 522 String rawValueKey = EditContentFunction.INTERNAL_FORM_ELEMENTS_PREFIX + metaPath + ".rawValue"; 523 newValues.put(rawValueKey, value); 524 } 525 else 526 { 527 // If it's not a binary, it's an explorer resource ID: process it as a simple string. 528 String value = metaHolder.getString(metaName, null); 529 values.put("type", "explorer"); 530 values.put("id", value); 531 } 532 533 String jsonValues = _jsonUtils.convertObjectToJson(values); 534 newValues.put(valueKey, jsonValues); 535 } 536 else 537 { 538 newValues.put(valueKey, null); 539 } 540 } 541 542 /** 543 * Get the value from a Reference old content metadata and put it in the new values map. 544 * @param metaHolder the source metadata holder. 545 * @param metaName the metadata name. 546 * @param metaDef the metadata definition. 547 * @param metaPath the metadata path. 548 * @param newValues the Map to fill with the old content's values. 549 * @param brokenReferences the Map of broken references (which could not be restored). 550 */ 551 protected void processReferenceMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues, Map<String, Object> brokenReferences) 552 { 553 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 554 555 Map<String, Object> values = new HashMap<>(); 556 557 try 558 { 559 CompositeMetadata meta = metaHolder.getCompositeMetadata(metaName); 560 561 values.put("value", meta.getString("value")); 562 values.put("type", meta.getString("type")); 563 564 String jsonValues = _jsonUtils.convertObjectToJson(values); 565 566 newValues.put(valueKey, jsonValues); 567 } 568 catch (UnknownMetadataException e) 569 { 570 // The composite metadata doesn't exist: store null 571 newValues.put(valueKey, null); 572 } 573 } 574 575 /** 576 * Get the value from a Content old content metadata and put it in the new values map. 577 * @param metaHolder the source metadata holder. 578 * @param metaName the metadata name. 579 * @param metaDef the metadata definition. 580 * @param metaPath the metadata path. 581 * @param newValues the Map to fill with the old content's values. 582 * @param brokenReferences the Map of broken references (which could not be restored). 583 */ 584 protected void processContentMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues, Map<String, Object> brokenReferences) 585 { 586 String valueKey = EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath; 587 588 if (metaDef.isMultiple()) 589 { 590 String[] contentIds = metaHolder.getStringArray(metaName, new String[0]); 591 List<String> validIds = new ArrayList<>(contentIds.length); 592 593 for (String value : contentIds) 594 { 595 if (_resolver.hasAmetysObjectForId(value)) 596 { 597 validIds.add(value); 598 } 599 else if (!brokenReferences.containsKey(metaName)) 600 { 601 brokenReferences.put(metaName, metaDef.getLabel()); 602 } 603 } 604 605 // Set the value (even if it's an empty array, to delete potentially existing values). 606 newValues.put(valueKey, validIds); 607 } 608 else 609 { 610 String value = metaHolder.getString(metaName, null); 611 if (value != null) 612 { 613 if (_resolver.hasAmetysObjectForId(value)) 614 { 615 newValues.put(valueKey, value); 616 } 617 else 618 { 619 brokenReferences.put(metaName, metaDef.getLabel()); 620 } 621 } 622 else 623 { 624 // Set the value even if it's null, to delete a potentially existing value. 625 newValues.put(valueKey, null); 626 } 627 } 628 } 629 630 /** 631 * Get the value from a Composite old content metadata and put it in the new values map. 632 * @param metaHolder the source metadata holder. 633 * @param metaName the metadata name. 634 * @param metaDef the metadata definition. 635 * @param metaPath the metadata path. 636 * @param newValues the Map to fill with the old content's values. 637 * @param brokenReferences the Map of broken references (which could not be restored). 638 * @throws WorkflowException if an error occurs. 639 */ 640 protected void processCompositeMetadata(CompositeMetadata metaHolder, String metaName, MetadataDefinition metaDef, String metaPath, Map<String, Object> newValues, Map<String, Object> brokenReferences) throws WorkflowException 641 { 642 if (metaDef instanceof RepeaterDefinition) 643 { 644 if (metaHolder.hasMetadata(metaName)) 645 { 646 CompositeMetadata repeaterMetaHolder = metaHolder.getCompositeMetadata(metaName); 647 648 String[] entryNames = repeaterMetaHolder.getMetadataNames(); 649 Arrays.sort(entryNames, MetadataManager.REPEATER_ENTRY_COMPARATOR); 650 651 newValues.put("_" + EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath + ".size", Integer.toString(entryNames.length)); 652 653 if (entryNames.length < 1) 654 { 655 newValues.put(EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath, null); 656 } 657 658 for (String entryName : entryNames) 659 { 660 CompositeMetadata entryMetaHolder = repeaterMetaHolder.getCompositeMetadata(entryName); 661 String entryPath = metaPath + "." + entryName; 662 663 processMetadatas(entryMetaHolder, metaDef, entryPath, newValues, brokenReferences); 664 } 665 } 666 else 667 { 668 newValues.put(EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath, null); 669 newValues.put("_" + EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath + ".size", "0"); 670 } 671 } 672 else 673 { 674 if (metaHolder.hasMetadata(metaName)) 675 { 676 CompositeMetadata compositeMetaHolder = metaHolder.getCompositeMetadata(metaName); 677 processMetadatas(compositeMetaHolder, metaDef, metaPath, newValues, brokenReferences); 678 } 679 else 680 { 681 newValues.put(EditContentFunction.FORM_ELEMENTS_PREFIX + metaPath, null); 682 } 683 } 684 } 685 686}