001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.jsp; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.containerpage.CmsElementUtil; 032import org.opencms.ade.containerpage.shared.CmsContainerElement; 033import org.opencms.ade.containerpage.shared.CmsFormatterConfig; 034import org.opencms.file.CmsObject; 035import org.opencms.file.CmsResource; 036import org.opencms.file.CmsResourceFilter; 037import org.opencms.file.collectors.I_CmsCollectorPostCreateHandler; 038import org.opencms.flex.CmsFlexController; 039import org.opencms.jsp.util.CmsJspContentAccessValueWrapper; 040import org.opencms.jsp.util.CmsJspStandardContextBean; 041import org.opencms.main.CmsException; 042import org.opencms.main.CmsLog; 043import org.opencms.main.OpenCms; 044import org.opencms.util.CmsRequestUtil; 045import org.opencms.util.CmsStringUtil; 046import org.opencms.util.CmsUUID; 047import org.opencms.workplace.editors.directedit.CmsAdvancedDirectEditProvider; 048import org.opencms.workplace.editors.directedit.CmsDirectEditMode; 049import org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider; 050import org.opencms.xml.containerpage.CmsADESessionCache; 051import org.opencms.xml.containerpage.CmsContainerElementBean; 052import org.opencms.xml.containerpage.CmsFormatterConfiguration; 053import org.opencms.xml.containerpage.I_CmsFormatterBean; 054import org.opencms.xml.types.CmsXmlDisplayFormatterValue; 055import org.opencms.xml.types.I_CmsXmlContentValue; 056 057import java.util.HashMap; 058import java.util.LinkedHashMap; 059import java.util.List; 060import java.util.Locale; 061import java.util.Map; 062import java.util.Map.Entry; 063 064import javax.servlet.ServletRequest; 065import javax.servlet.ServletResponse; 066import javax.servlet.http.HttpServletRequest; 067import javax.servlet.jsp.JspException; 068import javax.servlet.jsp.PageContext; 069import javax.servlet.jsp.tagext.BodyTagSupport; 070 071import org.apache.commons.lang3.builder.ReflectionToStringBuilder; 072import org.apache.commons.logging.Log; 073 074/** 075 * The 'display' tag can be used to display a single resource using a formatter. It also allows to activate direct editing.<p> 076 */ 077public class CmsJspTagDisplay extends BodyTagSupport implements I_CmsJspTagParamParent { 078 079 /** Setting used to store the display formatter key. */ 080 public static final String DISPLAY_FORMATTER_SETTING = "SYSTEM::DISPLAY_FORMATTER"; 081 082 /** The log object for this class. */ 083 private static final Log LOG = CmsLog.getLog(CmsJspTagDisplay.class); 084 085 /** The serial version id. */ 086 private static final long serialVersionUID = 2285680951218629093L; 087 088 /** The base URI. */ 089 private String m_baseUri; 090 091 /** True if the display formatter include should go through the flex cache. */ 092 private Boolean m_cacheable; 093 094 /** Flag, indicating if the create option should be displayed. */ 095 private boolean m_canCreate; 096 097 /** Flag, indicating if the delete option should be displayed. */ 098 private boolean m_canDelete; 099 100 /** The tag attribute's value, specifying the path to the (sub)sitemap where new content should be created. */ 101 private String m_creationSiteMap; 102 103 /** The display formatter ids. */ 104 private Map<String, String> m_displayFormatterIds; 105 106 /** The display formatter paths. */ 107 private Map<String, String> m_displayFormatterPaths; 108 109 /** The editable flag. */ 110 private boolean m_editable; 111 112 /** The settings parameter map. */ 113 private Map<String, String> m_parameterMap; 114 115 /** The pass settings flag. */ 116 private boolean m_passSettings; 117 118 /** The fully qualified class name of the post create handler to use. */ 119 private String m_postCreateHandler; 120 121 /** The element settings to be used. */ 122 private Map<String, String> m_settings; 123 124 /** The upload folder. */ 125 private String m_uploadFolder; 126 127 /** The site path to the resource to display. */ 128 private String m_value; 129 130 /** 131 * Constructor.<p> 132 */ 133 public CmsJspTagDisplay() { 134 135 m_parameterMap = new LinkedHashMap<>(); 136 m_displayFormatterPaths = new HashMap<>(); 137 m_displayFormatterIds = new HashMap<>(); 138 } 139 140 /** 141 * Includes the formatter rendering the given element.<p> 142 * 143 * @param element the element 144 * @param formatter the formatter configuration bean 145 * @param cacheable true if the flex cache should be used for calling the display formatter 146 * @param editable if editable 147 * @param canCreate if new resources may be created 148 * @param canDelete if the resource may be deleted 149 * @param creationSiteMap the create location sub site 150 * @param postCreateHandler the post create handler 151 * @param uploadFolder the upload folder to use 152 * @param context the page context 153 * @param request the request 154 * @param response the response 155 */ 156 public static void displayAction( 157 CmsContainerElementBean element, 158 I_CmsFormatterBean formatter, 159 boolean cacheable, 160 boolean editable, 161 boolean canCreate, 162 boolean canDelete, 163 String creationSiteMap, 164 String postCreateHandler, 165 String uploadFolder, 166 PageContext context, 167 ServletRequest request, 168 ServletResponse response) { 169 170 if (CmsFlexController.isCmsRequest(request)) { 171 // this will always be true if the page is called through OpenCms 172 CmsObject cms = CmsFlexController.getCmsObject(request); 173 CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfigurationWithCache( 174 cms, 175 cms.getRequestContext().getRootUri()); 176 Locale locale = cms.getRequestContext().getLocale(); 177 boolean isOnline = cms.getRequestContext().getCurrentProject().isOnlineProject(); 178 CmsJspStandardContextBean contextBean = CmsJspStandardContextBean.getInstance(request); 179 CmsContainerElementBean parentElement = contextBean.getElement(); 180 181 try { 182 if (formatter != null) { 183 element.initResource(cms); 184 element.initSettings(cms, adeConfig, formatter, locale, request, null); 185 element.getSettings().put(DISPLAY_FORMATTER_SETTING, formatter.getKeyOrId()); 186 boolean openedEditable = false; 187 contextBean.setElement(element); 188 if (editable && contextBean.getIsEditMode()) { 189 if (CmsJspTagEditable.getDirectEditProvider(context) == null) { 190 I_CmsDirectEditProvider eb = new CmsAdvancedDirectEditProvider(); 191 eb.init(cms, CmsDirectEditMode.TRUE, element.getSitePath()); 192 request.setAttribute(I_CmsDirectEditProvider.ATTRIBUTE_DIRECT_EDIT_PROVIDER, eb); 193 } 194 195 openedEditable = CmsJspTagEdit.insertDirectEditStart( 196 cms, 197 context, 198 element.getResource(), 199 canCreate, 200 canDelete, 201 null, 202 creationSiteMap, 203 postCreateHandler, 204 uploadFolder); 205 } 206 if (contextBean.getIsEditMode()) { 207 CmsADESessionCache.getCache( 208 (HttpServletRequest)(context.getRequest()), 209 cms).setCacheContainerElement(element.editorHash(), element); 210 } 211 try { 212 CmsJspTagInclude.includeTagAction( 213 context, 214 cms.getRequestContext().removeSiteRoot(formatter.getJspRootPath()), 215 null, 216 locale, 217 false, 218 isOnline && cacheable, 219 CmsRequestUtil.createParameterMap(element.getSettings()), 220 CmsRequestUtil.getAtrributeMap(request), 221 request, 222 response); 223 } catch (Exception e) { 224 LOG.error(e.getLocalizedMessage(), e); 225 } 226 if (openedEditable) { 227 CmsJspTagEdit.insertDirectEditEnd(context); 228 } 229 } 230 } catch (CmsException e) { 231 LOG.error(e.getLocalizedMessage(), e); 232 } 233 contextBean.setElement(parentElement); 234 } 235 236 } 237 238 /** 239 * Includes the formatter rendering the given element.<p> 240 * 241 * @param element the element 242 * @param formatter the formatter configuration bean 243 * @param context the page context 244 * @param request the request 245 * @param response the response 246 */ 247 public static void displayAction( 248 CmsContainerElementBean element, 249 I_CmsFormatterBean formatter, 250 PageContext context, 251 ServletRequest request, 252 ServletResponse response) { 253 254 displayAction(element, formatter, true, false, false, false, null, null, null, context, request, response); 255 } 256 257 /** 258 * Includes the formatter rendering the given element.<p> 259 * 260 * @param elementResource the element resource 261 * @param formatter the formatter configuration bean 262 * @param settings the element settings 263 * @param cacheable true if the flex cache should be used for calling the display formatter 264 * @param editable if editable 265 * @param canCreate if new resources may be created 266 * @param canDelete if the resource may be deleted 267 * @param creationSiteMap the create location sub site 268 * @param postCreateHandler the post create handler 269 * @param uploadFolder the upload folder 270 * @param context the page context 271 * @param request the request 272 * @param response the response 273 */ 274 public static void displayAction( 275 CmsResource elementResource, 276 I_CmsFormatterBean formatter, 277 Map<String, String> settings, 278 boolean cacheable, 279 boolean editable, 280 boolean canCreate, 281 boolean canDelete, 282 String creationSiteMap, 283 String postCreateHandler, 284 String uploadFolder, 285 PageContext context, 286 ServletRequest request, 287 ServletResponse response) { 288 289 CmsContainerElementBean element = new CmsContainerElementBean( 290 elementResource.getStructureId(), 291 formatter.getJspStructureId(), 292 settings, 293 false); 294 displayAction( 295 element, 296 formatter, 297 cacheable, 298 editable, 299 canCreate, 300 canDelete, 301 creationSiteMap, 302 postCreateHandler, 303 uploadFolder, 304 context, 305 request, 306 response); 307 } 308 309 /** 310 * If the setting key starts with the key or id of the given formatter, returns the remaining suffix, else null. 311 * 312 * @param config the current sitemap configuration 313 * @param formatter the formatter bean 314 * @param settingKey the setting key 315 * 316 * @return the remaining setting name suffix 317 */ 318 public static String getSettingKeyForMatchingFormatterPrefix( 319 CmsADEConfigData config, 320 I_CmsFormatterBean formatter, 321 String settingKey) { 322 323 if (CmsElementUtil.isSystemSetting(settingKey)) { 324 return null; 325 } 326 327 int underscoreIndex = settingKey.indexOf("_"); 328 if (underscoreIndex < 0) { 329 return null; 330 } 331 String prefix = settingKey.substring(0, underscoreIndex); 332 String suffix = settingKey.substring(underscoreIndex + 1); 333 I_CmsFormatterBean dynamicFmt = config.findFormatter(prefix, /*noWarn=*/true); 334 if (dynamicFmt == null) { 335 return null; 336 } 337 boolean keyMatch = (dynamicFmt.getKey() != null) && dynamicFmt.getKey().equals(formatter.getKey()); 338 boolean idMatch = (dynamicFmt.getId() != null) && dynamicFmt.getId().equals(formatter.getId()); 339 if (!keyMatch && !idMatch) { 340 return null; 341 } 342 if (!dynamicFmt.getSettings(config).containsKey(suffix)) { 343 return null; 344 } 345 return suffix; 346 } 347 348 /** 349 * Adds a display formatter.<p> 350 * 351 * @param type the resource type 352 * @param path the path to the formatter configuration file.<p> 353 */ 354 public void addDisplayFormatter(String type, String path) { 355 356 m_displayFormatterPaths.put(type, path); 357 } 358 359 /** 360 * @see org.opencms.jsp.I_CmsJspTagParamParent#addParameter(java.lang.String, java.lang.String) 361 */ 362 public void addParameter(String name, String value) { 363 364 // No null values allowed in parameters 365 if ((name == null) || (value == null)) { 366 return; 367 } 368 369 m_parameterMap.put(name, value); 370 } 371 372 /** 373 * @see javax.servlet.jsp.tagext.BodyTagSupport#doEndTag() 374 */ 375 @Override 376 public int doEndTag() throws JspException { 377 378 ServletRequest request = pageContext.getRequest(); 379 ServletResponse response = pageContext.getResponse(); 380 if (CmsFlexController.isCmsRequest(request)) { 381 // this will always be true if the page is called through OpenCms 382 CmsObject cms = CmsFlexController.getCmsObject(request); 383 try { 384 boolean isOnline = cms.getRequestContext().getCurrentProject().isOnlineProject(); 385 CmsResource res = null; 386 if (CmsUUID.isValidUUID(m_value)) { 387 CmsUUID structureId = new CmsUUID(m_value); 388 res = isOnline 389 ? cms.readResource(structureId) 390 : cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION); 391 } else { 392 res = isOnline 393 ? cms.readResource(m_value) 394 : cms.readResource(m_value, CmsResourceFilter.IGNORE_EXPIRATION); 395 } 396 397 CmsObject cmsForFormatterLookup = cms; 398 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_baseUri)) { 399 cmsForFormatterLookup = OpenCms.initCmsObject(cms); 400 cmsForFormatterLookup.getRequestContext().setUri(m_baseUri); 401 } 402 I_CmsFormatterBean formatter = getFormatterForType(cmsForFormatterLookup, res, isOnline); 403 CmsADEConfigData config = OpenCms.getADEManager().lookupConfigurationWithCache( 404 cmsForFormatterLookup, 405 cms.getRequestContext().getRootUri()); 406 if (formatter == null) { 407 String error = "cms:display - could not find display formatter for " + m_value + "\n"; 408 try { 409 error += "\n\nTag instance: " + ReflectionToStringBuilder.toString(this); 410 } catch (Exception e) { 411 // ignore 412 } 413 throw new JspException(error); 414 } 415 416 Map<String, String> settings = prepareSettings(config, formatter); 417 418 displayAction( 419 res, 420 formatter, 421 settings, 422 isCacheable(), 423 m_editable, 424 m_canCreate, 425 m_canDelete, 426 m_creationSiteMap, 427 m_postCreateHandler, 428 m_uploadFolder, 429 pageContext, 430 request, 431 response); 432 } catch (CmsException e) { 433 LOG.error(e.getLocalizedMessage(), e); 434 } 435 } 436 release(); 437 return EVAL_PAGE; 438 } 439 440 /** 441 * @see javax.servlet.jsp.tagext.BodyTagSupport#doStartTag() 442 */ 443 @Override 444 public int doStartTag() { 445 446 if (Boolean.valueOf(m_passSettings).booleanValue()) { 447 CmsContainerElementBean element = CmsJspStandardContextBean.getInstance( 448 pageContext.getRequest()).getElement(); 449 if (element != null) { 450 m_parameterMap.putAll(element.getSettings()); 451 } 452 } 453 if (m_settings != null) { 454 m_parameterMap.putAll(m_settings); 455 } 456 457 return EVAL_BODY_BUFFERED; 458 } 459 460 /** 461 * Returns the editable.<p> 462 * 463 * @return the editable 464 */ 465 public boolean getEditable() { 466 467 return m_editable; 468 } 469 470 /** 471 * Returns the passSettings.<p> 472 * 473 * @return the passSettings 474 */ 475 public boolean getPassSettings() { 476 477 return m_passSettings; 478 } 479 480 /** 481 * Returns the element settings to be used.<p> 482 * 483 * @return the element settings to be used 484 */ 485 public Map<String, String> getSettings() { 486 487 return m_settings; 488 } 489 490 /** 491 * Returns the value.<p> 492 * 493 * @return the value 494 */ 495 public String getValue() { 496 497 return m_value; 498 } 499 500 /** 501 * @see javax.servlet.jsp.tagext.BodyTagSupport#release() 502 */ 503 @Override 504 public void release() { 505 506 super.release(); 507 m_parameterMap.clear(); 508 m_displayFormatterPaths.clear(); 509 m_displayFormatterIds.clear(); 510 m_settings = null; 511 m_passSettings = false; 512 m_editable = false; 513 m_value = null; 514 } 515 516 /** 517 * Sets the base URI to use for finding the 'default' display formatter. 518 * 519 * @param uri the base URI 520 */ 521 public void setBaseUri(String uri) { 522 523 m_baseUri = uri; 524 } 525 526 /** 527 * Enables/disables the use of the flex cache for the display formatter include. 528 * 529 * @param cacheable true if the flex cache should be used for the display formatter include 530 */ 531 public void setCacheable(boolean cacheable) { 532 533 m_cacheable = Boolean.valueOf(cacheable); 534 } 535 536 /** Setter for the "create" attribute of the tag. 537 * @param canCreate value of the tag's attribute "create". 538 */ 539 public void setCreate(boolean canCreate) { 540 541 m_canCreate = canCreate; 542 } 543 544 /** Setter for the "create" attribute of the tag. 545 * @param canCreate value of the tag's attribute "create". 546 */ 547 public void setCreate(String canCreate) { 548 549 m_canCreate = Boolean.valueOf(canCreate).booleanValue(); 550 } 551 552 /** Setter for the "creationSiteMap" attribute of the tag. 553 * @param sitePath value of the "creationSiteMap" attribute of the tag. 554 */ 555 public void setCreationSiteMap(String sitePath) { 556 557 m_creationSiteMap = sitePath; 558 } 559 560 /**Setter for the "delete" attribute of the tag. 561 * @param canDelete value of the "delete" attribute of the tag. 562 */ 563 public void setDelete(boolean canDelete) { 564 565 m_canDelete = canDelete; 566 } 567 568 /**Setter for the "delete" attribute of the tag. 569 * @param canDelete value of the "delete" attribute of the tag. 570 */ 571 public void setDelete(String canDelete) { 572 573 m_canDelete = Boolean.valueOf(canDelete).booleanValue(); 574 } 575 576 /** 577 * Sets the items.<p> 578 * 579 * @param displayFormatters the items to set 580 */ 581 public void setDisplayFormatters(Object displayFormatters) { 582 583 if (displayFormatters instanceof List) { 584 for (Object formatterItem : ((List<?>)displayFormatters)) { 585 if (formatterItem instanceof CmsJspContentAccessValueWrapper) { 586 addFormatter((CmsJspContentAccessValueWrapper)formatterItem); 587 } 588 } 589 } else if (displayFormatters instanceof CmsJspContentAccessValueWrapper) { 590 addFormatter((CmsJspContentAccessValueWrapper)displayFormatters); 591 } else if (displayFormatters instanceof String) { 592 String[] temp = ((String)displayFormatters).split(CmsXmlDisplayFormatterValue.SEPARATOR); 593 if (temp.length == 2) { 594 addDisplayFormatter(temp[0], temp[1]); 595 } 596 } 597 } 598 599 /** 600 * Sets the editable.<p> 601 * 602 * @param editable the editable to set 603 */ 604 public void setEditable(boolean editable) { 605 606 m_editable = editable; 607 } 608 609 /** 610 * Sets the editable.<p> 611 * 612 * @param editable the editable to set 613 */ 614 public void setEditable(String editable) { 615 616 m_editable = Boolean.valueOf(editable).booleanValue(); 617 } 618 619 /** 620 * Sets the passSettings.<p> 621 * 622 * @param passSettings the passSettings to set 623 */ 624 public void setPassSettings(boolean passSettings) { 625 626 m_passSettings = passSettings; 627 } 628 629 /** 630 * Sets the passSettings.<p> 631 * 632 * @param passSettings the passSettings to set 633 */ 634 public void setPassSettings(String passSettings) { 635 636 m_passSettings = Boolean.valueOf(passSettings).booleanValue(); 637 } 638 639 /** Setter for the "postCreateHandler" attribute of the tag. 640 * @param postCreateHandler fully qualified class name of the {@link I_CmsCollectorPostCreateHandler} to use. 641 */ 642 public void setPostCreateHandler(final String postCreateHandler) { 643 644 m_postCreateHandler = postCreateHandler; 645 } 646 647 /** 648 * Sets the element settings to be used.<p> 649 * 650 * @param settings the element settings to be used 651 */ 652 public void setSettings(Map<String, String> settings) { 653 654 m_settings = settings; 655 } 656 657 /** 658 * Sets the upload folder. 659 * 660 * @param uploadFolder the upload folder 661 */ 662 public void setUploadFolder(String uploadFolder) { 663 664 m_uploadFolder = uploadFolder; 665 } 666 667 /** 668 * Sets the value.<p> 669 * 670 * @param value the value to set 671 */ 672 public void setValue(String value) { 673 674 m_value = value; 675 } 676 677 /** 678 * Adds a formatter.<p> 679 * 680 * @param formatterItem the formatter value 681 */ 682 private void addFormatter(CmsJspContentAccessValueWrapper formatterItem) { 683 684 I_CmsXmlContentValue val = formatterItem.getContentValue(); 685 if (val instanceof CmsXmlDisplayFormatterValue) { 686 CmsXmlDisplayFormatterValue value = (CmsXmlDisplayFormatterValue)val; 687 String type = value.getDisplayType(); 688 String formatterId = value.getFormatterId(); 689 if (formatterId != null) { 690 m_displayFormatterIds.put(type, formatterId); 691 } 692 } 693 } 694 695 /** 696 * Returns the config for the requested resource, or <code>null</code> if not available.<p> 697 * 698 * @param cms the cms context 699 * @param resource the resource 700 * @param isOnline the is online flag 701 * 702 * @return the formatter configuration bean 703 */ 704 private I_CmsFormatterBean getFormatterForType(CmsObject cms, CmsResource resource, boolean isOnline) { 705 706 String typeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName(); 707 CmsADEConfigData config = OpenCms.getADEManager().lookupConfigurationWithCache( 708 cms, 709 cms.getRequestContext().getRootUri()); 710 I_CmsFormatterBean result = null; 711 if (m_displayFormatterPaths.containsKey(typeName)) { 712 try { 713 CmsResource res = cms.readResource(m_displayFormatterPaths.get(typeName)); 714 result = OpenCms.getADEManager().getCachedFormatters(isOnline).getFormatters().get( 715 res.getStructureId()); 716 } catch (CmsException e) { 717 LOG.error(e.getLocalizedMessage(), e); 718 } 719 } else if (m_displayFormatterIds.containsKey(typeName)) { 720 result = config.findFormatter(m_displayFormatterIds.get(typeName)); 721 } else { 722 if (config != null) { 723 CmsFormatterConfiguration formatters = config.getFormatters(cms, resource); 724 if (formatters != null) { 725 result = formatters.getDisplayFormatter(); 726 } 727 } 728 } 729 return result; 730 } 731 732 /** 733 * Checks if this tag instance should use the flex cache for including the formatter. 734 * 735 * @return true if this tag instance should use the flex cache for including the formatter 736 */ 737 private boolean isCacheable() { 738 739 return (m_cacheable == null) || m_cacheable.booleanValue(); 740 } 741 742 /** 743 * Prepares the settings before the call to displayAction(). 744 * 745 * @param config the sitemap configuration 746 * @param formatter the display formatter 747 * 748 * @return the settings to use 749 */ 750 private Map<String, String> prepareSettings(CmsADEConfigData config, I_CmsFormatterBean formatter) { 751 752 Map<String, String> settings = new HashMap<String, String>(); 753 for (Entry<String, String> entry : m_parameterMap.entrySet()) { 754 if (CmsContainerElement.ELEMENT_INSTANCE_ID.equals(entry.getKey())) { 755 // remove any instance id to make sure to generate a unique one 756 continue; 757 } 758 String fmtSetting = getSettingKeyForMatchingFormatterPrefix(config, formatter, entry.getKey()); 759 if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) { 760 settings.put(entry.getKey(), formatter.getId()); 761 } else if (fmtSetting != null) { 762 settings.put(fmtSetting, entry.getValue()); 763 } else if (!settings.containsKey(entry.getKey())) { 764 settings.put(entry.getKey(), entry.getValue()); 765 } 766 } 767 return settings; 768 } 769}