001/* 002 * Copyright 2018 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 */ 016 017package org.ametys.plugins.contenttypeseditor.edition; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.OutputStream; 022import java.net.MalformedURLException; 023import java.nio.charset.Charset; 024import java.util.ArrayList; 025import java.util.HashMap; 026import java.util.HashSet; 027import java.util.LinkedHashMap; 028import java.util.List; 029import java.util.Map; 030import java.util.Map.Entry; 031import java.util.Properties; 032import java.util.Set; 033import java.util.stream.Collectors; 034 035import javax.xml.parsers.SAXParserFactory; 036import javax.xml.transform.OutputKeys; 037import javax.xml.transform.TransformerFactory; 038import javax.xml.transform.sax.SAXTransformerFactory; 039import javax.xml.transform.sax.TransformerHandler; 040import javax.xml.transform.stream.StreamResult; 041 042import org.apache.avalon.framework.component.Component; 043import org.apache.avalon.framework.configuration.Configuration; 044import org.apache.avalon.framework.configuration.ConfigurationException; 045import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 046import org.apache.avalon.framework.service.ServiceException; 047import org.apache.avalon.framework.service.ServiceManager; 048import org.apache.avalon.framework.service.Serviceable; 049import org.apache.cocoon.xml.AttributesImpl; 050import org.apache.cocoon.xml.XMLUtils; 051import org.apache.commons.io.IOUtils; 052import org.apache.commons.lang.StringUtils; 053import org.apache.excalibur.source.ModifiableSource; 054import org.apache.excalibur.source.Source; 055import org.apache.excalibur.source.SourceNotFoundException; 056import org.apache.excalibur.source.SourceResolver; 057import org.apache.excalibur.source.SourceUtil; 058import org.apache.xml.serializer.OutputPropertiesFactory; 059import org.xml.sax.SAXException; 060 061import org.ametys.cms.contenttype.AbstractMetadataSetElement; 062import org.ametys.cms.contenttype.ContentType; 063import org.ametys.cms.contenttype.ContentTypeDefinition; 064import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 065import org.ametys.cms.contenttype.EditContentTypeException; 066import org.ametys.cms.contenttype.EditContentTypeHelper; 067import org.ametys.cms.contenttype.Fieldset; 068import org.ametys.cms.contenttype.MetadataDefinition; 069import org.ametys.cms.contenttype.MetadataDefinitionReference; 070import org.ametys.cms.contenttype.MetadataSet; 071import org.ametys.cms.contenttype.MetadataType; 072import org.ametys.cms.contenttype.RepeaterDefinition; 073import org.ametys.runtime.i18n.I18nizableText; 074import org.ametys.runtime.parameter.DefaultValidator; 075import org.ametys.runtime.parameter.StaticEnumerator; 076import org.ametys.runtime.parameter.Validator; 077import org.ametys.runtime.plugin.component.AbstractLogEnabled; 078 079/** 080 * This component save a content type 081 */ 082public class SaveContentTypeComponent extends AbstractLogEnabled implements Component, Serviceable 083{ 084 /** The Avalon role name */ 085 public static final String ROLE = SaveContentTypeComponent.class.getName(); 086 087 /** The directory path of application i18n key */ 088 private static final String __I18N_CATALOG_DIR = "context://WEB-INF/i18n/"; 089 090 /** The path of rights on content types */ 091 private static final String __RIGHTS_FILE = "context://WEB-INF/param/rights.xml"; 092 093 /** The right category of a content type */ 094 private static final String __RIGHT_CATEGORY = "plugin.cms:PLUGINS_CMS_RIGHTS_CONTENT_CATEGORY"; 095 096 /** The url to save the right of content type */ 097 private static final String __SAVE_CONTENT_TYPE_RIGHT = "cocoon://_plugins/contenttypes-editor/save/content-type-right"; 098 099 /** The name of the default i18n catalogue */ 100 private static final String __DEFAULT_CATALOGUE = "application"; 101 102 /** The source resolver */ 103 protected SourceResolver _sourceResolver; 104 105 /** The content type extension point instance */ 106 protected ContentTypeExtensionPoint _contentTypeExtensionPoint; 107 108 /** The content type state instance */ 109 protected ContentTypeStateComponent _contentTypeStateComponent; 110 111 /** The edit content type helper instance */ 112 protected EditContentTypeInformationHelper _editContentTypeInformationHelper; 113 114 /** The edit content type component instance */ 115 protected EditContentTypeHelper _editContentTypeHelper; 116 117 /** Representation of i18n catalog according to the language */ 118 private Map<String, I18nCatalog> _i18nCatalogs = new HashMap<>(); 119 120 private List<TranslatedValue> _translatedValues; 121 122 private int _fieldsetNumber; 123 124 public void service(ServiceManager manager) throws ServiceException 125 { 126 _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 127 _contentTypeExtensionPoint = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 128 _contentTypeStateComponent = (ContentTypeStateComponent) manager.lookup(ContentTypeStateComponent.ROLE); 129 _editContentTypeInformationHelper = (EditContentTypeInformationHelper) manager.lookup(EditContentTypeInformationHelper.ROLE); 130 _editContentTypeHelper = (EditContentTypeHelper) manager.lookup(org.ametys.cms.contenttype.EditContentTypeHelper.ROLE); 131 } 132 133 /** 134 * Save content type 135 * 136 * @param contentTypeInfos all information about the content type to save 137 * @return True if the content type was successfully saved 138 */ 139 public boolean saveContentType(Map<String, Object> contentTypeInfos) 140 { 141 boolean success = true; 142 this._translatedValues = new ArrayList<>(); 143 144 String realContentTypeId = contentTypeInfos.get("id").toString(); 145 ContentTypeDefinition contentTypeDefinition = _getContentTypeDefinition(contentTypeInfos); 146 147 // Sax content type file 148 if (_contentTypeStateComponent.getContentTypeMarkedAsNew().contains(realContentTypeId)) 149 { 150 try 151 { 152 _editContentTypeHelper.createContentType(contentTypeDefinition); 153 154 // Sax right param 155 if (success) 156 { 157 try 158 { 159 // Adding right in param/rights.xml 160 if (contentTypeDefinition.getRight() != null) 161 { 162 String pluginName = contentTypeInfos.get("pluginName").toString(); 163 String idKey = _generateContentTypeIdKey(realContentTypeId); 164 String rightLabelKey = _generateI18nKey(pluginName, "right_create", idKey, "label"); 165 String rightDescriptionKey = _generateI18nKey(pluginName, "right_create", idKey, "description"); 166 _saxRightsParam(contentTypeDefinition.getRight(), rightLabelKey, rightDescriptionKey); 167 } 168 } 169 catch (Exception e) 170 { 171 getLogger().error("Error when trying to save the right of new content type '" + realContentTypeId + "'", e); 172 success = false; 173 } 174 } 175 } 176 catch (EditContentTypeException e) 177 { 178 success = false; 179 } 180 } 181 else 182 { 183 try 184 { 185 _editContentTypeHelper.editContentType(contentTypeDefinition); 186 } 187 catch (EditContentTypeException e) 188 { 189 success = false; 190 } 191 } 192 193 // Sax i18n catalog 194 if (success) 195 { 196 try 197 { 198 // Adding i18n key to catalog 199 Map<String, Map<String, String>> i18nMessageTranslations = _createNewI18nCatalogs(); 200 _saxCatalogs(i18nMessageTranslations); 201 } 202 catch (Exception e) 203 { 204 getLogger().error("Error when trying to save i18n key of new content type '" + realContentTypeId + "'", e); 205 success = false; 206 } 207 } 208 209 return success; 210 } 211 212 private ContentTypeDefinition _getContentTypeDefinition(Map<String, Object> contentTypeInfos) 213 { 214 String realContentTypeId = contentTypeInfos.get("id").toString(); 215 String contentTypeId = realContentTypeId.replaceFirst("content-type.", ""); 216 String pluginName = contentTypeInfos.get("pluginName").toString(); 217 218 ContentType existingContentType = _contentTypeExtensionPoint.getExtension(realContentTypeId); 219 220 ContentTypeDefinition contentType = new ContentTypeDefinition(contentTypeInfos.get("id").toString()); 221 contentType.setPluginName(pluginName); 222 _addGeneralInformation(contentType, existingContentType, contentTypeInfos, pluginName, contentTypeId); 223 _addMetadata(contentType, existingContentType, contentTypeInfos, pluginName, realContentTypeId); 224 _addMetadataSet(contentType, contentTypeInfos, pluginName, contentTypeId); 225 226 return contentType; 227 } 228 229 private void _addGeneralInformation(ContentTypeDefinition contentType, ContentType existingContentType, Map<String, Object> contentTypeInfos, String pluginName, String contentTypeId) 230 { 231 I18nizableText label = _getI18nizableText(existingContentType != null ? existingContentType.getLabel() : null, contentTypeInfos.get("label"), pluginName, "contenttype", contentTypeId, "label"); 232 contentType.setLabel(label); 233 234 I18nizableText defaultTitle = _getI18nizableText(existingContentType != null ? existingContentType.getDefaultTitle() : null, contentTypeInfos.get("defaultTitle"), pluginName, "contenttype", contentTypeId, "default_title"); 235 contentType.setDefaultTitle(defaultTitle); 236 237 I18nizableText description = _getI18nizableText(existingContentType != null ? existingContentType.getDescription() : null, contentTypeInfos.get("description"), pluginName, "contenttype", contentTypeId, "description"); 238 contentType.setDescription(description); 239 240 _addCategory(contentType, contentTypeInfos.get("category"), contentTypeInfos.get("newCategory"), pluginName); 241 242 _addIconGlyph(contentType, contentTypeInfos.get("iconGlyph")); 243 244 _addTags(contentType, contentTypeInfos.get("tags"), contentTypeInfos.get("private"), contentTypeInfos.get("referencetable"), contentTypeInfos.get("mixin")); 245 246 _addSupertypeIds(contentType, contentTypeInfos.get("superTypes")); 247 248 _addIsAbstract(contentType, contentTypeInfos.get("abstract")); 249 250 _addRight(contentType, contentTypeId, pluginName); 251 } 252 253 private void _addCategory(ContentTypeDefinition contentTypeDefinition, Object recoveredCategory, Object recoveredNewCategory, String pluginName) 254 { 255 if (recoveredCategory != null) 256 { 257 if (recoveredCategory instanceof Map) 258 { 259 Map categoryMap = (Map) recoveredCategory; 260 if (!categoryMap.isEmpty()) 261 { 262 Object isNewObject = categoryMap.get("isNew"); 263 if (isNewObject != null && isNewObject instanceof Boolean) 264 { 265 I18nizableText category = null; 266 boolean isNew = (Boolean) isNewObject; 267 if (isNew) 268 { 269 category = _getNewCategory(recoveredNewCategory, pluginName); 270 } 271 else 272 { 273 category = _getExistingCategory(categoryMap); 274 } 275 contentTypeDefinition.setCategory(category); 276 } 277 } 278 } 279 } 280 } 281 282 private I18nizableText _getNewCategory(Object recoveredNewCategory, String pluginName) 283 { 284 I18nizableText category = null; 285 286 if (recoveredNewCategory != null && recoveredNewCategory instanceof Map) 287 { 288 Map newCategory = (Map) recoveredNewCategory; 289 290 if (!newCategory.isEmpty()) 291 { 292 Object i18n = newCategory.get("isMultilingual"); 293 if (i18n instanceof Boolean) 294 { 295 boolean isI18n = (boolean) i18n; 296 if (isI18n) 297 { 298 Object recoveredI18nValues = newCategory.get("values"); 299 if (recoveredI18nValues != null && recoveredI18nValues instanceof Map) 300 { 301 Map i18nValues = (Map) recoveredI18nValues; 302 303 String categoryKey = _generateCategoryI18nKey(pluginName, newCategory); 304 category = new I18nizableText("plugin.contenttypes-editor", categoryKey); 305 306 // Add key and values to the TranslatedValue object 307 TranslatedValue translatedValue = new TranslatedValue(categoryKey, i18nValues); 308 _translatedValues.add(translatedValue); 309 } 310 } 311 else 312 { 313 Object value = newCategory.get("values"); 314 if (value instanceof String) 315 { 316 category = new I18nizableText((String) value); 317 } 318 } 319 _editContentTypeInformationHelper.addNewCategory(newCategory); 320 } 321 } 322 } 323 324 return category; 325 } 326 327 private I18nizableText _getExistingCategory(Map categoryMap) 328 { 329 I18nizableText category = null; 330 Object i18n = categoryMap.get("isMultilingual"); 331 if (i18n instanceof Boolean) 332 { 333 boolean isI18n = (boolean) i18n; 334 if (isI18n) 335 { 336 Object recoveredKey = categoryMap.get("key"); 337 Object recoveredCatalogue = categoryMap.get("catalogue"); 338 if (recoveredKey instanceof String && recoveredCatalogue instanceof String) 339 { 340 category = new I18nizableText((String) recoveredCatalogue, (String) recoveredKey); 341 } 342 } 343 else 344 { 345 Object value = categoryMap.get("values"); 346 if (value instanceof String) 347 { 348 category = new I18nizableText((String) value); 349 } 350 } 351 } 352 return category; 353 } 354 355 private void _addIconGlyph(ContentTypeDefinition contentTypeDefinition, Object recoverIconGlyph) 356 { 357 if (recoverIconGlyph instanceof String) 358 { 359 String icon = (String) recoverIconGlyph; 360 if (StringUtils.isNotBlank(icon)) 361 { 362 contentTypeDefinition.setIconGlyph(icon); 363 } 364 } 365 } 366 367 private void _addTags(ContentTypeDefinition contentTypeDefinition, Object recoverTags, Object recoverIsPrivate, Object recoverIsReferenceTable, Object recoverIsMixin) 368 { 369 Set<String> tags = new HashSet<>(); 370 if (recoverTags != null && recoverTags instanceof String) 371 { 372 String[] tagArray = ((String) recoverTags).split(","); 373 for (String tag : tagArray) 374 { 375 if (StringUtils.isNotBlank(tag)) 376 { 377 tags.add(tag); 378 } 379 } 380 } 381 if (recoverIsPrivate != null && recoverIsPrivate instanceof Boolean && (boolean) recoverIsPrivate) 382 { 383 tags.add("private"); 384 } 385 if (recoverIsReferenceTable != null && recoverIsReferenceTable instanceof Boolean && (boolean) recoverIsReferenceTable) 386 { 387 tags.add("reference-table"); 388 } 389 if (recoverIsMixin != null && recoverIsMixin instanceof Boolean && (boolean) recoverIsMixin) 390 { 391 tags.add("mixin"); 392 } 393 394 if (!tags.isEmpty()) 395 { 396 contentTypeDefinition.setTags(tags); 397 } 398 } 399 400 private void _addSupertypeIds(ContentTypeDefinition contentTypeDefinition, Object recoverSupertypes) 401 { 402 if (recoverSupertypes != null && recoverSupertypes instanceof List) 403 { 404 List<LinkedHashMap<String, String>> supertypes = (List<LinkedHashMap<String, String>>) recoverSupertypes; 405 List<String> supertypeIds = new ArrayList<>(); 406 supertypeIds = supertypes.stream().map(s -> s.get("id")).collect(Collectors.toList()); 407 contentTypeDefinition.setSupertypeIds(supertypeIds.toArray(new String[supertypeIds.size()])); 408 } 409 } 410 411 private void _addIsAbstract(ContentTypeDefinition contentTypeDefinition, Object recoverIsAbstract) 412 { 413 boolean isAbstract = recoverIsAbstract != null && recoverIsAbstract instanceof Boolean && (boolean) recoverIsAbstract; 414 contentTypeDefinition.setIsAbstract(isAbstract); 415 } 416 417 private void _addRight(ContentTypeDefinition contentTypeDefinition, String contentTypeId, String pluginName) 418 { 419 String right = pluginName + "_Right_" + _generateContentTypeIdKey(contentTypeId) + "_Create"; 420 contentTypeDefinition.setRight(right); 421 } 422 423 private void _addMetadata(ContentTypeDefinition contentType, ContentType existingContentType, Map<String, Object> contentTypeInfos, String pluginName, String realContentTypeId) 424 { 425 Object recoverMetadataList = contentTypeInfos.get("metadata"); 426 if (recoverMetadataList != null && recoverMetadataList instanceof List) 427 { 428 List metadataList = (List) recoverMetadataList; 429 List<MetadataDefinition> metadata = new ArrayList<>(); 430 for (Object recoverMetadata : metadataList) 431 { 432 if (recoverMetadata instanceof Map) 433 { 434 Map metadataInfo = (Map) recoverMetadata; 435 Object recoveredReferenceContentTypeId = metadataInfo.get("referenceContentTypeId"); 436 if (recoveredReferenceContentTypeId != null && recoveredReferenceContentTypeId instanceof String 437 && ((String) recoveredReferenceContentTypeId).equals(realContentTypeId)) 438 { 439 // if it's a metadata of current content type 440 Object recoverName = metadataInfo.get("name"); 441 MetadataDefinition metadataDefinition = null; 442 if (existingContentType != null && recoverName instanceof String) 443 { 444 String name = (String) recoverName; 445 metadataDefinition = existingContentType.getMetadataDefinition(name); 446 } 447 String contentTypeId = realContentTypeId.replaceFirst("content-type.", ""); 448 metadata.add(_getMetadata(metadataInfo, metadataDefinition, pluginName, contentTypeId)); 449 } 450 } 451 } 452 contentType.setMetadata(metadata); 453 } 454 } 455 456 private MetadataDefinition _getMetadata(Map<String, Object> metadataInfo, MetadataDefinition existingMetadataDefinition, String pluginName, String contentTypeId) 457 { 458 MetadataDefinition metadataDefinition = null; 459 460 Object recoverType = metadataInfo.get("type"); 461 if (recoverType != null && recoverType instanceof String) 462 { 463 String name = _getString(metadataInfo.get("name")); 464 465 String type = (String) recoverType; 466 if (type.equals("repeater")) 467 { 468 metadataDefinition = _getRepeater(metadataInfo, (RepeaterDefinition) existingMetadataDefinition, name, pluginName, contentTypeId); 469 _addChildrens(metadataDefinition, existingMetadataDefinition, metadataInfo, pluginName, contentTypeId); 470 } 471 else if (type.equals("composite")) 472 { 473 metadataDefinition = new MetadataDefinition(); 474 metadataDefinition.setType(MetadataType.COMPOSITE); 475 _addChildrens(metadataDefinition, existingMetadataDefinition, metadataInfo, pluginName, contentTypeId); 476 } 477 else 478 { 479 metadataDefinition = _getSimpleMetadata(metadataInfo, existingMetadataDefinition, pluginName, contentTypeId, name, type); 480 } 481 482 _addMetadataGeneralInformation(metadataDefinition, existingMetadataDefinition, metadataInfo, name, pluginName, contentTypeId); 483 484 } 485 return metadataDefinition; 486 } 487 488 private RepeaterDefinition _getRepeater(Map<String, Object> metadataInfo, RepeaterDefinition existingRepeaterDefinition, String name, String pluginName, String contentTypeId) 489 { 490 RepeaterDefinition repeater = new RepeaterDefinition(); 491 repeater.setInitialSize(_getInteger(metadataInfo.get("initializeSize"))); 492 repeater.setMinSize(_getInteger(metadataInfo.get("minSize"))); 493 repeater.setMaxSize(_getInteger(metadataInfo.get("maxSize"))); 494 495 I18nizableText addLabel = _getI18nizableText(existingRepeaterDefinition != null ? existingRepeaterDefinition.getAddLabel() : null, metadataInfo.get("addLabel"), pluginName, 496 "contenttype", contentTypeId, "metadata_" + name + "_add_label"); 497 repeater.setAddLabel(addLabel); 498 499 I18nizableText deleteLabel = _getI18nizableText(existingRepeaterDefinition != null ? existingRepeaterDefinition.getDeleteLabel() : null, metadataInfo.get("deleteLabel"), 500 pluginName, "contenttype", contentTypeId, "metadata_" + name + "_delete_label"); 501 repeater.setDeleteLabel(deleteLabel); 502 503 repeater.setType(MetadataType.COMPOSITE); 504 505 return repeater; 506 } 507 508 private MetadataDefinition _getSimpleMetadata(Map<String, Object> metadataInfo, MetadataDefinition existingMetadataDefinition, String pluginName, String contentTypeId, 509 String name, String type) 510 { 511 MetadataDefinition metadataDefinition = new MetadataDefinition(); 512 _addSimpleMetadataType(metadataDefinition, metadataInfo, type); 513 _addWidget(metadataDefinition, metadataInfo, name, pluginName, contentTypeId); 514 _addEnumerator(metadataDefinition, metadataInfo, name, pluginName, contentTypeId); 515 _addValidator(metadataDefinition, existingMetadataDefinition, metadataInfo, name, pluginName, contentTypeId); 516 return metadataDefinition; 517 } 518 519 private void _addSimpleMetadataType(MetadataDefinition metadataDefinition, Map<String, Object> metadataInfo, String type) 520 { 521 MetadataType[] metadataTypes = MetadataType.values(); 522 for (MetadataType metadataType : metadataTypes) 523 { 524 if (metadataType.toString().toLowerCase().equals(type.toLowerCase())) 525 { 526 metadataDefinition.setType(metadataType); 527 if (metadataType == MetadataType.CONTENT) 528 { 529 Object recoverLinkedContentType = metadataInfo.get("linkedContentType"); 530 if (recoverLinkedContentType != null && recoverLinkedContentType instanceof Map) 531 { 532 Map linkedContentType = (Map) recoverLinkedContentType; 533 Object recoverId = linkedContentType.get("id"); 534 if (recoverId != null && recoverId instanceof String) 535 { 536 metadataDefinition.setContentType((String) recoverId); 537 String invert = _getString(metadataInfo.get("invertRelationPath")); 538 metadataDefinition.setInvertRelationPath(invert); 539 } 540 } 541 } 542 break; 543 } 544 } 545 } 546 547 private void _addWidget(MetadataDefinition metadataDefinition, Map<String, Object> metadataInfo, String name, String pluginName, String contentTypeId) 548 { 549 String widget = _getString(metadataInfo.get("widget")); 550 metadataDefinition.setWidget(widget); 551 552 Map<String, I18nizableText> widgetParams = null; 553 Object recoverWidgetParams = metadataInfo.get("widgetParams"); 554 if (recoverWidgetParams != null && recoverWidgetParams instanceof List) 555 { 556 widgetParams = new HashMap<>(); 557 List params = (List) recoverWidgetParams; 558 for (Object recoverWidgetParam : params) 559 { 560 if (recoverWidgetParam != null && recoverWidgetParam instanceof Map) 561 { 562 Map widgetParam = (Map) recoverWidgetParam; 563 String recoverLabel = _getString(widgetParam.get("label")); 564 I18nizableText values = _getI18nizableText(null, widgetParam.get("value"), pluginName, "contentttype", contentTypeId, 565 "metadata_" + name + "_" + recoverLabel + "_widget_param"); 566 widgetParams.put(recoverLabel, values); 567 } 568 } 569 } 570 metadataDefinition.setWidgetParameters(widgetParams); 571 } 572 573 private void _addEnumerator(MetadataDefinition metadataDefinition, Map<String, Object> metadataInfo, String name, String pluginName, String contentTypeId) 574 { 575 String enumeratorName = _getString(metadataInfo.get("customEnumeratorClass")); 576 if (StringUtils.isNotBlank(enumeratorName)) 577 { 578 _addCustomEnumerator(metadataDefinition, metadataInfo, enumeratorName); 579 } 580 else if (metadataInfo.get("defaultEnumerator") != null) 581 { 582 _addDefaultEnumerator(metadataDefinition, metadataInfo, name, pluginName, contentTypeId); 583 } 584 } 585 586 private void _addCustomEnumerator(MetadataDefinition metadataDefinition, Map<String, Object> metadataInfo, String enumeratorName) 587 { 588 metadataDefinition.setCustomEnumerator(enumeratorName); 589 590 String customEnumeratorConfiguration = _getString(metadataInfo.get("customEnumeratorConfiguration")); 591 if (customEnumeratorConfiguration != null) 592 { 593 DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); 594 try 595 { 596 Configuration configuration = builder.build(IOUtils.toInputStream(customEnumeratorConfiguration, Charset.forName("UTF-8"))); 597 metadataDefinition.setEnumeratorConfiguration(configuration); 598 } 599 catch (ConfigurationException | SAXException | IOException e) 600 { 601 getLogger().error("The XML configuration of custom enumerator is not valid", e); 602 } 603 } 604 } 605 606 private void _addDefaultEnumerator(MetadataDefinition metadataDefinition, Map<String, Object> metadataInfo, String name, String pluginName, String contentTypeId) 607 { 608 Object recoverEnumerator = metadataInfo.get("defaultEnumerator"); 609 if (recoverEnumerator instanceof List) 610 { 611 StaticEnumerator staticEnumerator = new StaticEnumerator(); 612 List enumerator = (List) recoverEnumerator; 613 for (Object recoverValue : enumerator) 614 { 615 if (recoverValue != null && recoverValue instanceof Map) 616 { 617 Map value = (Map) recoverValue; 618 Object recoverEnumLabel = value.get("label"); 619 if (recoverEnumLabel != null && recoverEnumLabel instanceof String) 620 { 621 String enumLabel = (String) recoverEnumLabel; 622 Object recoveredEnumValue = value.get("value"); 623 I18nizableText enumValue = _getI18nizableText(null, recoveredEnumValue, pluginName, "contenttype", contentTypeId, 624 "metadata_" + name + "_" + enumLabel + "_enumeration"); 625 staticEnumerator.add(enumValue, enumLabel); 626 } 627 } 628 } 629 metadataDefinition.setEnumerator(staticEnumerator); 630 } 631 } 632 633 private void _addValidator(MetadataDefinition metadataDefinition, MetadataDefinition existingMetadataDefinition, Map<String, Object> metadataInfo, String name, 634 String pluginName, String contentTypeId) 635 { 636 String validatorName = _getString(metadataInfo.get("customValidatorClass")); 637 if (StringUtils.isNotBlank(validatorName)) 638 { 639 _addCustomValidator(metadataDefinition, metadataInfo, validatorName); 640 } 641 else if (metadataInfo.get("defaultValidator") != null) 642 { 643 _addDefaultValidator(metadataDefinition, existingMetadataDefinition, metadataInfo, name, pluginName, contentTypeId); 644 } 645 } 646 647 private void _addCustomValidator(MetadataDefinition metadataDefinition, Map<String, Object> metadataInfo, String validatorName) 648 { 649 metadataDefinition.setCustomValidator(validatorName); 650 651 String customValidatorConfiguration = _getString(metadataInfo.get("customValidatorConfiguration")); 652 if (customValidatorConfiguration != null) 653 { 654 DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); 655 try 656 { 657 Configuration configuration = builder.build(IOUtils.toInputStream(customValidatorConfiguration, Charset.forName("UTF-8"))); 658 metadataDefinition.setValidatorConfiguration(configuration); 659 } 660 catch (ConfigurationException | SAXException | IOException e) 661 { 662 getLogger().error("The XML configuration of custom validator is not valid", e); 663 } 664 } 665 } 666 667 private void _addDefaultValidator(MetadataDefinition metadataDefinition, MetadataDefinition existingMetadataDefinition, Map<String, Object> metadataInfo, String name, 668 String pluginName, String contentTypeId) 669 { 670 Object recoverValidator = metadataInfo.get("defaultValidator"); 671 if (recoverValidator instanceof Map) 672 { 673 Map validator = (Map) recoverValidator; 674 boolean isMandatory = _getBoolean(validator.get("mandatory")); 675 String regexp = _getString(validator.get("regexp")); 676 677 I18nizableText invalidText = null; 678 I18nizableText existingInvalidText = null; 679 Object recoverInvalidText = validator.get("invalidText"); 680 if (recoverInvalidText != null && recoverInvalidText instanceof Map) 681 { 682 if (existingMetadataDefinition != null) 683 { 684 Validator existingValidator = existingMetadataDefinition.getValidator(); 685 Map<String, Object> existingConfiguration = existingValidator.getConfiguration(); 686 if (existingConfiguration.get("invalidText") != null) 687 { 688 existingInvalidText = (I18nizableText) existingConfiguration.get("invalidText"); 689 } 690 } 691 invalidText = _getI18nizableText(existingInvalidText, recoverInvalidText, pluginName, "contenttype", contentTypeId, "metadata_" + name + "validator_invalid_text"); 692 } 693 DefaultValidator defaultValidator = new DefaultValidator(regexp, invalidText, isMandatory); 694 metadataDefinition.setValidator(defaultValidator); 695 } 696 } 697 698 private void _addMetadataGeneralInformation(MetadataDefinition metadataDefinition, MetadataDefinition existingMetadataDefinition, Map<String, Object> metadataInfo, String name, 699 String pluginName, String contentTypeId) 700 { 701 if (metadataDefinition != null) 702 { 703 metadataDefinition.setName(name); 704 705 I18nizableText label = _getI18nizableText(existingMetadataDefinition != null ? existingMetadataDefinition.getLabel() : null, metadataInfo.get("label"), pluginName, 706 "contenttype", contentTypeId, "metadata_" + name + "_label"); 707 metadataDefinition.setLabel(label); 708 709 I18nizableText description = _getI18nizableText(existingMetadataDefinition != null ? existingMetadataDefinition.getLabel() : null, metadataInfo.get("description"), 710 pluginName, "contenttype", contentTypeId, "metadata_" + name + "_description"); 711 metadataDefinition.setDescription(description); 712 713 boolean isMultiple = _getBoolean(metadataInfo.get("multiple")); 714 metadataDefinition.setMultiple(isMultiple); 715 } 716 } 717 718 private void _addChildrens(MetadataDefinition metadataDefinition, MetadataDefinition existingMetadataDefinition, Map<String, Object> metadataInfo, String pluginName, 719 String contentTypeId) 720 { 721 Object recoverChildrens = metadataInfo.get("children"); 722 if (recoverChildrens != null && recoverChildrens instanceof List) 723 { 724 List childrens = (List) recoverChildrens; 725 if (!childrens.isEmpty()) 726 { 727 for (Object recoverChildren : childrens) 728 { 729 if (recoverChildren != null && recoverChildren instanceof Map) 730 { 731 Map children = (Map) recoverChildren; 732 Object recoverName = children.get("name"); 733 MetadataDefinition existingChildrenMetadataDefinition = null; 734 if (existingMetadataDefinition != null && recoverName != null && recoverName instanceof String) 735 { 736 existingChildrenMetadataDefinition = existingMetadataDefinition.getMetadataDefinition((String) recoverName); 737 } 738 MetadataDefinition childrenMetadataDefinition = _getMetadata(children, existingChildrenMetadataDefinition, pluginName, contentTypeId); 739 metadataDefinition.addMetadata(childrenMetadataDefinition); 740 } 741 } 742 } 743 } 744 } 745 746 private void _addMetadataSet(ContentTypeDefinition contentTypeDefinition, Map<String, Object> contentTypeInfos, String pluginName, String contentTypeId) 747 { 748 Object recoverMetadataSets = contentTypeInfos.get("metadataSets"); 749 if (recoverMetadataSets != null && recoverMetadataSets instanceof List) 750 { 751 List<AbstractMetadataSetElement> metadataSetList = new ArrayList<>(); 752 List metadataSets = (List) recoverMetadataSets; 753 754 _fieldsetNumber = 1; 755 for (Object recoverMetadataSet : metadataSets) 756 { 757 if (recoverMetadataSet != null && recoverMetadataSet instanceof Map) 758 { 759 Map metadataSetInfo = (Map) recoverMetadataSet; 760 Object recoverMetadataSetName = metadataSetInfo.get("name"); 761 if (recoverMetadataSetName != null && recoverMetadataSetName instanceof String) 762 { 763 String metadataSetName = (String) recoverMetadataSetName; 764 Object recoverIsMetadataSetEdition = metadataSetInfo.get("isEdition"); 765 if (recoverIsMetadataSetEdition != null && recoverIsMetadataSetEdition instanceof Boolean) 766 { 767 boolean isMetadataSetEdition = (boolean) recoverIsMetadataSetEdition; 768 metadataSetList.add(_getMetadataSet(contentTypeDefinition, metadataSetInfo, metadataSetName, isMetadataSetEdition, pluginName, contentTypeId)); 769 } 770 } 771 } 772 } 773 contentTypeDefinition.setMetadataSet(metadataSetList); 774 } 775 } 776 777 private AbstractMetadataSetElement _getMetadataSet(ContentTypeDefinition contentTypeDefinition, Map<String, Object> metadataSetInfo, String metadataSetName, 778 boolean isMetadataSetEdition, String pluginName, String contentTypeId) 779 { 780 AbstractMetadataSetElement metadataSet = null; 781 782 String dataType = _getString(metadataSetInfo.get("dataType")); 783 if (StringUtils.isNotBlank(dataType)) 784 { 785 if (dataType.equals("metadata_set")) 786 { 787 metadataSet = _getMetadataSetDataType(contentTypeDefinition, metadataSetInfo, metadataSetName, isMetadataSetEdition, pluginName, contentTypeId); 788 } 789 else if (dataType.equals("fieldset")) 790 { 791 metadataSet = _getFieldSetDataType(contentTypeDefinition, metadataSetInfo, metadataSetName, isMetadataSetEdition, pluginName, contentTypeId); 792 } 793 else if (dataType.equals("metadata_ref")) 794 { 795 if (_isMetadataOfCurrentContentTypeDefinition(contentTypeDefinition, metadataSetName)) 796 { 797 metadataSet = new MetadataDefinitionReference(metadataSetName); 798 _addChildrensMetadataSet(metadataSet, contentTypeDefinition, metadataSetInfo, pluginName, contentTypeId); 799 } 800 } 801 802 } 803 return metadataSet; 804 } 805 806 private MetadataSet _getMetadataSetDataType(ContentTypeDefinition contentTypeDefinition, Map<String, Object> metadataSetInfo, String metadataSetName, boolean isMetadataSetEdition, String pluginName, String contentTypeId) 807 { 808 MetadataSet metadataSet = new MetadataSet(); 809 metadataSet.setEdition(isMetadataSetEdition); 810 metadataSet.setName(metadataSetName); 811 812 Object recoverLabel = metadataSetInfo.get("label"); 813 I18nizableText label = _getI18nizableText(null, recoverLabel, pluginName, "contenttype", contentTypeId, 814 "metadatasets_" + metadataSetName + "_" + (isMetadataSetEdition ? "edition" : "view") + "_label"); 815 metadataSet.setLabel(label); 816 817 Object recoverDescription = metadataSetInfo.get("description"); 818 I18nizableText description = _getI18nizableText(null, recoverDescription, pluginName, "contenttype", contentTypeId, 819 "metadatasets_" + metadataSetName + "_" + (isMetadataSetEdition ? "edition" : "view") + "_description"); 820 metadataSet.setDescription(description); 821 822 _addChildrensMetadataSet(metadataSet, contentTypeDefinition, metadataSetInfo, pluginName, contentTypeId); 823 824 return metadataSet; 825 } 826 827 private Fieldset _getFieldSetDataType(ContentTypeDefinition contentTypeDefinition, Map<String, Object> metadataSetInfo, String metadataSetName, boolean isMetadataSetEdition, String pluginName, String contentTypeId) 828 { 829 Fieldset fieldSet = new Fieldset(); 830 831 Object recoverLabel = metadataSetInfo.get("label"); 832 I18nizableText label = _getI18nizableText(null, recoverLabel, pluginName, "contenttype", contentTypeId, 833 "metadatasets_" + metadataSetName + "_" + (isMetadataSetEdition ? "edition" : "view") + "_fieldset_" + _fieldsetNumber + "_label"); 834 fieldSet.setLabel(label); 835 836 _addChildrensMetadataSet(fieldSet, contentTypeDefinition, metadataSetInfo, pluginName, contentTypeId); 837 838 return fieldSet; 839 } 840 841 private boolean _isMetadataOfCurrentContentTypeDefinition(ContentTypeDefinition contentTypeDefinition, String metadataName) 842 { 843 boolean isMetadataOfCurrentContentTypeDefinition = false; 844 845 List<MetadataDefinition> metadata = contentTypeDefinition.getMetadata(); 846 for (MetadataDefinition metadataDefinition : metadata) 847 { 848 if (metadataDefinition.getName().equals(metadataName)) 849 { 850 isMetadataOfCurrentContentTypeDefinition = true; 851 break; 852 } 853 else 854 { 855 isMetadataOfCurrentContentTypeDefinition = _isMetadataOfCurrentContentTypeDefinition(metadataName, metadataDefinition); 856 } 857 } 858 return isMetadataOfCurrentContentTypeDefinition; 859 } 860 861 private boolean _isMetadataOfCurrentContentTypeDefinition(String metadataName, MetadataDefinition metadataDefinition) 862 { 863 boolean isMetadataOfCurrentContentTypeDefinition = false; 864 865 if (metadataDefinition.getName().equals(metadataName)) 866 { 867 isMetadataOfCurrentContentTypeDefinition = true; 868 } 869 else 870 { 871 Set<String> metadataNames = metadataDefinition.getMetadataNames(); 872 for (String childrenMetadataName : metadataNames) 873 { 874 MetadataDefinition metadata = metadataDefinition.getMetadataDefinition(childrenMetadataName); 875 if (_isMetadataOfCurrentContentTypeDefinition(metadataName, metadata)) 876 { 877 isMetadataOfCurrentContentTypeDefinition = true; 878 break; 879 } 880 } 881 } 882 return isMetadataOfCurrentContentTypeDefinition; 883 } 884 885 private void _addChildrensMetadataSet(AbstractMetadataSetElement metadataSet, ContentTypeDefinition contentTypeDefinition, Map<String, Object> metadataSetInfo, String pluginName, String contentTypeId) 886 { 887 Object recoverChildrens = metadataSetInfo.get("children"); 888 if (recoverChildrens != null && recoverChildrens instanceof List) 889 { 890 List<AbstractMetadataSetElement> childrenMetadataSet = new ArrayList<>(); 891 892 List childrens = (List) recoverChildrens; 893 for (Object recoverChildren : childrens) 894 { 895 if (recoverChildren != null && recoverChildren instanceof Map) 896 { 897 Map children = (Map) recoverChildren; 898 Object recoverChildrenMetadataSetName = children.get("name"); 899 if (recoverChildrenMetadataSetName != null && recoverChildrenMetadataSetName instanceof String) 900 { 901 String childrenMetadataSetName = (String) recoverChildrenMetadataSetName; 902 Object recoverMetadataIsMetadataSetEdition = children.get("isEdition"); 903 if (recoverMetadataIsMetadataSetEdition != null && recoverMetadataIsMetadataSetEdition instanceof Boolean) 904 { 905 boolean isChildrenMetadataSetEdition = (boolean) recoverMetadataIsMetadataSetEdition; 906 childrenMetadataSet.add(_getMetadataSet(contentTypeDefinition, children, childrenMetadataSetName, isChildrenMetadataSetEdition, pluginName, contentTypeId)); 907 } 908 else 909 { 910 boolean isChildrenMetadataSetEdition = false; 911 childrenMetadataSet.add(_getMetadataSet(contentTypeDefinition, children, childrenMetadataSetName, isChildrenMetadataSetEdition, pluginName, contentTypeId)); 912 } 913 } 914 } 915 } 916 metadataSet.setElements(childrenMetadataSet); 917 } 918 } 919 920 private boolean _getBoolean(Object recoverValue) 921 { 922 return recoverValue instanceof Boolean && (boolean) recoverValue; 923 } 924 925 private String _getString(Object recoverValue) 926 { 927 String value = null; 928 if (recoverValue != null && recoverValue instanceof String) 929 { 930 value = (String) recoverValue; 931 } 932 return value; 933 } 934 935 private int _getInteger(Object recoverValue) 936 { 937 int value = 0; 938 if (recoverValue != null && recoverValue instanceof Integer) 939 { 940 value = (int) recoverValue; 941 } 942 return value; 943 } 944 945 private I18nizableText _getI18nizableText(I18nizableText i18nizableText, Object recoverValue, String pluginName, String type, String contentTypeId, String label) 946 { 947 I18nizableText text = null; 948 if (recoverValue != null && recoverValue instanceof LinkedHashMap) 949 { 950 String key = _generateI18nKey(pluginName, type, contentTypeId, label); 951 text = _getI18nizableText(i18nizableText, recoverValue, key); 952 } 953 return text; 954 } 955 956 private I18nizableText _getI18nizableText(I18nizableText existingI18nizableText, Object recoverValue, String key) 957 { 958 I18nizableText text = null; 959 960 if (recoverValue != null && recoverValue instanceof Map) 961 { 962 Map value = (Map) recoverValue; 963 Object isMultilingual = value.get("isMultilingual"); 964 if (isMultilingual != null && isMultilingual instanceof Boolean) 965 { 966 boolean isI18n = (Boolean) isMultilingual; 967 if (isI18n) 968 { 969 Object recoveredI18nValues = value.get("values"); 970 if (recoveredI18nValues != null && recoveredI18nValues instanceof Map) 971 { 972 Map i18nValues = (Map) recoveredI18nValues; 973 if (!i18nValues.isEmpty()) 974 { 975 // There is an existing key for the data 976 if (existingI18nizableText != null && existingI18nizableText.isI18n()) 977 { 978 text = existingI18nizableText; 979 } 980 else 981 { 982 text = new I18nizableText(__DEFAULT_CATALOGUE, key); 983 } 984 // Add key and values to the TranslatedValue object 985 TranslatedValue translatedValue = new TranslatedValue(key, i18nValues); 986 _translatedValues.add(translatedValue); 987 } 988 } 989 } 990 else 991 { 992 Object recoverLabel = value.get("values"); 993 if (recoverLabel instanceof String) 994 { 995 String label = (String) recoverLabel; 996 if (StringUtils.isNotBlank(label)) 997 { 998 text = new I18nizableText(label); 999 } 1000 } 1001 } 1002 } 1003 } 1004 return text; 1005 } 1006 1007 private String _generateContentTypeIdKey(String contentTypeId) 1008 { 1009 String key = contentTypeId.replaceFirst("content-type.", ""); 1010 key = key.replaceAll("\\s", "_"); 1011 key = key.replaceAll("[^\\p{L}&&[^0-9]]", "_"); 1012 return key; 1013 } 1014 1015 @SuppressWarnings("unchecked") 1016 private String _generateCategoryI18nKey(String pluginName, Map<String, Object> recoveredCategory) 1017 { 1018 String key = ""; 1019 Map<String, String> values = (Map<String, String>) recoveredCategory.get("values"); 1020 if (values != null && !values.isEmpty()) 1021 { 1022 String categoryLabel = ""; 1023 if (values.containsKey("en")) 1024 { 1025 categoryLabel = values.get("en"); 1026 1027 } 1028 else 1029 { 1030 List<String> valuesAsList = new ArrayList(values.values()); 1031 categoryLabel = valuesAsList.get(0); 1032 } 1033 key = "plugins_" + pluginName + "_" + "content_createcontentmenu_group" + "_" + _generateContentTypeIdKey(categoryLabel); 1034 key = key.toUpperCase(); 1035 } 1036 return key; 1037 } 1038 1039 private String _generateI18nKey(String pluginName, String type, String contentTypeId, String label) 1040 { 1041 String id = _generateContentTypeIdKey(contentTypeId); 1042 String key = "plugins_" + pluginName + "_" + type + "_" + id + "_" + label; 1043 key = key.toUpperCase(); 1044 return key; 1045 } 1046 1047 private Map<String, Map<String, String>> _createNewI18nCatalogs() 1048 { 1049 Map<String, Map<String, String>> i18nMessageTranslations = new HashMap<>(); 1050 1051 for (TranslatedValue translatedValue : _translatedValues) 1052 { 1053 if (translatedValue.getTranslations() != null) 1054 { 1055 for (Entry<String, String> translation : translatedValue.getTranslations().entrySet()) 1056 { 1057 String i18nKey = translatedValue.getKey(); 1058 if (StringUtils.isNotBlank(i18nKey) && StringUtils.isNotBlank(translation.getValue())) 1059 { 1060 String language = translation.getKey(); 1061 if (i18nMessageTranslations.containsKey(language)) 1062 { 1063 Map<String, String> map = i18nMessageTranslations.get(language); 1064 map.put(i18nKey, translation.getValue()); 1065 } 1066 else 1067 { 1068 Map<String, String> map = new HashMap<>(); 1069 map.put(i18nKey, translation.getValue()); 1070 i18nMessageTranslations.put(language, map); 1071 } 1072 } 1073 } 1074 } 1075 } 1076 return i18nMessageTranslations; 1077 } 1078 1079 private void _saxCatalogs(Map<String, Map<String, String>> newI18nMessages) throws Exception 1080 { 1081 // Determine the default catalog language 1082 String defaultLanguage = ""; 1083 String defaultI18nCatalogPath = __I18N_CATALOG_DIR + "application.xml"; 1084 Source defaultI18nCatalogSource = null; 1085 try 1086 { 1087 defaultI18nCatalogSource = _sourceResolver.resolveURI(defaultI18nCatalogPath); 1088 if (defaultI18nCatalogSource.exists()) 1089 { 1090 // Parse default catalog application to know the default 1091 // language 1092 Configuration configuration = new DefaultConfigurationBuilder(true).build(defaultI18nCatalogSource.getInputStream(), ""); 1093 defaultLanguage = configuration.getAttribute("xml:lang"); 1094 } 1095 } 1096 catch (SourceNotFoundException e) 1097 { 1098 // Silently ignore 1099 } 1100 finally 1101 { 1102 _sourceResolver.release(defaultI18nCatalogSource); 1103 } 1104 1105 for (Entry<String, Map<String, String>> i18nMessageTranslation : newI18nMessages.entrySet()) 1106 { 1107 Map<String, String> i18nMessages = new HashMap<>(); 1108 String language = i18nMessageTranslation.getKey(); 1109 String catalogPath; 1110 if (language.equals(defaultLanguage)) 1111 { 1112 catalogPath = __I18N_CATALOG_DIR + "application.xml"; 1113 i18nMessages = _readI18nCatalog(catalogPath); 1114 } 1115 else 1116 { 1117 catalogPath = __I18N_CATALOG_DIR + "application_" + language + ".xml"; 1118 i18nMessages = _readI18nCatalog(catalogPath); 1119 } 1120 Map<String, String> updatedI18nMessages = _updateI18nMessages(i18nMessages, i18nMessageTranslation.getValue()); 1121 _saveI18nCalatog(updatedI18nMessages, catalogPath, language); 1122 } 1123 } 1124 1125 private Map<String, String> _readI18nCatalog(String path) throws Exception 1126 { 1127 Map<String, String> i18nMessages = new LinkedHashMap<>(); 1128 Source i18nCatalogSource = null; 1129 1130 try 1131 { 1132 i18nCatalogSource = _sourceResolver.resolveURI(path); 1133 if (i18nCatalogSource.exists()) 1134 { 1135 if (_i18nCatalogs.containsKey(path)) 1136 { 1137 I18nCatalog i18nCatalog = _i18nCatalogs.get(path); 1138 if (i18nCatalog.getLastModified() < i18nCatalogSource.getLastModified()) 1139 { 1140 SAXParserFactory.newInstance().newSAXParser().parse(i18nCatalogSource.getInputStream(), new I18nMessageHandler(i18nMessages)); 1141 i18nCatalog.setI18nMessages(i18nMessages); 1142 } 1143 else 1144 { 1145 i18nMessages = i18nCatalog.getI18nMessages(); 1146 } 1147 } 1148 else 1149 { 1150 SAXParserFactory.newInstance().newSAXParser().parse(i18nCatalogSource.getInputStream(), new I18nMessageHandler(i18nMessages)); 1151 I18nCatalog i18nCatalog = new I18nCatalog(i18nMessages); 1152 _i18nCatalogs.put(path, i18nCatalog); 1153 } 1154 } 1155 } 1156 catch (SourceNotFoundException e) 1157 { 1158 // Silently ignore 1159 } 1160 finally 1161 { 1162 _sourceResolver.release(i18nCatalogSource); 1163 } 1164 1165 return i18nMessages; 1166 } 1167 1168 private Map<String, String> _updateI18nMessages(Map<String, String> i18nMessages, Map<String, String> newI18nMessages) 1169 { 1170 for (Entry<String, String> newI18nMessage : newI18nMessages.entrySet()) 1171 { 1172 String key = newI18nMessage.getKey(); 1173 String value = newI18nMessage.getValue(); 1174 if (i18nMessages.containsKey(key)) 1175 { 1176 i18nMessages.replace(key, value); 1177 } 1178 else 1179 { 1180 i18nMessages.put(key, value); 1181 } 1182 } 1183 return i18nMessages; 1184 } 1185 1186 private void _saveI18nCalatog(Map<String, String> i18nMessages, String catalogPath, String language) throws Exception 1187 { 1188 ModifiableSource defaultI18nCatalogSource = null; 1189 try 1190 { 1191 defaultI18nCatalogSource = (ModifiableSource) _sourceResolver.resolveURI(catalogPath); 1192 try (OutputStream os = defaultI18nCatalogSource.getOutputStream()) 1193 { 1194 // create a transformer for saving sax into a file 1195 TransformerHandler th = ((SAXTransformerFactory) TransformerFactory.newInstance()).newTransformerHandler(); 1196 1197 StreamResult result = new StreamResult(os); 1198 th.setResult(result); 1199 1200 // create the format of result 1201 Properties format = new Properties(); 1202 format.put(OutputKeys.METHOD, "xml"); 1203 format.put(OutputKeys.INDENT, "yes"); 1204 format.put(OutputKeys.ENCODING, "UTF-8"); 1205 format.put(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "2"); 1206 th.getTransformer().setOutputProperties(format); 1207 1208 // sax the config into the transformer 1209 _saxI18nCatalog(th, i18nMessages, language); 1210 1211 } 1212 catch (Exception e) 1213 { 1214 throw new Exception("An error occured while saving the catalog values.", e); 1215 } 1216 _i18nCatalogs.get(catalogPath).setLastModified(defaultI18nCatalogSource.getLastModified()); 1217 } 1218 catch (SourceNotFoundException e) 1219 { 1220 // Silently ignore 1221 } 1222 finally 1223 { 1224 _sourceResolver.release(defaultI18nCatalogSource); 1225 } 1226 1227 } 1228 1229 private void _saxI18nCatalog(TransformerHandler handler, Map<String, String> i18nMessages, String language) throws SAXException 1230 { 1231 handler.startDocument(); 1232 AttributesImpl attribute = new AttributesImpl(); 1233 attribute.addCDATAAttribute("xml:lang", language); 1234 XMLUtils.startElement(handler, "catalogue", attribute); 1235 for (Entry<String, String> i18Message : i18nMessages.entrySet()) 1236 { 1237 attribute = new AttributesImpl(); 1238 attribute.addCDATAAttribute("key", i18Message.getKey()); 1239 XMLUtils.createElement(handler, "message", attribute, i18Message.getValue()); 1240 } 1241 XMLUtils.endElement(handler, "catalogue"); 1242 handler.endDocument(); 1243 } 1244 1245 private void _saxRightsParam(String id, String label, String description) throws MalformedURLException, IOException 1246 { 1247 // For sax right params, a pipeline is used because it's more simple to copy a part of the existing right file to add or modify a right 1248 String uri = __SAVE_CONTENT_TYPE_RIGHT + "?id=" + id + "&label=" + label + "&description=" + description + "&category=" + __RIGHT_CATEGORY + "&file-path=" + __RIGHTS_FILE; 1249 Source source = null; 1250 ModifiableSource fileSource = null; 1251 1252 try 1253 { 1254 source = _sourceResolver.resolveURI(uri); 1255 fileSource = (ModifiableSource) _sourceResolver.resolveURI(__RIGHTS_FILE); 1256 try (OutputStream resultOs = fileSource.getOutputStream(); InputStream sourceIs = source.getInputStream()) 1257 { 1258 SourceUtil.copy(sourceIs, resultOs); 1259 } 1260 } 1261 finally 1262 { 1263 _sourceResolver.release(source); 1264 _sourceResolver.release(fileSource); 1265 } 1266 } 1267 1268}