001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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.ade.containerpage; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.configuration.CmsElementView; 032import org.opencms.ade.configuration.CmsResourceTypeConfig; 033import org.opencms.ade.containerpage.inherited.CmsContainerConfigurationCache; 034import org.opencms.ade.containerpage.inherited.CmsInheritanceReference; 035import org.opencms.ade.containerpage.inherited.CmsInheritanceReferenceParser; 036import org.opencms.ade.containerpage.inherited.CmsInheritedContainerState; 037import org.opencms.ade.containerpage.shared.CmsContainer; 038import org.opencms.ade.containerpage.shared.CmsContainerElement; 039import org.opencms.ade.containerpage.shared.CmsContainerElement.ModelGroupState; 040import org.opencms.ade.containerpage.shared.CmsContainerElementData; 041import org.opencms.ade.containerpage.shared.CmsElementLockInfo; 042import org.opencms.ade.containerpage.shared.CmsElementSettingsConfig; 043import org.opencms.ade.containerpage.shared.CmsFormatterConfig; 044import org.opencms.ade.containerpage.shared.CmsFormatterConfigCollection; 045import org.opencms.ade.containerpage.shared.CmsInheritanceInfo; 046import org.opencms.ade.detailpage.CmsDetailPageResourceHandler; 047import org.opencms.configuration.CmsConfigurationException; 048import org.opencms.db.CmsResourceState; 049import org.opencms.file.CmsFile; 050import org.opencms.file.CmsObject; 051import org.opencms.file.CmsProperty; 052import org.opencms.file.CmsPropertyDefinition; 053import org.opencms.file.CmsRequestContext; 054import org.opencms.file.CmsResource; 055import org.opencms.file.CmsResourceFilter; 056import org.opencms.file.CmsUser; 057import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 058import org.opencms.file.types.CmsResourceTypeXmlContent; 059import org.opencms.file.types.I_CmsResourceType; 060import org.opencms.gwt.CmsDefaultResourceStatusProvider; 061import org.opencms.gwt.CmsIconUtil; 062import org.opencms.gwt.CmsVfsService; 063import org.opencms.gwt.shared.CmsAdditionalInfoBean; 064import org.opencms.gwt.shared.CmsListInfoBean; 065import org.opencms.gwt.shared.CmsPermissionInfo; 066import org.opencms.i18n.CmsMessageContainer; 067import org.opencms.i18n.CmsMessages; 068import org.opencms.jsp.util.CmsJspStandardContextBean; 069import org.opencms.jsp.util.CmsJspStandardContextBean.TemplateBean; 070import org.opencms.loader.CmsTemplateContextManager; 071import org.opencms.lock.CmsLock; 072import org.opencms.main.CmsException; 073import org.opencms.main.CmsLog; 074import org.opencms.main.OpenCms; 075import org.opencms.relations.CmsRelation; 076import org.opencms.relations.CmsRelationFilter; 077import org.opencms.relations.CmsRelationType; 078import org.opencms.search.galleries.CmsGallerySearch; 079import org.opencms.search.galleries.CmsGallerySearchResult; 080import org.opencms.util.CmsDateUtil; 081import org.opencms.util.CmsStringUtil; 082import org.opencms.util.CmsUUID; 083import org.opencms.workplace.CmsWorkplaceMessages; 084import org.opencms.workplace.editors.CmsWorkplaceEditorManager; 085import org.opencms.workplace.editors.directedit.CmsAdvancedDirectEditProvider; 086import org.opencms.workplace.editors.directedit.CmsDirectEditMode; 087import org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider; 088import org.opencms.workplace.explorer.CmsExplorerTypeSettings; 089import org.opencms.workplace.explorer.CmsResourceUtil; 090import org.opencms.xml.containerpage.CmsADESessionCache; 091import org.opencms.xml.containerpage.CmsContainerBean; 092import org.opencms.xml.containerpage.CmsContainerElementBean; 093import org.opencms.xml.containerpage.CmsContainerPageBean; 094import org.opencms.xml.containerpage.CmsFormatterConfiguration; 095import org.opencms.xml.containerpage.CmsGroupContainerBean; 096import org.opencms.xml.containerpage.CmsXmlContainerPage; 097import org.opencms.xml.containerpage.CmsXmlContainerPageFactory; 098import org.opencms.xml.containerpage.CmsXmlGroupContainer; 099import org.opencms.xml.containerpage.CmsXmlGroupContainerFactory; 100import org.opencms.xml.containerpage.I_CmsFormatterBean; 101import org.opencms.xml.content.CmsXmlContent; 102import org.opencms.xml.content.CmsXmlContentFactory; 103import org.opencms.xml.content.CmsXmlContentProperty; 104import org.opencms.xml.content.CmsXmlContentPropertyHelper; 105 106import java.io.IOException; 107import java.text.DateFormat; 108import java.util.ArrayList; 109import java.util.Collection; 110import java.util.Collections; 111import java.util.Date; 112import java.util.HashMap; 113import java.util.HashSet; 114import java.util.LinkedHashMap; 115import java.util.LinkedHashSet; 116import java.util.List; 117import java.util.Locale; 118import java.util.Map; 119import java.util.Map.Entry; 120import java.util.Set; 121import java.util.function.Function; 122 123import javax.servlet.ServletException; 124import javax.servlet.http.HttpServletRequest; 125import javax.servlet.http.HttpServletResponse; 126 127import org.apache.commons.logging.Log; 128 129import org.jsoup.Jsoup; 130import org.jsoup.nodes.Document; 131import org.jsoup.select.Elements; 132 133import com.google.common.base.Supplier; 134import com.google.common.base.Suppliers; 135import com.google.common.collect.Sets; 136 137/** 138 * Utility class to generate the element data objects used within the container-page editor.<p> 139 * 140 * @since 8.0.0 141 */ 142public class CmsElementUtil { 143 144 /** The maximum number of nested container levels. */ 145 public static final int MAX_NESTING_LEVEL = 7; 146 147 /** Static reference to the log. */ 148 private static final Log LOG = CmsLog.getLog(org.opencms.ade.containerpage.CmsElementUtil.class); 149 150 /** The ADE configuration data for the current page URI. */ 151 private CmsADEConfigData m_adeConfig; 152 153 /** The cms context. */ 154 private CmsObject m_cms; 155 156 /** The current page uri. */ 157 private String m_currentPageUri; 158 159 /** The content locale. */ 160 private Locale m_locale; 161 162 /** The current container page. */ 163 private CmsResource m_page; 164 165 /** The request parameters to use while rendering the elements. */ 166 @SuppressWarnings("unused") 167 private Map<String, Object> m_parameterMap; 168 169 /** The http request. */ 170 private HttpServletRequest m_req; 171 172 /** The http response. */ 173 private HttpServletResponse m_res; 174 175 /** The standard context bean. */ 176 private CmsJspStandardContextBean m_standardContext; 177 178 /** 179 * Creates a new instance.<p> 180 * Use this constructor to set the current container page state.<p> 181 * 182 * @param cms the cms context 183 * @param currentPageUri the current page uri 184 * @param containerPage the container page bean with the current container state 185 * @param detailContentId the detail content structure id 186 * @param req the http request 187 * @param res the http response 188 * @param isDragMode if the page is in drag mode 189 * @param locale the content locale 190 * 191 * @throws CmsException if something goes wrong 192 */ 193 public CmsElementUtil( 194 CmsObject cms, 195 String currentPageUri, 196 CmsContainerPageBean containerPage, 197 CmsUUID detailContentId, 198 HttpServletRequest req, 199 HttpServletResponse res, 200 boolean isDragMode, 201 Locale locale) 202 throws CmsException { 203 204 m_cms = OpenCms.initCmsObject(cms); 205 String contextPath = (String)cms.getRequestContext().getAttribute(CmsRequestContext.ATTRIBUTE_ADE_CONTEXT_PATH); 206 if (contextPath != null) { 207 m_cms.getRequestContext().setAttribute(CmsRequestContext.ATTRIBUTE_ADE_CONTEXT_PATH, contextPath); 208 } 209 m_req = req; 210 m_res = res; 211 m_currentPageUri = currentPageUri; 212 m_locale = locale; 213 // initializing request for standard context bean 214 req.setAttribute(CmsJspStandardContextBean.ATTRIBUTE_CMS_OBJECT, m_cms); 215 if (detailContentId != null) { 216 CmsResource detailRes = m_cms.readResource( 217 detailContentId, 218 CmsResourceFilter.ignoreExpirationOffline(m_cms)); 219 req.setAttribute(CmsDetailPageResourceHandler.ATTR_DETAIL_CONTENT_RESOURCE, detailRes); 220 } 221 m_standardContext = CmsJspStandardContextBean.getInstance(req); 222 m_page = m_cms.readResource(currentPageUri, CmsResourceFilter.ignoreExpirationOffline(cms)); 223 m_standardContext.setPage(containerPage); 224 m_standardContext.setDragMode(isDragMode); 225 } 226 227 /** 228 * Creates a new instance.<p> 229 * 230 * @param cms the cms context 231 * @param currentPageUri the current page uri 232 * @param detailContentId the detail content structure id 233 * @param req the http request 234 * @param res the http response 235 * @param locale the content locale 236 * 237 * @throws CmsException if something goes wrong 238 */ 239 public CmsElementUtil( 240 CmsObject cms, 241 String currentPageUri, 242 CmsUUID detailContentId, 243 HttpServletRequest req, 244 HttpServletResponse res, 245 Locale locale) 246 throws CmsException { 247 248 m_cms = OpenCms.initCmsObject(cms); 249 m_req = req; 250 m_res = res; 251 m_currentPageUri = currentPageUri; 252 m_locale = locale; 253 // initializing request for standard context bean 254 req.setAttribute(CmsJspStandardContextBean.ATTRIBUTE_CMS_OBJECT, m_cms); 255 if (detailContentId != null) { 256 CmsResource detailRes = m_cms.readResource(detailContentId, CmsResourceFilter.ignoreExpirationOffline(cms)); 257 req.setAttribute(CmsDetailPageResourceHandler.ATTR_DETAIL_CONTENT_RESOURCE, detailRes); 258 } 259 m_standardContext = CmsJspStandardContextBean.getInstance(req); 260 m_page = m_cms.readResource(currentPageUri); 261 CmsXmlContainerPage xmlContainerPage = CmsXmlContainerPageFactory.unmarshal(cms, m_page, req); 262 CmsContainerPageBean containerPage = xmlContainerPage.getContainerPage(cms); 263 m_standardContext.setPage(containerPage); 264 } 265 266 /** 267 * Creates a new instance.<p> 268 * 269 * @param cms the cms context 270 * @param currentPageUri the current page uri 271 * @param detailContentId the detail content structure id 272 * @param requestParameters the request parameters to use while rendering the elements 273 * @param req the http request 274 * @param res the http response 275 * @param locale the content locale 276 * 277 * @throws CmsException if something goes wrong 278 */ 279 public CmsElementUtil( 280 CmsObject cms, 281 String currentPageUri, 282 CmsUUID detailContentId, 283 String requestParameters, 284 HttpServletRequest req, 285 HttpServletResponse res, 286 Locale locale) 287 throws CmsException { 288 289 this(cms, currentPageUri, detailContentId, req, res, locale); 290 m_parameterMap = parseRequestParameters(requestParameters); 291 } 292 293 /** 294 * Checks if a group element is allowed in a container with a given type.<p> 295 * 296 * @param containerType the container type spec (comma separated) 297 * @param groupContainer the group 298 * 299 * @return true if the group is allowed in the container 300 */ 301 public static boolean checkGroupAllowed(String containerType, CmsGroupContainerBean groupContainer) { 302 303 return !Sets.intersection(CmsContainer.splitType(containerType), groupContainer.getTypes()).isEmpty(); 304 } 305 306 /** 307 * Converts a client container bean to a server container bean. 308 * 309 * @param container the client container 310 * @param elements the elements of the container 311 * @return the server container bean 312 */ 313 public static CmsContainerBean clientToServerContainer( 314 CmsContainer container, 315 List<CmsContainerElementBean> elements) { 316 317 return new CmsContainerBean( 318 container.getName(), 319 container.getType(), 320 container.getParentInstanceId(), 321 container.isRootContainer(), 322 container.getMaxElements(), 323 elements); 324 325 } 326 327 /** 328 * Helper method to create a string template source for a given formatter and content. 329 * 330 * @param formatter the formatter 331 * @param contentSupplier the content supplier 332 * 333 * @return the string template provider 334 */ 335 public static Function<String, String> createStringTemplateSource( 336 I_CmsFormatterBean formatter, 337 Supplier<CmsXmlContent> contentSupplier) { 338 339 return key -> { 340 String result = null; 341 if (formatter != null) { 342 result = formatter.getAttributes().get(key); 343 } 344 if (result == null) { 345 CmsXmlContent content = contentSupplier.get(); 346 if (content != null) { 347 result = content.getHandler().getParameter(key); 348 } 349 } 350 return result; 351 }; 352 } 353 354 /** 355 * Returns the formatter bean for the given element and container.<p> 356 * 357 * @param cms the cms context 358 * @param element the element to render 359 * @param container the container 360 * @param config the configuration data 361 * @param cache the session cache 362 * 363 * @return the formatter bean 364 */ 365 public static I_CmsFormatterBean getFormatterForContainer( 366 CmsObject cms, 367 CmsContainerElementBean element, 368 CmsContainer container, 369 CmsADEConfigData config, 370 CmsADESessionCache cache) { 371 372 I_CmsFormatterBean formatter = null; 373 CmsFormatterConfiguration formatterSet = config.getFormatters(cms, element.getResource()); 374 Map<String, I_CmsFormatterBean> formatters = formatterSet.getFormatterSelectionByKeyOrId( 375 container.getType(), 376 container.getWidth()); 377 String formatterId = element.getIndividualSettings().get( 378 CmsFormatterConfig.getSettingsKeyForContainer(container.getName())); 379 if (formatterId != null) { 380 I_CmsFormatterBean dynamicFmt = config.findFormatter(formatterId); 381 if (dynamicFmt != null) { 382 formatter = dynamicFmt; 383 } else { 384 formatter = formatters.get(formatterId); 385 } 386 } 387 if (formatter == null) { 388 formatterId = element.getIndividualSettings().get(CmsFormatterConfig.FORMATTER_SETTINGS_KEY); 389 if (formatterId != null) { 390 formatter = lookupFormatter(config, formatterId, formatters); 391 } 392 } 393 if (formatter == null) { 394 // check for formatter config id stored for other containers matching the current container 395 for (Entry<String, String> settingsEntry : element.getIndividualSettings().entrySet()) { 396 if (settingsEntry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) { 397 formatter = lookupFormatter(config, settingsEntry.getValue(), formatters); 398 if (formatter != null) { 399 break; 400 } 401 } 402 } 403 } 404 if ((formatter == null) && (element.getFormatterId() != null)) { 405 for (I_CmsFormatterBean currentFormatter : formatters.values()) { 406 if ((currentFormatter.getJspStructureId() != null) 407 && currentFormatter.getJspStructureId().equals(element.getFormatterId())) { 408 formatter = currentFormatter; 409 break; 410 } 411 } 412 } 413 if (formatter == null) { 414 formatter = getStartFormatter(cms, container, config, element, cache); 415 } 416 return formatter; 417 } 418 419 /** 420 * Gets the ids for the current page and potentially detail-only containers. 421 * @param cms the CMS context 422 * @param pageId the id for the current page 423 * @param detailContent the current detail content 424 * @return the set of ids for the current page and detail-only containers 425 */ 426 public static Set<CmsUUID> getPageAndDetailOnlyIds(CmsObject cms, CmsUUID pageId, CmsResource detailContent) { 427 428 Set<CmsUUID> result = new HashSet<>(); 429 result.add(pageId); 430 if (detailContent != null) { 431 for (CmsResource detailOnlyRes : CmsDetailOnlyContainerUtil.getDetailOnlyResources(cms, detailContent)) { 432 result.add(detailOnlyRes.getStructureId()); 433 } 434 } 435 return result; 436 } 437 438 /** 439 * Checks if the given setting name is a system setting. 440 * 441 * @param name the setting name 442 * @return true if the name corresponds to a system setting 443 */ 444 public static final boolean isSystemSetting(String name) { 445 446 if (CmsXmlContainerPage.LEGACY_SYSTEM_SETTING_NAMES.contains(name) 447 || CmsContainerElement.ELEMENT_INSTANCE_ID.equals(name) 448 || name.startsWith(CmsXmlContainerPage.SYSTEM_SETTING_PREFIX) 449 || name.startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) { 450 return true; 451 } 452 return false; 453 } 454 455 /** 456 * Returns the start formatter for a newly dropped element.<p> 457 * This will be either the least recently used matching formatter or the default formatter.<p> 458 * 459 * @param cms the cms context 460 * @param cnt the container 461 * @param configData the configuration data 462 * @param element the container element 463 * @param cache the session cache 464 * 465 * @return the formatter bean 466 */ 467 private static I_CmsFormatterBean getStartFormatter( 468 CmsObject cms, 469 CmsContainer cnt, 470 CmsADEConfigData configData, 471 CmsContainerElementBean element, 472 CmsADESessionCache cache) { 473 474 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource()); 475 I_CmsFormatterBean formatter = cache.getRecentFormatter(type.getTypeName(), cnt, configData); 476 if (formatter == null) { 477 formatter = configData.getFormatters(cms, element.getResource()).getDefaultFormatter( 478 cnt.getType(), 479 cnt.getWidth()); 480 } 481 return formatter; 482 } 483 484 /** 485 * Helper method for looking up the correct formatter for an element. 486 * 487 * @param config the sitemap config 488 * @param keyOrId the key or id of the formatter stored with the container element 489 * @param active map of active formatters by key or id 490 * 491 * @return the formatter with the given key or id 492 */ 493 private static I_CmsFormatterBean lookupFormatter( 494 CmsADEConfigData config, 495 String keyOrId, 496 Map<String, I_CmsFormatterBean> active) { 497 498 I_CmsFormatterBean dynamicFmt = config.findFormatter(keyOrId); 499 if (dynamicFmt != null) { 500 for (String key : new String[] {dynamicFmt.getKey(), dynamicFmt.getId(), keyOrId}) { 501 if ((key != null) && (active.get(key) != null)) { 502 return active.get(key); 503 } 504 } 505 return null; 506 } else { 507 // schema formatters 508 return active.get(keyOrId); 509 } 510 } 511 512 /** 513 * Returns the HTML content for the given resource and container.<p> 514 * 515 * @param elementFile the element resource file 516 * @param elementId the element id 517 * @param container the container 518 * 519 * @return the HTML content 520 */ 521 public String getContentByContainer(CmsFile elementFile, String elementId, CmsContainer container) { 522 523 CmsContainerElementBean element = CmsADESessionCache.getCache(m_req, m_cms).getCacheContainerElement(elementId); 524 element = element.clone(); 525 element.setTemporaryFile(elementFile); 526 CmsFormatterConfiguration configs = getFormatterConfiguration(element.getResource()); 527 return getContentByContainer(element, container, configs); 528 } 529 530 /** 531 * Returns the data for an element.<p> 532 * 533 * @param page the current container page 534 * @param element the resource 535 * @param containers the containers on the current container page 536 * 537 * @return the data for an element 538 * 539 * @throws CmsException if something goes wrong 540 */ 541 public CmsContainerElementData getElementData( 542 CmsResource page, 543 CmsContainerElementBean element, 544 Collection<CmsContainer> containers) 545 throws CmsException { 546 547 Locale requestLocale = m_cms.getRequestContext().getLocale(); 548 m_cms.getRequestContext().setLocale(m_locale); 549 element.initResource(m_cms); 550 if (element.getResource().isFolder()) { 551 return null; 552 } 553 boolean typeDisabled = false; 554 boolean createDisabled = false; 555 if (page != null) { 556 557 CmsADEConfigData config = OpenCms.getADEManager().lookupConfigurationWithCache(m_cms, page.getRootPath()); 558 String typeName = OpenCms.getResourceManager().getResourceType(element.getResource()).getTypeName(); 559 if (!config.getAddableTypeNames().contains(typeName)) { 560 typeDisabled = true; 561 } 562 CmsResourceTypeConfig typeConfig = config.getTypesByName().get(typeName); 563 if ((typeConfig == null) || typeConfig.isCreateDisabled()) { 564 createDisabled = true; 565 } 566 } 567 568 CmsContainerElementData elementData = getBaseElementData(page, element); 569 elementData.setAddDisabled(typeDisabled); 570 elementData.setCopyDisabled(createDisabled); 571 CmsFormatterConfiguration formatterConfiguraton = getFormatterConfiguration(element.getResource()); 572 Map<String, String> contents = new HashMap<String, String>(); 573 if (element.isGroupContainer(m_cms)) { 574 Map<String, CmsContainer> containersByName = new HashMap<String, CmsContainer>(); 575 for (CmsContainer container : containers) { 576 containersByName.put(container.getName(), container); 577 } 578 CmsXmlGroupContainer xmlGroupContainer = CmsXmlGroupContainerFactory.unmarshal( 579 m_cms, 580 element.getResource(), 581 m_req); 582 CmsGroupContainerBean groupContainer = xmlGroupContainer.getGroupContainer(m_cms); 583 // make sure to use the content title and not the property title 584 elementData.setTitle(groupContainer.getTitle()); 585 elementData.setTypes(groupContainer.getTypes()); 586 elementData.setDescription(groupContainer.getDescription()); 587 if (groupContainer.getTypes().isEmpty()) { 588 if (groupContainer.getElements().isEmpty()) { 589 String emptySub = "<div>NEW AND EMPTY</div>"; 590 for (CmsContainer cont : containersByName.values()) { 591 if (formatterConfiguraton.hasFormatter(cont.getType(), cont.getWidth())) { 592 contents.put(cont.getName(), emptySub); 593 } 594 } 595 } else { 596 // TODO: throw appropriate exception 597 return null; 598 } 599 } else { 600 601 // add formatter and content entries for the supported types 602 for (CmsContainer cnt : containersByName.values()) { 603 604 String type = cnt.getType(); 605 if (checkGroupAllowed(type, groupContainer)) { 606 contents.put(cnt.getName(), "<div>should not be used</div>"); 607 } 608 } 609 } 610 // add subitems 611 List<String> subItems = new ArrayList<String>(); 612 613 for (CmsContainerElementBean subElement : groupContainer.getElements()) { 614 // collect ids 615 subItems.add(subElement.editorHash()); 616 } 617 elementData.setSubItems(subItems); 618 } else if (element.isInheritedContainer(m_cms)) { 619 CmsInheritanceReferenceParser parser = new CmsInheritanceReferenceParser(m_cms); 620 parser.parse(element.getResource()); 621 CmsInheritanceReference ref = parser.getReference(m_locale); 622 String name = null; 623 // check for new inheritance reference 624 if (ref != null) { 625 name = ref.getName(); 626 elementData.setDescription(ref.getDescription()); 627 elementData.setTitle(ref.getTitle()); 628 } 629 for (CmsContainer container : containers) { 630 if (formatterConfiguraton.hasFormatter(container.getType(), container.getWidth())) { 631 contents.put(container.getName(), "<div>should not be used</div>"); 632 } 633 } 634 635 List<CmsInheritanceInfo> inheritanceInfos = new ArrayList<CmsInheritanceInfo>(); 636 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(name)) { 637 CmsInheritedContainerState result = OpenCms.getADEManager().getInheritedContainerState( 638 m_cms, 639 m_cms.addSiteRoot(m_currentPageUri), 640 name); 641 for (CmsContainerElementBean subElement : result.getElements(true)) { 642 CmsInheritanceInfo inheritanceInfo = subElement.getInheritanceInfo(); 643 inheritanceInfo.setClientId(subElement.editorHash()); 644 inheritanceInfos.add(inheritanceInfo); 645 } 646 } else { 647 // setting a new id for name, will be persisted once the inheritance reference is edited and saved. 648 // use the structure id so it will always be the same for the resource 649 name = element.getResource().getStructureId().toString(); 650 } 651 elementData.setInheritanceInfos(inheritanceInfos); 652 elementData.setInheritanceName(name); 653 } else { 654 for (CmsContainer cnt : containers) { 655 boolean missesFormatterSetting = !elementData.getSettings().containsKey( 656 CmsFormatterConfig.getSettingsKeyForContainer(cnt.getName())); 657 if (missesFormatterSetting) { 658 if (element.getFormatterId() == null) { 659 I_CmsFormatterBean formatter = getStartFormatter( 660 m_cms, 661 cnt, 662 m_adeConfig, 663 element, 664 CmsADESessionCache.getCache(m_req, m_cms)); 665 if (formatter != null) { 666 elementData.getSettings().put( 667 CmsFormatterConfig.getSettingsKeyForContainer(cnt.getName()), 668 formatter.getId()); 669 element.addFormatterSetting(cnt.getName(), formatter.getKeyOrId()); 670 } 671 } else { 672 Map<String, I_CmsFormatterBean> formatterSelection = formatterConfiguraton.getFormatterSelection( 673 cnt.getType(), 674 cnt.getWidth()); 675 for (Entry<String, I_CmsFormatterBean> formatterEntry : formatterSelection.entrySet()) { 676 I_CmsFormatterBean formatter = formatterEntry.getValue(); 677 if (element.getFormatterId().equals(formatter.getJspStructureId())) { 678 elementData.getSettings().put( 679 CmsFormatterConfig.getSettingsKeyForContainer(cnt.getName()), 680 formatter.getKeyOrId()); 681 break; 682 } 683 } 684 } 685 } 686 } 687 // get the formatter configuration 688 Map<String, String> contentsByName = getContentsByContainerName(element, containers); 689 contents = contentsByName; 690 } 691 CmsListInfoBean listInfo = CmsVfsService.getPageInfo(m_cms, element.getResource()); 692 elementData.setListInfo(listInfo); 693 elementData.setContents(contents); 694 m_cms.getRequestContext().setLocale(requestLocale); 695 return elementData; 696 } 697 698 /** 699 * Returns the formatter and settings config data for an element.<p> 700 * 701 * @param page the current container page 702 * @param element the resource 703 * @param containerId the parent container id 704 * @param containers the containers on the current container page 705 * 706 * @return the data for an element 707 * 708 * @throws CmsException if something goes wrong 709 */ 710 public CmsElementSettingsConfig getElementSettingsConfig( 711 CmsResource page, 712 CmsContainerElementBean element, 713 String containerId, 714 Collection<CmsContainer> containers) 715 throws CmsException { 716 717 Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms); 718 CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfigurationWithCache(m_cms, page.getRootPath()); 719 boolean isCopyGroup = CmsResourceTypeXmlContainerPage.isModelCopyGroup(m_cms, page); 720 Locale requestLocale = m_cms.getRequestContext().getLocale(); 721 m_cms.getRequestContext().setLocale(m_locale); 722 element.initResource(m_cms); 723 if (element.getResource().isFolder()) { 724 return null; 725 } 726 String schema = null; 727 try { 728 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource()); 729 schema = type.getConfiguration().getString("schema", null); 730 } catch (Exception e) { 731 LOG.error(e.getLocalizedMessage(), e); 732 } 733 CmsContainerElementData elementData = getBaseElementData(page, element); 734 735 Map<String, String> settingUpdates = new HashMap<>(); 736 for (Map.Entry<String, String> entry : elementData.getSettings().entrySet()) { 737 int underscorePos = entry.getKey().indexOf("_"); 738 if ((underscorePos >= 0) && !isSystemSetting(entry.getKey())) { 739 String prefix = entry.getKey().substring(0, underscorePos); 740 I_CmsFormatterBean dynamicFmt = adeConfig.findFormatter(prefix, true); 741 742 if (CmsUUID.isValidUUID(prefix)) { 743 // If we already have a formatter referenced by name, we don't need to do anything 744 if ((dynamicFmt != null) && (dynamicFmt.getKey() != null)) { 745 // Replace setting prefix with formatter key 746 String newSettingName = dynamicFmt.getKey() + entry.getKey().substring(underscorePos); 747 settingUpdates.put(newSettingName, entry.getValue()); 748 settingUpdates.put(entry.getKey(), null); 749 } 750 } 751 } 752 753 if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) { 754 String value = entry.getValue(); 755 if (CmsUUID.isValidUUID(value)) { 756 I_CmsFormatterBean dynamicFmt = adeConfig.findFormatter(value); 757 if ((dynamicFmt != null) && (dynamicFmt.getKey() != null)) { 758 settingUpdates.put(entry.getKey(), dynamicFmt.getKey()); 759 } 760 } 761 } 762 } 763 for (String key : settingUpdates.keySet()) { 764 String value = settingUpdates.get(key); 765 if (value == null) { 766 elementData.getSettings().remove(key); 767 } else { 768 elementData.getSettings().put(key, value); 769 } 770 } 771 Supplier<CmsXmlContent> contentSupplier = Suppliers.memoize(() -> { 772 try { 773 return CmsXmlContentFactory.unmarshal(m_cms, m_cms.readFile(element.getResource())); 774 } catch (CmsException e) { 775 LOG.error(e.getLocalizedMessage(), e); 776 return null; 777 } 778 }); 779 I_CmsFormatterBean foundFormatter = null; 780 781 if (!element.isGroupContainer(m_cms) && !element.isInheritedContainer(m_cms)) { 782 CmsFormatterConfiguration formatterConfiguraton = getFormatterConfiguration(element.getResource()); 783 Map<String, CmsFormatterConfigCollection> formatters = new HashMap<String, CmsFormatterConfigCollection>(); 784 for (CmsContainer cnt : containers) { 785 if (cnt.getName().equals(containerId)) { 786 CmsFormatterConfigCollection containerFormatters = new CmsFormatterConfigCollection(); 787 String foundFormatterKey = null; 788 for (String containerName : new String[] {cnt.getName(), ""}) { 789 foundFormatterKey = elementData.getSettings().get( 790 CmsFormatterConfig.getSettingsKeyForContainer(containerName)); 791 if (foundFormatterKey != null) { 792 break; 793 } 794 } 795 boolean missesFormatterSetting = (foundFormatterKey == null); 796 if (!missesFormatterSetting) { 797 foundFormatter = adeConfig.findFormatter(foundFormatterKey); 798 } 799 Map<String, I_CmsFormatterBean> formatterSelection = formatterConfiguraton.getFormatterSelection( 800 cnt.getType(), 801 cnt.getWidth()); 802 for (Entry<String, I_CmsFormatterBean> formatterEntry : formatterSelection.entrySet()) { 803 I_CmsFormatterBean formatter = formatterEntry.getValue(); 804 String id = formatterEntry.getValue().getId(); 805 if (missesFormatterSetting 806 && ((element.getFormatterId() == null) 807 || element.getFormatterId().equals(formatter.getJspStructureId()))) { 808 elementData.getSettings().put( 809 CmsFormatterConfig.getSettingsKeyForContainer(cnt.getName()), 810 id); 811 missesFormatterSetting = false; 812 } 813 String label = formatter.getNiceName(OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms)); 814 if (formatterEntry.getKey().startsWith(CmsFormatterConfig.SCHEMA_FORMATTER_ID)) { 815 label = Messages.get().getBundle().key(Messages.GUI_SCHEMA_FORMATTER_LABEL_0) 816 + " [" 817 + CmsResource.getName(formatter.getJspRootPath()) 818 + "]"; 819 } 820 if (CmsStringUtil.isEmptyOrWhitespaceOnly(label)) { 821 label = id; 822 } 823 CmsFormatterConfig config = new CmsFormatterConfig(id); 824 Set<String> cssResources = new LinkedHashSet<String>(); 825 for (String cssSitePath : formatter.getCssHeadIncludes()) { 826 cssResources.add(OpenCms.getLinkManager().getOnlineLink(m_cms, cssSitePath)); 827 } 828 config.setCssResources(cssResources); 829 config.setInlineCss(formatter.getInlineCss()); 830 config.setKey(formatter.getKey()); 831 config.setLabel(label); 832 config.setDescription( 833 formatter.getDescription(OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms))); 834 Map<String, CmsXmlContentProperty> settingsConfig = OpenCms.getADEManager().getFormatterSettings( 835 m_cms, 836 adeConfig, 837 formatter, 838 element.getResource(), 839 m_locale, 840 m_req); 841 Function<String, String> templateSource = createStringTemplateSource( 842 formatter, 843 contentSupplier); 844 settingsConfig = CmsXmlContentPropertyHelper.resolveMacrosForPropertyInfo( 845 m_cms, 846 page, 847 element.getResource(), 848 contentSupplier, 849 templateSource, 850 settingsConfig); 851 config.setSettingConfig(settingsConfig); 852 List<I_CmsFormatterBean> nestedFormatters = OpenCms.getADEManager().getNestedFormatters( 853 m_cms, 854 adeConfig, 855 element.getResource(), 856 m_locale, 857 m_req); 858 if ((nestedFormatters != null) && !nestedFormatters.isEmpty()) { 859 Map<String, String> settingPrefixes = new LinkedHashMap<String, String>(); 860 for (I_CmsFormatterBean nested : nestedFormatters) { 861 String sectionLabel = nested.getNiceName( 862 OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms)); 863 settingPrefixes.put(nested.getId(), sectionLabel); 864 if (nested.getKey() != null) { 865 settingPrefixes.put(nested.getKey() + "_", sectionLabel); 866 } 867 } 868 config.setNestedFormatterPrefixes(settingPrefixes); 869 } 870 871 config.setJspRootPath(formatter.getJspRootPath()); 872 containerFormatters.add(config); 873 } 874 formatters.put(cnt.getName(), containerFormatters); 875 } 876 } 877 elementData.setFormatters(formatters); 878 } 879 880 m_cms.getRequestContext().setLocale(requestLocale); 881 ArrayList<CmsAdditionalInfoBean> infos = new ArrayList<>(); 882 883 CmsResource resource = element.getResource(); 884 String resTypeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName(); 885 CmsExplorerTypeSettings cmsExplorerTypeSettings = OpenCms.getWorkplaceManager().getExplorerTypeSetting( 886 resTypeName); 887 if (null == cmsExplorerTypeSettings) { 888 CmsMessageContainer errMsg = org.opencms.gwt.Messages.get().container( 889 org.opencms.gwt.Messages.ERR_EXPLORER_TYPE_SETTINGS_FOR_RESOURCE_TYPE_NOT_FOUND_3, 890 resource.getRootPath(), 891 resTypeName, 892 Integer.valueOf(resource.getTypeId())); 893 throw new CmsConfigurationException(errMsg); 894 } 895 String key = cmsExplorerTypeSettings.getKey(); 896 Locale currentLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms); 897 CmsMessages messages = OpenCms.getWorkplaceManager().getMessages(currentLocale); 898 String resTypeNiceName = messages.key(key); 899 infos.add( 900 new CmsAdditionalInfoBean( 901 messages.key(org.opencms.workplace.commons.Messages.GUI_LABEL_TYPE_0), 902 resTypeNiceName, 903 null)); 904 905 try { 906 CmsRelationFilter filter = CmsRelationFilter.relationsFromStructureId( 907 element.getResource().getStructureId()).filterType(CmsRelationType.XSD); 908 for (CmsRelation relation : m_cms.readRelations(filter)) { 909 CmsResource target = relation.getTarget(m_cms, CmsResourceFilter.IGNORE_EXPIRATION); 910 String label = Messages.get().getBundle(wpLocale).key(Messages.GUI_ADDINFO_SCHEMA_0); 911 infos.add(new CmsAdditionalInfoBean(label, target.getRootPath(), null)); 912 break; 913 } 914 } catch (CmsException e) { 915 LOG.error(e.getLocalizedMessage(), e); 916 } 917 if (foundFormatter != null) { 918 Map<String, String> formatterInfo = CmsDefaultResourceStatusProvider.getFormatterInfo( 919 m_cms, 920 foundFormatter); 921 for (Map.Entry<String, String> entry : formatterInfo.entrySet()) { 922 infos.add(new CmsAdditionalInfoBean(entry.getKey(), entry.getValue(), null)); 923 } 924 } 925 926 CmsResourceState state = element.getResource().getState(); 927 return new CmsElementSettingsConfig(elementData, state, infos, schema, isCopyGroup); 928 } 929 930 /** 931 * Gets the container page.<p> 932 * 933 * @return the container page resource 934 */ 935 public CmsResource getPage() { 936 937 return m_page; 938 } 939 940 /** 941 * Sets the data to the given container element.<p> 942 * 943 * @param elementBean the element bean 944 * @param result the container element to set the data to 945 * 946 * @return the container element 947 * 948 * @throws CmsException if something goes wrong 949 */ 950 public CmsContainerElement setElementInfo(CmsContainerElementBean elementBean, CmsContainerElement result) 951 throws CmsException { 952 953 Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms); 954 // reinitializing resource to avoid caching issues 955 elementBean.initResource(m_cms); 956 CmsResource resource = elementBean.getResource(); 957 boolean isModelGroup = elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_ID); 958 if (isModelGroup) { 959 CmsUUID groupId = new CmsUUID(elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_ID)); 960 resource = m_cms.readResource(groupId, CmsResourceFilter.IGNORE_EXPIRATION); 961 } 962 963 boolean newEditorDisabled = !CmsWorkplaceEditorManager.checkAcaciaEditorAvailable( 964 m_cms, 965 elementBean.getResource()); 966 result.setNewEditorDisabled(newEditorDisabled); 967 I_CmsResourceType resourceType = OpenCms.getResourceManager().getResourceType(resource); 968 String typeName = resourceType.getTypeName(); 969 result.setHasEditHandler( 970 (resourceType instanceof CmsResourceTypeXmlContent) 971 && (((CmsResourceTypeXmlContent)resourceType).getEditHandler(m_cms) != null)); 972 result.setResourceType(typeName); 973 result.setIconClasses( 974 CmsIconUtil.getIconClasses( 975 CmsIconUtil.getDisplayType(m_cms, resource), 976 elementBean.getResource().getName(), 977 false)); 978 CmsPermissionInfo permissionInfo; 979 String title; 980 String subTitle; 981 if (!elementBean.isInMemoryOnly()) { 982 CmsElementLockInfo lockInfo = getLockInfo(m_cms, resource); 983 result.setLockInfo(lockInfo); 984 permissionInfo = OpenCms.getADEManager().getPermissionInfo(m_cms, resource, m_page.getRootPath()); 985 if (CmsResourceTypeXmlContent.isXmlContent(resource)) { 986 if (CmsStringUtil.isEmptyOrWhitespaceOnly(permissionInfo.getNoEditReason()) 987 && elementBean.isInheritedContainer(m_cms)) { 988 String requestUri = m_cms.getRequestContext().getUri(); 989 String folderPath = CmsResource.getFolderPath(requestUri); 990 String configPath = CmsStringUtil.joinPaths( 991 folderPath, 992 CmsContainerConfigurationCache.INHERITANCE_CONFIG_FILE_NAME); 993 if (m_cms.existsResource(configPath)) { 994 permissionInfo.setNoEditReason( 995 new CmsResourceUtil(m_cms, m_cms.readResource(configPath)).getNoEditReason(wpLocale, true)); 996 } else { 997 if (!m_cms.getLock(folderPath).isLockableBy(m_cms.getRequestContext().getCurrentUser())) { 998 permissionInfo.setNoEditReason( 999 org.opencms.workplace.explorer.Messages.get().getBundle(wpLocale).key( 1000 org.opencms.workplace.explorer.Messages.GUI_NO_EDIT_REASON_LOCK_1, 1001 new CmsResourceUtil(m_cms, m_cms.readResource(folderPath)).getLockedByName())); 1002 } 1003 } 1004 } 1005 } else { 1006 permissionInfo.setNoEditReason( 1007 Messages.get().getBundle(wpLocale).key(Messages.GUI_ELEMENT_RESOURCE_CAN_NOT_BE_EDITED_0)); 1008 } 1009 1010 try { 1011 CmsProperty namePatternProp = m_cms.readPropertyObject( 1012 resource, 1013 CmsPropertyDefinition.PROPERTY_CONTENT_NAME_PATTERN, 1014 true); 1015 String namePattern = namePatternProp.getValue(); 1016 if ((namePattern != null) && !"none".equals(namePattern)) { 1017 result.setHasNamePatternProperty(true); 1018 } 1019 } catch (CmsException e) { 1020 LOG.error(e.getLocalizedMessage(), e); 1021 } 1022 1023 CmsGallerySearchResult searchResult = CmsGallerySearch.searchById( 1024 m_cms, 1025 resource.getStructureId(), 1026 m_locale); 1027 title = searchResult.getTitle(); 1028 if (CmsStringUtil.isEmptyOrWhitespaceOnly(title)) { 1029 resource.getName(); 1030 } 1031 subTitle = searchResult.getUserLastModified(); 1032 Date lastModDate = searchResult.getDateLastModified(); 1033 if (lastModDate != null) { 1034 subTitle += " / " + CmsDateUtil.getDateTime(lastModDate, DateFormat.MEDIUM, wpLocale); 1035 } 1036 } else { 1037 permissionInfo = new CmsPermissionInfo(true, true, ""); 1038 title = CmsWorkplaceMessages.getResourceTypeName(wpLocale, typeName); 1039 subTitle = CmsWorkplaceMessages.getResourceTypeDescription(wpLocale, typeName); 1040 } 1041 result.setTitle(title); 1042 result.setSubTitle(subTitle); 1043 result.setClientId(elementBean.editorHash()); 1044 result.setSitePath(m_cms.getSitePath(resource)); 1045 1046 result.setCreateNew(elementBean.isCreateNew()); 1047 CmsResourceTypeConfig typeConfig = getConfigData().getResourceType(typeName); 1048 if (!elementBean.isInMemoryOnly() && (typeConfig != null)) { 1049 result.setCopyInModels(typeConfig.isCopyInModels()); 1050 if (typeConfig.isCheckReuse()) { 1051 final Set<CmsUUID> pageAndAttachments = getPageAndDetailOnlyIds(); 1052 boolean reused = OpenCms.getADEManager().isElementReused( 1053 resource, 1054 res -> pageAndAttachments.contains(res.getStructureId())); 1055 result.setReused(reused); 1056 } 1057 } 1058 1059 Map<CmsUUID, CmsElementView> viewMap = OpenCms.getADEManager().getElementViews(m_cms); 1060 1061 boolean isModelGroupEditing = CmsModelGroupHelper.isModelGroupResource(m_page); 1062 if (!isModelGroup 1063 && isModelGroupEditing 1064 && elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_STATE) 1065 && (ModelGroupState.isModelGroup == ModelGroupState.evaluate( 1066 elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_STATE)))) { 1067 isModelGroup = true; 1068 } 1069 if (!isModelGroupEditing && isModelGroup) { 1070 CmsResourceTypeConfig modelGroupConfig = getConfigData().getResourceType( 1071 CmsResourceTypeXmlContainerPage.MODEL_GROUP_TYPE_NAME); 1072 if (modelGroupConfig != null) { 1073 CmsUUID elementView = modelGroupConfig.getElementView(); 1074 CmsElementView viewObject = viewMap.get(elementView); 1075 if ((viewObject != null) && (viewObject.getParentViewId() != null)) { 1076 elementView = viewObject.getParentViewId(); 1077 } 1078 result.setElementView(elementView); 1079 } 1080 } else if (typeConfig != null) { 1081 CmsUUID elementView = typeConfig.getElementView(); 1082 CmsElementView viewObject = viewMap.get(elementView); 1083 if ((viewObject != null) && (viewObject.getParentViewId() != null)) { 1084 elementView = viewObject.getParentViewId(); 1085 } 1086 result.setElementView(elementView); 1087 } 1088 if (CmsStringUtil.isEmptyOrWhitespaceOnly(permissionInfo.getNoEditReason()) 1089 && ((typeConfig == null) || typeConfig.isEditDisabled())) { 1090 String message = Messages.get().getBundle(wpLocale).key( 1091 Messages.GUI_CONTAINERPAGE_EDIT_DISABLED_BY_SITEMAP_CONFIG_0); 1092 permissionInfo.setNoEditReason(message); 1093 } 1094 result.setHasSettings(hasSettings(m_cms, elementBean.getResource())); 1095 result.setPermissionInfo(permissionInfo); 1096 result.setReleasedAndNotExpired(elementBean.isReleasedAndNotExpired()); 1097 if (elementBean.isModelGroup()) { 1098 String modelId = elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_ID); 1099 result.setModelGroupId(modelId != null ? new CmsUUID(modelId) : CmsUUID.getNullUUID()); 1100 } 1101 result.setWasModelGroup( 1102 elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_STATE) 1103 && (ModelGroupState.evaluate( 1104 elementBean.getIndividualSettings().get( 1105 CmsContainerElement.MODEL_GROUP_STATE)) == ModelGroupState.wasModelGroup)); 1106 return result; 1107 } 1108 1109 /** 1110 * Returns the formatter configuration for the given element resource.<p> 1111 * 1112 * @param resource the element resource 1113 * 1114 * @return the formatter configuration 1115 */ 1116 CmsFormatterConfiguration getFormatterConfiguration(CmsResource resource) { 1117 1118 return getConfigData().getFormatters(m_cms, resource); 1119 } 1120 1121 /** 1122 * Returns the base element data for the given element bean, without content or formatter info.<p> 1123 * 1124 * @param page the current container page 1125 * @param element the resource 1126 * 1127 * @return base element data 1128 * 1129 * @throws CmsException in case reading the data fails 1130 */ 1131 private CmsContainerElementData getBaseElementData(CmsResource page, CmsContainerElementBean element) 1132 throws CmsException { 1133 1134 CmsResourceUtil resUtil = new CmsResourceUtil(m_cms, element.getResource()); 1135 CmsContainerElementData elementData = new CmsContainerElementData(); 1136 setElementInfo(element, elementData); 1137 elementData.setLoadTime(System.currentTimeMillis()); 1138 elementData.setLastModifiedDate(element.getResource().getDateLastModified()); 1139 String userName = null; 1140 try { 1141 CmsUser user = m_cms.readUser(element.getResource().getUserLastModified()); 1142 userName = user.getName(); 1143 } catch (CmsException e) { 1144 userName = "" + element.getResource().getUserLastModified(); 1145 LOG.debug(e.getLocalizedMessage(), e); 1146 } 1147 elementData.setLastModifiedByUser(userName); 1148 elementData.setNavText(resUtil.getNavText()); 1149 Map<String, CmsXmlContentProperty> settingConfig = CmsXmlContentPropertyHelper.getPropertyInfo( 1150 m_cms, 1151 page, 1152 element.getResource()); 1153 elementData.setSettings( 1154 CmsXmlContentPropertyHelper.convertPropertiesToClientFormat( 1155 m_cms, 1156 element.getIndividualSettings(), 1157 settingConfig)); 1158 return elementData; 1159 } 1160 1161 /** 1162 * Returns the ADE configuration data for the current URI.<p> 1163 * 1164 * @return the ADE configuration data 1165 */ 1166 private CmsADEConfigData getConfigData() { 1167 1168 if (m_adeConfig == null) { 1169 m_adeConfig = OpenCms.getADEManager().lookupConfigurationWithCache( 1170 m_cms, 1171 m_cms.addSiteRoot(m_currentPageUri)); 1172 } 1173 return m_adeConfig; 1174 } 1175 1176 /** 1177 * Returns the HTML content of the given element and container.<p> 1178 * 1179 * @param element the element 1180 * @param container the container 1181 * @param configs the formatter configurations 1182 * 1183 * @return the HTML content 1184 */ 1185 private String getContentByContainer( 1186 CmsContainerElementBean element, 1187 CmsContainer container, 1188 CmsFormatterConfiguration configs) { 1189 1190 String content = null; 1191 1192 I_CmsFormatterBean formatter = getFormatterForContainer( 1193 m_cms, 1194 element, 1195 container, 1196 m_adeConfig, 1197 CmsADESessionCache.getCache(m_req, m_cms)); 1198 if (formatter != null) { 1199 element = element.clone(); // clone element because presets for different containers may be different 1200 element.initSettings(m_cms, m_adeConfig, formatter, m_locale, m_req, container.getSettingPresets()); 1201 try { 1202 content = getElementContent(element, m_cms.readResource(formatter.getJspStructureId()), container); 1203 // } 1204 } catch (Exception e) { 1205 LOG.error(e.getLocalizedMessage(), e); 1206 } 1207 if (content != null) { 1208 content = removeScriptTags(content); 1209 } 1210 } 1211 return content; 1212 } 1213 1214 /** 1215 * Returns the rendered element content for all the given containers. 1216 * 1217 * @param element the element to render 1218 * @param containers the containers the element appears in 1219 * 1220 * @return a map from container names to rendered page contents 1221 */ 1222 private Map<String, String> getContentsByContainerName( 1223 CmsContainerElementBean element, 1224 Collection<CmsContainer> containers) { 1225 1226 CmsFormatterConfiguration configs = getFormatterConfiguration(element.getResource()); 1227 Map<String, String> result = new HashMap<String, String>(); 1228 for (CmsContainer container : containers) { 1229 String content = getContentByContainer(element, container, configs); 1230 if (content != null) { 1231 content = removeScriptTags(content); 1232 } 1233 result.put(container.getName(), content); 1234 } 1235 return result; 1236 } 1237 1238 /** 1239 * Returns the content of an element when rendered with the given formatter.<p> 1240 * 1241 * @param element the element bean 1242 * @param formatter the formatter uri 1243 * @param container the container for which the element content should be retrieved 1244 * 1245 * @return generated html code 1246 * 1247 * @throws CmsException if an cms related error occurs 1248 * @throws ServletException if a jsp related error occurs 1249 * 1250 * @throws IOException if a jsp related error occurs 1251 */ 1252 private String getElementContent(CmsContainerElementBean element, CmsResource formatter, CmsContainer container) 1253 throws CmsException, ServletException, IOException { 1254 1255 element.initResource(m_cms); 1256 TemplateBean templateBean = CmsADESessionCache.getCache(m_req, m_cms).getTemplateBean( 1257 m_cms.addSiteRoot(m_currentPageUri), 1258 true); 1259 String oldUri = m_cms.getRequestContext().getUri(); 1260 try { 1261 m_cms.getRequestContext().setUri(m_currentPageUri); 1262 CmsContainerBean containerBean = null; 1263 if ((m_standardContext.getPage() != null) 1264 && m_standardContext.getPage().getContainers().containsKey(container.getName())) { 1265 containerBean = m_standardContext.getPage().getContainers().get(container.getName()); 1266 } else { 1267 containerBean = CmsElementUtil.clientToServerContainer( 1268 container, 1269 Collections.<CmsContainerElementBean> emptyList()); 1270 } 1271 if (containerBean.getWidth() == null) { 1272 containerBean.setWidth(String.valueOf(container.getWidth())); 1273 } 1274 containerBean.setDetailOnly(container.isDetailOnly()); 1275 m_standardContext.setContainer(containerBean); 1276 m_standardContext.setElement(element); 1277 m_standardContext.setEdited(true); 1278 // to enable 'old' direct edit features for content-collector-elements, 1279 // set the direct-edit-provider-attribute in the request 1280 I_CmsDirectEditProvider eb = new CmsAdvancedDirectEditProvider(); 1281 eb.init(m_cms, CmsDirectEditMode.TRUE, element.getSitePath()); 1282 m_req.setAttribute(I_CmsDirectEditProvider.ATTRIBUTE_DIRECT_EDIT_PROVIDER, eb); 1283 m_req.setAttribute(CmsTemplateContextManager.ATTR_TEMPLATE_BEAN, templateBean); 1284 String encoding = m_res.getCharacterEncoding(); 1285 return (new String( 1286 OpenCms.getResourceManager().getLoader(formatter).dump(m_cms, formatter, null, m_locale, m_req, m_res), 1287 encoding)).trim(); 1288 } finally { 1289 m_cms.getRequestContext().setUri(oldUri); 1290 } 1291 } 1292 1293 /** 1294 * Gets the lock information. 1295 * 1296 * @param cms the current CMS context 1297 * @param resource the resource for which to get lock information 1298 * @return the lock information 1299 */ 1300 private CmsElementLockInfo getLockInfo(CmsObject cms, CmsResource resource) { 1301 1302 try { 1303 CmsLock lock = cms.getLock(resource); 1304 CmsUUID owner = lock.getUserId(); 1305 boolean isPublish = lock.isPublish(); 1306 return new CmsElementLockInfo(owner, isPublish); 1307 } catch (Exception e) { 1308 LOG.error(e.getLocalizedMessage(), e); 1309 return new CmsElementLockInfo(null, false); 1310 } 1311 } 1312 1313 /** 1314 * Gets the ids for the current page and potentially detail-only containers. 1315 * 1316 * @return the set of ids for the current page and detail-only containers 1317 */ 1318 private Set<CmsUUID> getPageAndDetailOnlyIds() { 1319 1320 Set<CmsUUID> result = new HashSet<>(); 1321 result.add(m_page.getStructureId()); 1322 CmsResource detailContent = (CmsResource)m_req.getAttribute( 1323 CmsDetailPageResourceHandler.ATTR_DETAIL_CONTENT_RESOURCE); 1324 if (detailContent != null) { 1325 for (CmsResource detailOnlyRes : CmsDetailOnlyContainerUtil.getDetailOnlyResources(m_cms, detailContent)) { 1326 result.add(detailOnlyRes.getStructureId()); 1327 } 1328 } 1329 return result; 1330 } 1331 1332 /** 1333 * Helper method for checking whether there are properties defined for a given content element.<p> 1334 * 1335 * @param cms the CmsObject to use for VFS operations 1336 * @param resource the resource for which it should be checked whether it has properties 1337 * 1338 * @return true if the resource has properties defined 1339 * 1340 * @throws CmsException if something goes wrong 1341 */ 1342 private boolean hasSettings(CmsObject cms, CmsResource resource) throws CmsException { 1343 1344 if (!CmsResourceTypeXmlContent.isXmlContent(resource)) { 1345 return false; 1346 } 1347 1348 CmsADEConfigData config = getConfigData(); 1349 CmsFormatterConfiguration formatters = config.getFormatters(m_cms, resource); 1350 boolean result = (formatters.getAllFormatters().size() > 1) 1351 || !CmsXmlContentPropertyHelper.getPropertyInfo(m_cms, null, resource).isEmpty(); 1352 if (!result && (formatters.getAllFormatters().size() == 1)) { 1353 result = (formatters.getAllFormatters().get(0).getSettings(config).size() > 0); 1354 } 1355 return result; 1356 } 1357 1358 /** 1359 * Parses the given request parameters string into a parameter map.<p> 1360 * 1361 * @param requestParameters the request parameters to parse 1362 * 1363 * @return the parameter map 1364 */ 1365 private Map<String, Object> parseRequestParameters(String requestParameters) { 1366 1367 Map<String, Object> parameterMap; 1368 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(requestParameters)) { 1369 parameterMap = new HashMap<String, Object>(); 1370 String[] params = requestParameters.split("&"); 1371 for (int i = 0; i < params.length; i++) { 1372 int position = params[i].indexOf("="); 1373 if (position >= 0) { 1374 String key = params[i].substring(0, position); 1375 String value = params[i].substring(position + 1); 1376 if (value.contains(",")) { 1377 parameterMap.put(key, value.split(",")); 1378 } else { 1379 parameterMap.put(key, value); 1380 } 1381 } 1382 } 1383 } else { 1384 parameterMap = Collections.<String, Object> emptyMap(); 1385 } 1386 return parameterMap; 1387 } 1388 1389 /** 1390 * Removes all script tags from given input.<p> 1391 * 1392 * @param input the input to remove script tags from 1393 * 1394 * @return the cleaned input 1395 */ 1396 private String removeScriptTags(String input) { 1397 1398 Document doc = Jsoup.parseBodyFragment(input); 1399 Elements scriptTags = doc.select("script"); 1400 String output = input; 1401 if (scriptTags.size() > 0) { 1402 scriptTags.remove(); 1403 doc.outputSettings().prettyPrint(false); 1404 output = doc.body().html(); 1405 } 1406 return output; 1407 } 1408}