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