001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (C) Alkacon Software (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.ade.configuration; 029 030import org.opencms.ade.configuration.CmsADEConfigData.DetailInfo; 031import org.opencms.ade.configuration.CmsElementView.ElementViewComparator; 032import org.opencms.ade.configuration.formatters.CmsFormatterConfigurationCache; 033import org.opencms.ade.configuration.formatters.CmsFormatterConfigurationCacheState; 034import org.opencms.ade.containerpage.inherited.CmsContainerConfigurationCache; 035import org.opencms.ade.containerpage.inherited.CmsContainerConfigurationWriter; 036import org.opencms.ade.containerpage.inherited.CmsInheritedContainerState; 037import org.opencms.ade.detailpage.CmsDetailPageConfigurationWriter; 038import org.opencms.ade.detailpage.CmsDetailPageInfo; 039import org.opencms.ade.detailpage.CmsSitemapDetailPageFinder; 040import org.opencms.ade.detailpage.I_CmsDetailPageFinder; 041import org.opencms.configuration.CmsSystemConfiguration; 042import org.opencms.db.I_CmsProjectDriver; 043import org.opencms.file.CmsFile; 044import org.opencms.file.CmsObject; 045import org.opencms.file.CmsProject; 046import org.opencms.file.CmsRequestContext; 047import org.opencms.file.CmsResource; 048import org.opencms.file.CmsResourceFilter; 049import org.opencms.file.CmsUser; 050import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 051import org.opencms.file.types.CmsResourceTypeXmlContent; 052import org.opencms.file.types.I_CmsResourceType; 053import org.opencms.gwt.shared.CmsPermissionInfo; 054import org.opencms.gwt.shared.CmsTemplateContextInfo; 055import org.opencms.i18n.CmsEncoder; 056import org.opencms.i18n.CmsLocaleManager; 057import org.opencms.json.JSONArray; 058import org.opencms.json.JSONException; 059import org.opencms.json.JSONObject; 060import org.opencms.jsp.CmsJspNavBuilder; 061import org.opencms.jsp.CmsJspNavElement; 062import org.opencms.jsp.CmsJspTagLink; 063import org.opencms.jsp.util.CmsJspStandardContextBean; 064import org.opencms.loader.CmsLoaderException; 065import org.opencms.main.CmsException; 066import org.opencms.main.CmsLog; 067import org.opencms.main.OpenCms; 068import org.opencms.monitor.CmsMemoryMonitor; 069import org.opencms.security.CmsPermissionSet; 070import org.opencms.util.CmsRequestUtil; 071import org.opencms.util.CmsStringUtil; 072import org.opencms.util.CmsUUID; 073import org.opencms.util.CmsWaitHandle; 074import org.opencms.workplace.explorer.CmsExplorerTypeSettings; 075import org.opencms.workplace.explorer.CmsResourceUtil; 076import org.opencms.xml.CmsXmlContentDefinition; 077import org.opencms.xml.CmsXmlException; 078import org.opencms.xml.containerpage.CmsADECache; 079import org.opencms.xml.containerpage.CmsADECacheSettings; 080import org.opencms.xml.containerpage.CmsContainerElementBean; 081import org.opencms.xml.containerpage.I_CmsFormatterBean; 082import org.opencms.xml.containerpage.Messages; 083import org.opencms.xml.content.CmsXmlContent; 084import org.opencms.xml.content.CmsXmlContentFactory; 085import org.opencms.xml.content.CmsXmlContentProperty; 086import org.opencms.xml.content.CmsXmlContentProperty.Visibility; 087import org.opencms.xml.content.CmsXmlContentPropertyHelper; 088import org.opencms.xml.content.I_CmsXmlContentHandler; 089import org.opencms.xml.types.I_CmsXmlContentValue; 090 091import java.util.ArrayList; 092import java.util.Arrays; 093import java.util.Collections; 094import java.util.HashMap; 095import java.util.HashSet; 096import java.util.Iterator; 097import java.util.LinkedHashMap; 098import java.util.List; 099import java.util.Locale; 100import java.util.Map; 101import java.util.Map.Entry; 102import java.util.Set; 103 104import javax.servlet.ServletRequest; 105import javax.servlet.http.HttpServletRequest; 106import javax.servlet.http.HttpServletResponse; 107 108import org.apache.commons.logging.Log; 109 110import com.google.common.collect.Lists; 111import com.google.common.collect.Maps; 112 113/** 114 * This is the main class used to access the ADE configuration and also accomplish some other related tasks 115 * like loading/saving favorite and recent lists.<p> 116 */ 117public class CmsADEManager { 118 119 /** JSON property name constant. */ 120 protected enum FavListProp { 121 /** element property. */ 122 ELEMENT, 123 /** formatter property. */ 124 FORMATTER, 125 /** properties property. */ 126 PROPERTIES; 127 } 128 129 /** 130 * A status enum for the initialization status.<p> 131 */ 132 protected enum Status { 133 /** already initialized. */ 134 initialized, 135 /** currently initializing. */ 136 initializing, 137 /** not initialized. */ 138 notInitialized 139 } 140 141 /** The client id separator. */ 142 public static final String CLIENT_ID_SEPERATOR = "#"; 143 144 /** The configuration file name. */ 145 public static final String CONFIG_FILE_NAME = ".config"; 146 147 /** The name of the sitemap configuration file type. */ 148 public static final String CONFIG_FOLDER_TYPE = "content_folder"; 149 150 /** The path for sitemap configuration files relative from the base path. */ 151 public static final String CONFIG_SUFFIX = "/" 152 + CmsADEManager.CONTENT_FOLDER_NAME 153 + "/" 154 + CmsADEManager.CONFIG_FILE_NAME; 155 156 /** The name of the sitemap configuration file type. */ 157 public static final String CONFIG_TYPE = "sitemap_config"; 158 159 /** The content folder name. */ 160 public static final String CONTENT_FOLDER_NAME = ".content"; 161 162 /** Default favorite/recent list size constant. */ 163 public static final int DEFAULT_ELEMENT_LIST_SIZE = 10; 164 165 /** The default detail page type name. */ 166 public static final String DEFAULT_DETAILPAGE_TYPE = "##DEFAULT##"; 167 168 /** The name of the element view configuration file type. */ 169 public static final String ELEMENT_VIEW_TYPE = "elementview"; 170 171 /** The name of the module configuration file type. */ 172 public static final String MODULE_CONFIG_TYPE = "module_config"; 173 174 /** The aADE configuration module name. */ 175 public static final String MODULE_NAME_ADE_CONFIG = "org.opencms.base"; 176 177 /** Node name for the nav level link value. */ 178 public static final String N_LINK = "Link"; 179 180 /** Node name for the nav level type value. */ 181 public static final String N_TYPE = "Type"; 182 183 /** The path to the sitemap editor JSP. */ 184 public static final String PATH_SITEMAP_EDITOR_JSP = "/system/workplace/commons/sitemap.jsp"; 185 186 /** User additional info key constant. */ 187 protected static final String ADDINFO_ADE_FAVORITE_LIST = "ADE_FAVORITE_LIST"; 188 189 /** User additional info key constant. */ 190 protected static final String ADDINFO_ADE_RECENT_LIST = "ADE_RECENT_LIST"; 191 192 /** User additional info key constant. */ 193 protected static final String ADDINFO_ADE_SHOW_EDITOR_HELP = "ADE_SHOW_EDITOR_HELP"; 194 195 /** The logger instance for this class. */ 196 private static final Log LOG = CmsLog.getLog(CmsADEManager.class); 197 198 /** The cache instance. */ 199 private CmsADECache m_cache; 200 201 /** The sitemap configuration file type. */ 202 private I_CmsResourceType m_configType; 203 204 /** The detail page finder. */ 205 private I_CmsDetailPageFinder m_detailPageFinder = new CmsSitemapDetailPageFinder(); 206 207 /** The element view configuration file type. */ 208 private I_CmsResourceType m_elementViewType; 209 210 /** The initialization status. */ 211 private Status m_initStatus = Status.notInitialized; 212 213 /** The module configuration file type. */ 214 private I_CmsResourceType m_moduleConfigType; 215 216 /** The online cache instance. */ 217 private CmsConfigurationCache m_offlineCache; 218 219 /** The offline CMS context. */ 220 private CmsObject m_offlineCms; 221 222 /** The offline inherited container configuration cache. */ 223 private CmsContainerConfigurationCache m_offlineContainerConfigurationCache; 224 225 /** The detail id cache for the Offline project. */ 226 private CmsDetailNameCache m_offlineDetailIdCache; 227 228 /** The offline formatter bean cache. */ 229 private CmsFormatterConfigurationCache m_offlineFormatterCache; 230 231 /** The offline cache instance. */ 232 private CmsConfigurationCache m_onlineCache; 233 234 /** The online CMS context. */ 235 private CmsObject m_onlineCms; 236 237 /** The online inherited container configuration cache. */ 238 private CmsContainerConfigurationCache m_onlineContainerConfigurationCache; 239 240 /** The Online project detail id cache. */ 241 private CmsDetailNameCache m_onlineDetailIdCache; 242 243 /** The online formatter bean cache. */ 244 private CmsFormatterConfigurationCache m_onlineFormatterCache; 245 246 /** ADE parameters. */ 247 private Map<String, String> m_parameters; 248 249 /** 250 * Creates a new ADE manager.<p> 251 * 252 * @param adminCms a CMS context with admin privileges 253 * @param memoryMonitor the memory monitor instance 254 * @param systemConfiguration the system configuration 255 */ 256 public CmsADEManager( 257 CmsObject adminCms, 258 CmsMemoryMonitor memoryMonitor, 259 CmsSystemConfiguration systemConfiguration) { 260 261 // initialize the ade cache 262 CmsADECacheSettings cacheSettings = systemConfiguration.getAdeCacheSettings(); 263 if (cacheSettings == null) { 264 cacheSettings = new CmsADECacheSettings(); 265 } 266 m_onlineCms = adminCms; 267 m_cache = new CmsADECache(memoryMonitor, cacheSettings); 268 m_parameters = new LinkedHashMap<String, String>(systemConfiguration.getAdeParameters()); 269 // further initialization is done by the initialize() method. We don't do that in the constructor, 270 // because during the setup the configuration resource types don't exist yet. 271 } 272 273 /** 274 * Adds a wait handle for the next cache update to a formatter configuration.<p> 275 * 276 * @param online true if we want to add a wait handle to the online cache, else the offline cache 277 * @return the wait handle that has been added 278 */ 279 public CmsWaitHandle addFormatterCacheWaitHandle(boolean online) { 280 281 CmsWaitHandle handle = new CmsWaitHandle(true); // single use wait handle 282 CmsFormatterConfigurationCache cache = online ? m_onlineFormatterCache : m_offlineFormatterCache; 283 cache.addWaitHandle(handle); 284 return handle; 285 286 } 287 288 /** 289 * Finds the entry point to a sitemap.<p> 290 * 291 * @param cms the CMS context 292 * @param openPath the resource path to find the sitemap to 293 * 294 * @return the sitemap entry point 295 */ 296 public String findEntryPoint(CmsObject cms, String openPath) { 297 298 CmsADEConfigData configData = lookupConfiguration(cms, openPath); 299 String result = configData.getBasePath(); 300 if (result == null) { 301 return cms.getRequestContext().addSiteRoot("/"); 302 } 303 return result; 304 } 305 306 /** 307 * Flushes inheritance group changes so the cache is updated.<p> 308 * 309 * This is useful for test cases. 310 */ 311 public void flushInheritanceGroupChanges() { 312 313 m_offlineContainerConfigurationCache.flushUpdates(); 314 m_onlineContainerConfigurationCache.flushUpdates(); 315 } 316 317 /** 318 * Gets the complete list of beans for the currently configured detail pages.<p> 319 * 320 * @param cms the CMS context to use 321 * 322 * @return the list of detail page infos 323 */ 324 public List<CmsDetailPageInfo> getAllDetailPages(CmsObject cms) { 325 326 return getCacheState(isOnline(cms)).getAllDetailPages(); 327 } 328 329 /** 330 * Gets the containerpage cache instance.<p> 331 * 332 * @return the containerpage cache instance 333 */ 334 public CmsADECache getCache() { 335 336 return m_cache; 337 } 338 339 /** 340 * Gets the cached formatter beans.<p> 341 * 342 * @param online true if the Online project formatters should be returned, false for the Offline formatters 343 * 344 * @return the formatter configuration cache state 345 */ 346 public CmsFormatterConfigurationCacheState getCachedFormatters(boolean online) { 347 348 CmsFormatterConfigurationCache cache = online ? m_onlineFormatterCache : m_offlineFormatterCache; 349 return cache.getState(); 350 } 351 352 /** 353 * Gets the configuration file type.<p> 354 * 355 * @return the configuration file type 356 */ 357 public I_CmsResourceType getConfigurationType() { 358 359 return m_configType; 360 } 361 362 /** 363 * Returns the names of the bundles configured as workplace bundles in any module configuration. 364 * @return the names of the bundles configured as workplace bundles in any module configuration. 365 */ 366 public Set<String> getConfiguredWorkplaceBundles() { 367 368 CmsADEConfigData configData = internalLookupConfiguration(null, null); 369 return configData.getConfiguredWorkplaceBundles(); 370 } 371 372 /** 373 * Reads the current element bean from the request.<p> 374 * 375 * @param req the servlet request 376 * 377 * @return the element bean 378 * 379 * @throws CmsException if no current element is set 380 */ 381 public CmsContainerElementBean getCurrentElement(ServletRequest req) throws CmsException { 382 383 CmsJspStandardContextBean sCBean = CmsJspStandardContextBean.getInstance(req); 384 CmsContainerElementBean element = sCBean.getElement(); 385 if (element == null) { 386 throw new CmsException( 387 Messages.get().container( 388 Messages.ERR_READING_ELEMENT_FROM_REQUEST_1, 389 sCBean.getRequestContext().getUri())); 390 } 391 return element; 392 } 393 394 /** 395 * Gets the detail id cache for the Online or Offline projects.<p> 396 * 397 * @param online if true, gets the Online project detail id 398 * 399 * @return the detail name cache 400 */ 401 public CmsDetailNameCache getDetailIdCache(boolean online) { 402 403 return online ? m_onlineDetailIdCache : m_offlineDetailIdCache; 404 } 405 406 /** 407 * Gets the detail page information for everything.<p> 408 * 409 * @param cms the current CMS context 410 * 411 * @return the list with all the detail page information 412 */ 413 public List<DetailInfo> getDetailInfo(CmsObject cms) { 414 415 return getCacheState(isOnline(cms)).getDetailInfosForSubsites(cms); 416 } 417 418 /** 419 * Gets the detail page for a content element.<p> 420 * 421 * @param cms the CMS context 422 * @param pageRootPath the element's root path 423 * @param originPath the path in which the the detail page is being requested 424 * 425 * @return the detail page for the content element 426 */ 427 public String getDetailPage(CmsObject cms, String pageRootPath, String originPath) { 428 429 return getDetailPage(cms, pageRootPath, originPath, null); 430 } 431 432 /** 433 * Gets the detail page for a content element.<p> 434 * 435 * @param cms the CMS context 436 * @param pageRootPath the element's root path 437 * @param originPath the path in which the the detail page is being requested 438 * @param targetDetailPage the target detail page to use 439 * 440 * @return the detail page for the content element 441 */ 442 public String getDetailPage(CmsObject cms, String pageRootPath, String originPath, String targetDetailPage) { 443 444 boolean online = isOnline(cms); 445 String resType = getCacheState(online).getParentFolderType(pageRootPath); 446 if (resType == null) { 447 return null; 448 } 449 if ((targetDetailPage != null) && getDetailPages(cms, resType).contains(targetDetailPage)) { 450 return targetDetailPage; 451 } 452 453 String originRootPath = cms.getRequestContext().addSiteRoot(originPath); 454 CmsADEConfigData configData = lookupConfiguration(cms, originRootPath); 455 CmsADEConfigData targetConfigData = lookupConfiguration(cms, pageRootPath); 456 boolean targetFirst = targetConfigData.isPreferDetailPagesForLocalContents(); 457 List<CmsADEConfigData> configs = targetFirst 458 ? Arrays.asList(targetConfigData, configData) 459 : Arrays.asList(configData, targetConfigData); 460 for (CmsADEConfigData config : configs) { 461 List<CmsDetailPageInfo> pageInfo = config.getDetailPagesForType(resType); 462 if ((pageInfo != null) && !pageInfo.isEmpty()) { 463 return pageInfo.get(0).getUri(); 464 } 465 } 466 return null; 467 } 468 469 /** 470 * Gets the detail page finder.<p> 471 * 472 * @return the detail page finder 473 */ 474 public I_CmsDetailPageFinder getDetailPageFinder() { 475 476 return m_detailPageFinder; 477 } 478 479 /** 480 * Returns the main detail pages for a type in all of the VFS tree.<p> 481 * 482 * @param cms the current CMS context 483 * @param type the resource type name 484 * @return a list of detail page root paths 485 */ 486 public List<String> getDetailPages(CmsObject cms, String type) { 487 488 CmsConfigurationCache cache = isOnline(cms) ? m_onlineCache : m_offlineCache; 489 return cache.getState().getDetailPages(type); 490 } 491 492 /** 493 * Gets the set of types for which detail pages are defined.<p> 494 * 495 * @param cms the current CMS context 496 * 497 * @return the set of types for which detail pages are defined 498 */ 499 public Set<String> getDetailPageTypes(CmsObject cms) { 500 501 return getCacheState(isOnline(cms)).getDetailPageTypes(); 502 } 503 504 /** 505 * Returns the element settings for a given resource.<p> 506 * 507 * @param cms the current cms context 508 * @param resource the resource 509 * 510 * @return the element settings for a given resource 511 * 512 * @throws CmsException if something goes wrong 513 */ 514 public Map<String, CmsXmlContentProperty> getElementSettings(CmsObject cms, CmsResource resource) 515 throws CmsException { 516 517 if (CmsResourceTypeXmlContent.isXmlContent(resource)) { 518 Map<String, CmsXmlContentProperty> result = new LinkedHashMap<String, CmsXmlContentProperty>(); 519 Map<String, CmsXmlContentProperty> settings = CmsXmlContentDefinition.getContentHandlerForResource( 520 cms, 521 resource).getSettings(cms, resource); 522 result.putAll(settings); 523 return CmsXmlContentPropertyHelper.copyPropertyConfiguration(result); 524 } 525 return Collections.<String, CmsXmlContentProperty> emptyMap(); 526 } 527 528 /** 529 * Returns the available element views.<p> 530 * 531 * @param cms the cms context 532 * 533 * @return the element views 534 */ 535 public Map<CmsUUID, CmsElementView> getElementViews(CmsObject cms) { 536 537 CmsConfigurationCache cache = getCache(isOnline(cms)); 538 List<CmsElementView> viewList = Lists.newArrayList(); 539 viewList.addAll(cache.getState().getElementViews().values()); 540 viewList.addAll(OpenCms.getWorkplaceManager().getExplorerTypeViews().values()); 541 Collections.sort(viewList, new ElementViewComparator()); 542 Map<CmsUUID, CmsElementView> result = Maps.newLinkedHashMap(); 543 for (CmsElementView viewValue : viewList) { 544 result.put(viewValue.getId(), viewValue); 545 } 546 return result; 547 } 548 549 /** 550 * Gets the element view configuration resource type.<p> 551 * 552 * @return the element view configuration resource type 553 */ 554 public I_CmsResourceType getElementViewType() { 555 556 return m_elementViewType; 557 } 558 559 /** 560 * Returns the favorite list, or creates it if not available.<p> 561 * 562 * @param cms the cms context 563 * 564 * @return the favorite list 565 * 566 * @throws CmsException if something goes wrong 567 */ 568 public List<CmsContainerElementBean> getFavoriteList(CmsObject cms) throws CmsException { 569 570 CmsUser user = cms.getRequestContext().getCurrentUser(); 571 Object obj = user.getAdditionalInfo(ADDINFO_ADE_FAVORITE_LIST); 572 573 List<CmsContainerElementBean> favList = new ArrayList<CmsContainerElementBean>(); 574 if (obj instanceof String) { 575 try { 576 JSONArray array = new JSONArray((String)obj); 577 for (int i = 0; i < array.length(); i++) { 578 try { 579 favList.add(elementFromJson(array.getJSONObject(i))); 580 } catch (Throwable e) { 581 // should never happen, catches wrong or no longer existing values 582 LOG.warn(e.getLocalizedMessage()); 583 } 584 } 585 } catch (Throwable e) { 586 // should never happen, catches json parsing 587 LOG.warn(e.getLocalizedMessage()); 588 } 589 } else { 590 // save to be better next time 591 saveFavoriteList(cms, favList); 592 } 593 594 return favList; 595 } 596 597 /** 598 * Returns the settings configured for the given formatter.<p> 599 * 600 * @param cms the cms context 601 * @param mainFormatter the formatter 602 * @param res the element resource 603 * @param locale the content locale 604 * @param req the current request, if available 605 * 606 * @return the settings configured for the given formatter 607 */ 608 public Map<String, CmsXmlContentProperty> getFormatterSettings( 609 CmsObject cms, 610 I_CmsFormatterBean mainFormatter, 611 CmsResource res, 612 Locale locale, 613 ServletRequest req) { 614 615 Map<String, CmsXmlContentProperty> result = new LinkedHashMap<String, CmsXmlContentProperty>(); 616 Visibility defaultVisibility = Visibility.elementAndParentIndividual; 617 if (mainFormatter != null) { 618 for (Entry<String, CmsXmlContentProperty> entry : mainFormatter.getSettings().entrySet()) { 619 Visibility visibility = entry.getValue().getVisibility(defaultVisibility); 620 if (!(visibility.equals(Visibility.parentShared) || visibility.equals(Visibility.parentIndividual))) { 621 result.put(entry.getKey(), entry.getValue()); 622 } 623 } 624 if (mainFormatter.hasNestedFormatterSettings()) { 625 List<I_CmsFormatterBean> nestedFormatters = getNestedFormatters(cms, res, locale, req); 626 if (nestedFormatters != null) { 627 for (I_CmsFormatterBean formatter : nestedFormatters) { 628 for (Entry<String, CmsXmlContentProperty> entry : formatter.getSettings().entrySet()) { 629 Visibility visibility = entry.getValue().getVisibility(defaultVisibility); 630 switch (visibility) { 631 case parentShared: 632 case elementAndParentShared: 633 result.put(entry.getKey(), entry.getValue()); 634 break; 635 case elementAndParentIndividual: 636 case parentIndividual: 637 String settingName = formatter.getId() + "_" + entry.getKey(); 638 CmsXmlContentProperty settingConf = entry.getValue().withName(settingName); 639 result.put(settingName, settingConf); 640 break; 641 default: 642 break; 643 } 644 } 645 } 646 } 647 } 648 } 649 return result; 650 } 651 652 /** 653 * Returns the inheritance state for the given inheritance name and resource.<p> 654 * 655 * @param cms the current cms context 656 * @param resource the resource 657 * @param name the inheritance name 658 * 659 * @return the inheritance state 660 */ 661 public CmsInheritedContainerState getInheritedContainerState(CmsObject cms, CmsResource resource, String name) { 662 663 String rootPath = resource.getRootPath(); 664 if (!resource.isFolder()) { 665 rootPath = CmsResource.getParentFolder(rootPath); 666 } 667 CmsInheritedContainerState result = new CmsInheritedContainerState(); 668 boolean online = isOnline(cms); 669 CmsContainerConfigurationCache cache = online 670 ? m_onlineContainerConfigurationCache 671 : m_offlineContainerConfigurationCache; 672 result.addConfigurations(cache, rootPath, name); 673 return result; 674 675 } 676 677 /** 678 * Returns the inheritance state for the given inheritance name and root path.<p> 679 * 680 * @param cms the current cms context 681 * @param rootPath the root path 682 * @param name the inheritance name 683 * 684 * @return the inheritance state 685 * 686 * @throws CmsException if something goes wrong 687 */ 688 public CmsInheritedContainerState getInheritedContainerState(CmsObject cms, String rootPath, String name) 689 throws CmsException { 690 691 String oldSiteRoot = cms.getRequestContext().getSiteRoot(); 692 try { 693 cms.getRequestContext().setSiteRoot(""); 694 CmsResource resource = cms.readResource(rootPath); 695 return getInheritedContainerState(cms, resource, name); 696 } finally { 697 cms.getRequestContext().setSiteRoot(oldSiteRoot); 698 } 699 } 700 701 /** 702 * Gets the maximum sitemap depth.<p> 703 * 704 * @return the maximum sitemap depth 705 */ 706 public int getMaxSitemapDepth() { 707 708 return 20; 709 } 710 711 /** 712 * Gets the module configuration resource type.<p> 713 * 714 * @return the module configuration resource type 715 */ 716 public I_CmsResourceType getModuleConfigurationType() { 717 718 return m_moduleConfigType; 719 } 720 721 /** 722 * Returns the nested formatters of the given resource.<p> 723 * 724 * @param cms the cms context 725 * @param res the resource 726 * @param locale the content locale 727 * @param req the request, if available 728 * 729 * @return the nested formatters 730 */ 731 public List<I_CmsFormatterBean> getNestedFormatters( 732 CmsObject cms, 733 CmsResource res, 734 Locale locale, 735 ServletRequest req) { 736 737 List<I_CmsFormatterBean> result = null; 738 if (CmsResourceTypeXmlContent.isXmlContent(res)) { 739 CmsResourceTypeXmlContent type = (CmsResourceTypeXmlContent)OpenCms.getResourceManager().getResourceType( 740 res); 741 String schema = type.getSchema(); 742 try { 743 CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.unmarshal(cms, schema); 744 // get the content handler for the resource type to create 745 I_CmsXmlContentHandler handler = contentDefinition.getContentHandler(); 746 if (handler.hasNestedFormatters()) { 747 Map<CmsUUID, I_CmsFormatterBean> formatters = getCachedFormatters( 748 cms.getRequestContext().getCurrentProject().isOnlineProject()).getFormatters(); 749 result = new ArrayList<I_CmsFormatterBean>(); 750 for (CmsUUID formatterId : handler.getNestedFormatters(cms, res, locale, req)) { 751 I_CmsFormatterBean formatter = formatters.get(formatterId); 752 if (formatter != null) { 753 result.add(formatter); 754 } 755 } 756 } 757 } catch (CmsXmlException e) { 758 LOG.error(e.getMessage(), e); 759 } 760 } 761 return result; 762 } 763 764 /** 765 * Gets ADE parameters.<p> 766 * 767 * @param cms the current CMS context 768 * @return the ADE parameters for the current user 769 */ 770 public Map<String, String> getParameters(CmsObject cms) { 771 772 Map<String, String> result = new LinkedHashMap<String, String>(m_parameters); 773 if (cms != null) { 774 String userParamsStr = (String)(cms.getRequestContext().getCurrentUser().getAdditionalInfo().get( 775 "ADE_PARAMS")); 776 if (userParamsStr != null) { 777 Map<String, String> userParams = CmsStringUtil.splitAsMap(userParamsStr, "|", ":"); 778 result.putAll(userParams); 779 } 780 } 781 return result; 782 } 783 784 /** 785 * Returns the permission info for the given resource.<p> 786 * 787 * @param cms the cms context 788 * @param resource the resource 789 * @param contextPath the context path 790 * 791 * @return the permission info 792 * 793 * @throws CmsException if checking the permissions fails 794 */ 795 public CmsPermissionInfo getPermissionInfo(CmsObject cms, CmsResource resource, String contextPath) 796 throws CmsException { 797 798 boolean hasView = cms.hasPermissions( 799 resource, 800 CmsPermissionSet.ACCESS_VIEW, 801 false, 802 CmsResourceFilter.ALL.addRequireVisible()); 803 boolean hasWrite = false; 804 if (hasView) { 805 try { 806 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resource.getTypeId()); 807 CmsExplorerTypeSettings settings = OpenCms.getWorkplaceManager().getExplorerTypeSetting( 808 type.getTypeName()); 809 hasView = (settings == null) 810 || settings.getAccess().getPermissions(cms, resource).requiresViewPermission(); 811 if (hasView 812 && CmsResourceTypeXmlContent.isXmlContent(resource) 813 && !CmsResourceTypeXmlContainerPage.isContainerPage(resource)) { 814 if (contextPath == null) { 815 contextPath = resource.getRootPath(); 816 } 817 CmsResourceTypeConfig localConfigData = lookupConfiguration(cms, contextPath).getResourceType( 818 type.getTypeName()); 819 if (localConfigData != null) { 820 Map<CmsUUID, CmsElementView> elmenetViews = getElementViews(cms); 821 hasView = elmenetViews.containsKey(localConfigData.getElementView()) 822 && elmenetViews.get(localConfigData.getElementView()).hasPermission(cms, resource); 823 } 824 } 825 // the user may only have write permissions if he is allowed to view the resource 826 hasWrite = hasView 827 && cms.hasPermissions( 828 resource, 829 CmsPermissionSet.ACCESS_WRITE, 830 false, 831 CmsResourceFilter.IGNORE_EXPIRATION) 832 && ((settings == null) 833 || settings.getAccess().getPermissions(cms, resource).requiresWritePermission()); 834 } catch (CmsLoaderException e) { 835 LOG.warn(e.getLocalizedMessage(), e); 836 hasWrite = false; 837 } 838 } 839 840 String noEdit = new CmsResourceUtil(cms, resource).getNoEditReason( 841 OpenCms.getWorkplaceManager().getWorkplaceLocale(cms), 842 true); 843 return new CmsPermissionInfo(hasView, hasWrite, noEdit); 844 } 845 846 /** 847 * Returns the favorite list, or creates it if not available.<p> 848 * 849 * @param cms the cms context 850 * 851 * @return the favorite list 852 * 853 * @throws CmsException if something goes wrong 854 */ 855 public List<CmsContainerElementBean> getRecentList(CmsObject cms) throws CmsException { 856 857 CmsUser user = cms.getRequestContext().getCurrentUser(); 858 Object obj = user.getAdditionalInfo(ADDINFO_ADE_RECENT_LIST); 859 860 List<CmsContainerElementBean> recentList = new ArrayList<CmsContainerElementBean>(); 861 if (obj instanceof String) { 862 try { 863 JSONArray array = new JSONArray((String)obj); 864 for (int i = 0; i < array.length(); i++) { 865 try { 866 recentList.add(elementFromJson(array.getJSONObject(i))); 867 } catch (Throwable e) { 868 // should never happen, catches wrong or no longer existing values 869 LOG.warn(e.getLocalizedMessage()); 870 } 871 } 872 } catch (Throwable e) { 873 // should never happen, catches json parsing 874 LOG.warn(e.getLocalizedMessage()); 875 } 876 } else { 877 // save to be better next time 878 saveRecentList(cms, recentList); 879 } 880 881 return recentList; 882 } 883 884 /** 885 * Gets the sitemap configuration resource type.<p> 886 * 887 * @return the resource type for sitemap configurations 888 */ 889 public I_CmsResourceType getSitemapConfigurationType() { 890 891 return m_configType; 892 } 893 894 /** 895 * Returns all sub sites below the given path.<p> 896 * 897 * @param cms the cms context 898 * @param subSiteRoot the sub site root path 899 * 900 * @return the sub site root paths 901 */ 902 public List<String> getSubSitePaths(CmsObject cms, String subSiteRoot) { 903 904 List<String> result = new ArrayList<String>(); 905 String normalizedRootPath = CmsStringUtil.joinPaths("/", subSiteRoot, "/"); 906 CmsADEConfigCacheState state = getCacheState(isOnline(cms)); 907 Set<String> siteConfigurationPaths = state.getSiteConfigurationPaths(); 908 for (String path : siteConfigurationPaths) { 909 if ((path.length() > normalizedRootPath.length()) && path.startsWith(normalizedRootPath)) { 910 result.add(path); 911 } 912 } 913 return result; 914 } 915 916 /** 917 * Tries to get the subsite root for a given resource root path.<p> 918 * 919 * @param cms the current CMS context 920 * @param rootPath the root path for which the subsite root should be found 921 * 922 * @return the subsite root 923 */ 924 public String getSubSiteRoot(CmsObject cms, String rootPath) { 925 926 CmsADEConfigData configData = lookupConfiguration(cms, rootPath); 927 String basePath = configData.getBasePath(); 928 String siteRoot = OpenCms.getSiteManager().getSiteRoot(rootPath); 929 if (siteRoot == null) { 930 siteRoot = ""; 931 } 932 if ((basePath == null) || !basePath.startsWith(siteRoot)) { 933 // the subsite root should always be below the site root 934 return siteRoot; 935 } else { 936 return basePath; 937 } 938 } 939 940 /** 941 * Processes a HTML redirect content.<p> 942 * 943 * This needs to be in the ADE manager because the user for whom the HTML redirect is being loaded 944 * does not necessarily have read permissions for the redirect target, so we read the redirect target 945 * with admin privileges.<p> 946 * 947 * @param userCms the CMS context of the current user 948 * @param request the servlet request 949 * @param response the servlet response 950 * @param htmlRedirect the path of the HTML redirect resource 951 * 952 * @throws CmsException if something goes wrong 953 */ 954 public void handleHtmlRedirect( 955 CmsObject userCms, 956 HttpServletRequest request, 957 HttpServletResponse response, 958 String htmlRedirect) 959 throws CmsException { 960 961 CmsObject cms = OpenCms.initCmsObject(m_offlineCms); 962 CmsRequestContext userContext = userCms.getRequestContext(); 963 CmsRequestContext currentContext = cms.getRequestContext(); 964 currentContext.setCurrentProject(userContext.getCurrentProject()); 965 currentContext.setSiteRoot(userContext.getSiteRoot()); 966 currentContext.setLocale(userContext.getLocale()); 967 currentContext.setUri(userContext.getUri()); 968 969 CmsFile file = cms.readFile(htmlRedirect); 970 CmsXmlContent content = CmsXmlContentFactory.unmarshal(cms, file); 971 972 // find out the locale to use for reading values from the redirect 973 List<Locale> candidates = new ArrayList<Locale>(); 974 candidates.add(currentContext.getLocale()); 975 candidates.add(CmsLocaleManager.getDefaultLocale()); 976 candidates.add(Locale.ENGLISH); 977 candidates.addAll(content.getLocales()); 978 Locale contentLocale = currentContext.getLocale(); 979 for (Locale candidateLocale : candidates) { 980 if (content.hasLocale(candidateLocale)) { 981 contentLocale = candidateLocale; 982 break; 983 } 984 } 985 986 String typeValue = content.getValue(N_TYPE, contentLocale).getStringValue(cms); 987 String lnkUri = ""; 988 Integer errorCode; 989 if ("sublevel".equals(typeValue)) { 990 // use the nav builder to get the first sub level entry 991 CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(cms); 992 if (navBuilder.getNavigationForFolder().size() > 0) { 993 CmsJspNavElement target = navBuilder.getNavigationForFolder().get(0); 994 lnkUri = CmsJspTagLink.linkTagAction(target.getResourceName(), request); 995 errorCode = Integer.valueOf(HttpServletResponse.SC_MOVED_TEMPORARILY); 996 } else { 997 // send error 404 if no sub entry available 998 errorCode = Integer.valueOf(HttpServletResponse.SC_NOT_FOUND); 999 } 1000 } else { 1001 I_CmsXmlContentValue contentValue = content.getValue(N_LINK, contentLocale); 1002 if (contentValue != null) { 1003 String linkValue = contentValue.getStringValue(cms); 1004 lnkUri = OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, linkValue); 1005 try { 1006 errorCode = Integer.valueOf(typeValue); 1007 } catch (NumberFormatException e) { 1008 LOG.error(e.getMessage(), e); 1009 // fall back to default 1010 errorCode = Integer.valueOf(307); 1011 } 1012 } else { 1013 // send error 404 if no link value is set 1014 errorCode = Integer.valueOf(HttpServletResponse.SC_NOT_FOUND); 1015 } 1016 } 1017 request.setAttribute(CmsRequestUtil.ATTRIBUTE_ERRORCODE, errorCode); 1018 response.setHeader("Location", CmsEncoder.convertHostToPunycode(lnkUri)); 1019 response.setHeader("Connection", "close"); 1020 response.setStatus(errorCode.intValue()); 1021 } 1022 1023 /** 1024 * Initializes the configuration by reading all configuration files and caching their data.<p> 1025 */ 1026 public synchronized void initialize() { 1027 1028 // no need to try initialization in case the 'org.opencms.base' is not present and the contained resource types missing 1029 if ((m_initStatus == Status.notInitialized) && OpenCms.getModuleManager().hasModule(MODULE_NAME_ADE_CONFIG)) { 1030 try { 1031 CmsLog.INIT.info(". Initializing the ADE configuration, this may take a while..."); 1032 m_initStatus = Status.initializing; 1033 m_configType = OpenCms.getResourceManager().getResourceType(CONFIG_TYPE); 1034 m_moduleConfigType = OpenCms.getResourceManager().getResourceType(MODULE_CONFIG_TYPE); 1035 m_elementViewType = OpenCms.getResourceManager().getResourceType(ELEMENT_VIEW_TYPE); 1036 CmsProject temp = getTempfileProject(m_onlineCms); 1037 m_offlineCms = OpenCms.initCmsObject(m_onlineCms); 1038 m_offlineCms.getRequestContext().setCurrentProject(temp); 1039 m_onlineCache = new CmsConfigurationCache( 1040 m_onlineCms, 1041 m_configType, 1042 m_moduleConfigType, 1043 m_elementViewType); 1044 m_offlineCache = new CmsConfigurationCache( 1045 m_offlineCms, 1046 m_configType, 1047 m_moduleConfigType, 1048 m_elementViewType); 1049 CmsLog.INIT.info(". Reading online configuration..."); 1050 m_onlineCache.initialize(); 1051 CmsLog.INIT.info(". Reading offline configuration..."); 1052 m_offlineCache.initialize(); 1053 m_onlineContainerConfigurationCache = new CmsContainerConfigurationCache( 1054 m_onlineCms, 1055 "online inheritance groups"); 1056 m_offlineContainerConfigurationCache = new CmsContainerConfigurationCache( 1057 m_offlineCms, 1058 "offline inheritance groups"); 1059 CmsLog.INIT.info(". Reading online inherited container configurations..."); 1060 m_onlineContainerConfigurationCache.initialize(); 1061 CmsLog.INIT.info(". Reading offline inherited container configurations..."); 1062 m_offlineContainerConfigurationCache.initialize(); 1063 m_offlineFormatterCache = new CmsFormatterConfigurationCache(m_offlineCms, "offline formatters"); 1064 m_onlineFormatterCache = new CmsFormatterConfigurationCache(m_onlineCms, "online formatters"); 1065 CmsLog.INIT.info(". Reading online formatter configurations..."); 1066 m_onlineFormatterCache.initialize(); 1067 CmsLog.INIT.info(". Reading offline formatter configurations..."); 1068 m_offlineFormatterCache.initialize(); 1069 1070 m_offlineDetailIdCache = new CmsDetailNameCache(m_offlineCms); 1071 m_onlineDetailIdCache = new CmsDetailNameCache(m_onlineCms); 1072 CmsLog.INIT.info(". Initializing online detail name cache..."); 1073 m_onlineDetailIdCache.initialize(); 1074 CmsLog.INIT.info(". Initializing offline detail name cache..."); 1075 m_offlineDetailIdCache.initialize(); 1076 1077 CmsGlobalConfigurationCacheEventHandler handler = new CmsGlobalConfigurationCacheEventHandler( 1078 m_onlineCms); 1079 handler.addCache(m_offlineCache, m_onlineCache, "ADE configuration cache"); 1080 handler.addCache( 1081 m_offlineContainerConfigurationCache, 1082 m_onlineContainerConfigurationCache, 1083 "Inherited container cache"); 1084 handler.addCache(m_offlineFormatterCache, m_onlineFormatterCache, "formatter configuration cache"); 1085 handler.addCache(m_offlineDetailIdCache, m_onlineDetailIdCache, "Detail ID cache"); 1086 OpenCms.getEventManager().addCmsEventListener(handler); 1087 CmsLog.INIT.info(". Done initializing the ADE configuration."); 1088 m_initStatus = Status.initialized; 1089 } catch (CmsException e) { 1090 m_initStatus = Status.notInitialized; 1091 LOG.error(e.getLocalizedMessage(), e); 1092 } 1093 } 1094 } 1095 1096 /** 1097 * Checks whether the given resource is configured as a detail page.<p> 1098 * 1099 * @param cms the current CMS context 1100 * @param resource the resource which should be tested 1101 * 1102 * @return true if the resource is configured as a detail page 1103 */ 1104 public boolean isDetailPage(CmsObject cms, CmsResource resource) { 1105 1106 return getCache(isOnline(cms)).isDetailPage(cms, resource); 1107 } 1108 1109 /** 1110 * Checks whether the ADE manager is initialized (this should usually be the case except during the setup).<p> 1111 * 1112 * @return true if the ADE manager is initialized 1113 */ 1114 public boolean isInitialized() { 1115 1116 return m_initStatus == Status.initialized; 1117 } 1118 1119 /** 1120 * Returns the show editor help flag.<p> 1121 * 1122 * @param cms the cms context 1123 * 1124 * @return the show editor help flag 1125 */ 1126 public boolean isShowEditorHelp(CmsObject cms) { 1127 1128 CmsUser user = cms.getRequestContext().getCurrentUser(); 1129 String showHelp = (String)user.getAdditionalInfo(ADDINFO_ADE_SHOW_EDITOR_HELP); 1130 return CmsStringUtil.isEmptyOrWhitespaceOnly(showHelp) || Boolean.parseBoolean(showHelp); 1131 } 1132 1133 /** 1134 * Looks up the configuration data for a given sitemap path.<p> 1135 * 1136 * @param cms the current CMS context 1137 * @param rootPath the root path for which the configuration data should be looked up 1138 * 1139 * @return the configuration data 1140 */ 1141 public CmsADEConfigData lookupConfiguration(CmsObject cms, String rootPath) { 1142 1143 CmsADEConfigData configData = internalLookupConfiguration(cms, rootPath); 1144 return configData; 1145 } 1146 1147 /** 1148 * Reloads the configuration.<p> 1149 * 1150 * Normally you shouldn't call this directly since the event handlers take care of updating the configuration. 1151 */ 1152 public void refresh() { 1153 1154 m_onlineCache.initialize(); 1155 m_offlineCache.initialize(); 1156 } 1157 1158 /** 1159 * Saves a list of detail pages.<p> 1160 * @param cms the cms context 1161 * @param rootPath the root path 1162 * @param detailPages the detail pages 1163 * @param newId the id to use for new detail pages without an id 1164 * @return true if the detail pages could be successfully saved 1165 * 1166 * @throws CmsException if something goes wrong 1167 */ 1168 public boolean saveDetailPages(CmsObject cms, String rootPath, List<CmsDetailPageInfo> detailPages, CmsUUID newId) 1169 throws CmsException { 1170 1171 CmsADEConfigData configData = lookupConfiguration(cms, rootPath); 1172 CmsDetailPageConfigurationWriter configWriter; 1173 String originalSiteRoot = cms.getRequestContext().getSiteRoot(); 1174 try { 1175 cms.getRequestContext().setSiteRoot(""); 1176 if (configData.isModuleConfiguration()) { 1177 return false; 1178 } 1179 CmsResource configFile = configData.getResource(); 1180 configWriter = new CmsDetailPageConfigurationWriter(cms, configFile); 1181 configWriter.updateAndSave(detailPages, newId); 1182 return true; 1183 } finally { 1184 cms.getRequestContext().setSiteRoot(originalSiteRoot); 1185 } 1186 } 1187 1188 /** 1189 * Saves the favorite list, user based.<p> 1190 * 1191 * @param cms the cms context 1192 * @param favoriteList the element list 1193 * 1194 * @throws CmsException if something goes wrong 1195 */ 1196 public void saveFavoriteList(CmsObject cms, List<CmsContainerElementBean> favoriteList) throws CmsException { 1197 1198 saveElementList(cms, favoriteList, ADDINFO_ADE_FAVORITE_LIST); 1199 } 1200 1201 /** 1202 * Saves the inheritance container information.<p> 1203 * 1204 * @param cms the current cms context 1205 * @param pageResource the resource or parent folder 1206 * @param name the inheritance name 1207 * @param newOrder if the element have been reordered 1208 * @param elements the elements 1209 * 1210 * @throws CmsException if something goes wrong 1211 */ 1212 public void saveInheritedContainer( 1213 CmsObject cms, 1214 CmsResource pageResource, 1215 String name, 1216 boolean newOrder, 1217 List<CmsContainerElementBean> elements) 1218 throws CmsException { 1219 1220 CmsContainerConfigurationWriter writer = new CmsContainerConfigurationWriter(); 1221 writer.save(cms, name, newOrder, pageResource, elements); 1222 1223 // Inheritance groups are usually reloaded directly after saving them, 1224 // so the cache needs to be up to date after this method is called 1225 m_offlineContainerConfigurationCache.flushUpdates(); 1226 } 1227 1228 /** 1229 * Saves the inheritance container information.<p> 1230 * 1231 * @param cms the current cms context 1232 * @param sitePath the site path of the resource or parent folder 1233 * @param name the inheritance name 1234 * @param newOrder if the element have been reordered 1235 * @param elements the elements 1236 * 1237 * @throws CmsException if something goes wrong 1238 */ 1239 public void saveInheritedContainer( 1240 CmsObject cms, 1241 String sitePath, 1242 String name, 1243 boolean newOrder, 1244 List<CmsContainerElementBean> elements) 1245 throws CmsException { 1246 1247 saveInheritedContainer(cms, cms.readResource(sitePath), name, newOrder, elements); 1248 } 1249 1250 /** 1251 * Saves the favorite list, user based.<p> 1252 * 1253 * @param cms the cms context 1254 * @param recentList the element list 1255 * 1256 * @throws CmsException if something goes wrong 1257 */ 1258 public void saveRecentList(CmsObject cms, List<CmsContainerElementBean> recentList) throws CmsException { 1259 1260 saveElementList(cms, recentList, ADDINFO_ADE_RECENT_LIST); 1261 } 1262 1263 /** 1264 * Sets the show editor help flag.<p> 1265 * 1266 * @param cms the cms context 1267 * @param showHelp the show help flag 1268 * @throws CmsException if writing the user info fails 1269 */ 1270 public void setShowEditorHelp(CmsObject cms, boolean showHelp) throws CmsException { 1271 1272 CmsUser user = cms.getRequestContext().getCurrentUser(); 1273 user.setAdditionalInfo(ADDINFO_ADE_SHOW_EDITOR_HELP, String.valueOf(showHelp)); 1274 cms.writeUser(user); 1275 } 1276 1277 /** 1278 * The method which is called when the OpenCms instance is shut down.<p> 1279 */ 1280 public void shutdown() { 1281 1282 // do nothing 1283 } 1284 1285 /** 1286 * Waits until the next time the cache is updated.<p> 1287 * 1288 * @param online true if we want to wait for the online cache, false for the offline cache 1289 */ 1290 public void waitForCacheUpdate(boolean online) { 1291 1292 getCache(online).getWaitHandleForUpdateTask().enter(2 * CmsConfigurationCache.TASK_DELAY_MILLIS); 1293 } 1294 1295 /** 1296 * Waits until the formatter cache has finished updating itself.<p> 1297 * 1298 * This method is only intended for use in test cases. 1299 * 1300 * @param online true if we should wait for the online formatter cache,false for the offline cache 1301 */ 1302 public void waitForFormatterCache(boolean online) { 1303 1304 CmsFormatterConfigurationCache cache = online ? m_onlineFormatterCache : m_offlineFormatterCache; 1305 cache.waitForUpdate(); 1306 } 1307 1308 /** 1309 * Creates an element from its serialized data.<p> 1310 * 1311 * @param data the serialized data 1312 * 1313 * @return the restored element bean 1314 * 1315 * @throws JSONException if the serialized data got corrupted 1316 */ 1317 protected CmsContainerElementBean elementFromJson(JSONObject data) throws JSONException { 1318 1319 CmsUUID element = new CmsUUID(data.getString(FavListProp.ELEMENT.name().toLowerCase())); 1320 CmsUUID formatter = null; 1321 if (data.has(FavListProp.FORMATTER.name().toLowerCase())) { 1322 formatter = new CmsUUID(data.getString(FavListProp.FORMATTER.name().toLowerCase())); 1323 } 1324 Map<String, String> properties = new HashMap<String, String>(); 1325 1326 JSONObject props = data.getJSONObject(FavListProp.PROPERTIES.name().toLowerCase()); 1327 Iterator<String> keys = props.keys(); 1328 while (keys.hasNext()) { 1329 String key = keys.next(); 1330 properties.put(key, props.getString(key)); 1331 } 1332 1333 return new CmsContainerElementBean(element, formatter, properties, false); 1334 } 1335 1336 /** 1337 * Converts the given element to JSON.<p> 1338 * 1339 * @param element the element to convert 1340 * @param excludeSettings the keys of settings which should not be written to the JSON 1341 * 1342 * @return the JSON representation 1343 */ 1344 protected JSONObject elementToJson(CmsContainerElementBean element, Set<String> excludeSettings) { 1345 1346 JSONObject data = null; 1347 try { 1348 data = new JSONObject(); 1349 data.put(FavListProp.ELEMENT.name().toLowerCase(), element.getId().toString()); 1350 if (element.getFormatterId() != null) { 1351 data.put(FavListProp.FORMATTER.name().toLowerCase(), element.getFormatterId().toString()); 1352 } 1353 JSONObject properties = new JSONObject(); 1354 for (Map.Entry<String, String> entry : element.getIndividualSettings().entrySet()) { 1355 String settingKey = entry.getKey(); 1356 if (!excludeSettings.contains(settingKey)) { 1357 properties.put(entry.getKey(), entry.getValue()); 1358 } 1359 } 1360 data.put(FavListProp.PROPERTIES.name().toLowerCase(), properties); 1361 } catch (JSONException e) { 1362 // should never happen 1363 if (!LOG.isDebugEnabled()) { 1364 LOG.warn(e.getLocalizedMessage()); 1365 } 1366 LOG.debug(e.getLocalizedMessage(), e); 1367 return null; 1368 } 1369 return data; 1370 } 1371 1372 /** 1373 * Gets the configuration cache instance.<p> 1374 * 1375 * @param online true if you want the online cache, false for the offline cache 1376 * 1377 * @return the ADE configuration cache instance 1378 */ 1379 protected CmsConfigurationCache getCache(boolean online) { 1380 1381 return online ? m_onlineCache : m_offlineCache; 1382 } 1383 1384 /** 1385 * Gets the current ADE configuration cache state.<p> 1386 * 1387 * @param online true if you want the online state, false for the offline state 1388 * 1389 * @return the configuration cache state 1390 */ 1391 protected CmsADEConfigCacheState getCacheState(boolean online) { 1392 1393 return (online ? m_onlineCache : m_offlineCache).getState(); 1394 } 1395 1396 /** 1397 * Gets the offline cache.<p> 1398 * 1399 * @return the offline configuration cache 1400 */ 1401 protected CmsConfigurationCache getOfflineCache() { 1402 1403 return m_offlineCache; 1404 } 1405 1406 /** 1407 * Gets the online cache.<p> 1408 * 1409 * @return the online configuration cache 1410 */ 1411 protected CmsConfigurationCache getOnlineCache() { 1412 1413 return m_onlineCache; 1414 } 1415 1416 /** 1417 * Gets the root path for a given resource structure id.<p> 1418 * 1419 * @param structureId the structure id 1420 * @param online if true, the resource will be looked up in the online project ,else in the offline project 1421 * 1422 * @return the root path for the given structure id 1423 * 1424 * @throws CmsException if something goes wrong 1425 */ 1426 protected String getRootPath(CmsUUID structureId, boolean online) throws CmsException { 1427 1428 CmsConfigurationCache cache = online ? m_onlineCache : m_offlineCache; 1429 return cache.getPathForStructureId(structureId); 1430 } 1431 1432 /** 1433 * Gets a tempfile project, creating one if it doesn't exist already.<p> 1434 * 1435 * @param cms the CMS context to use 1436 * @return the tempfile project 1437 * 1438 * @throws CmsException if something goes wrong 1439 */ 1440 protected CmsProject getTempfileProject(CmsObject cms) throws CmsException { 1441 1442 try { 1443 return cms.readProject(I_CmsProjectDriver.TEMP_FILE_PROJECT_NAME); 1444 } catch (CmsException e) { 1445 return cms.createTempfileProject(); 1446 } 1447 } 1448 1449 /** 1450 * Internal configuration lookup method.<p> 1451 * 1452 * @param cms the cms context 1453 * @param rootPath the root path for which to look up the configuration 1454 * 1455 * @return the configuration for the given path 1456 */ 1457 protected CmsADEConfigData internalLookupConfiguration(CmsObject cms, String rootPath) { 1458 1459 boolean online = (null == cms) || isOnline(cms); 1460 CmsADEConfigCacheState state = getCacheState(online); 1461 return state.lookupConfiguration(rootPath); 1462 } 1463 1464 /** 1465 * Returns true if the project set in the CmsObject is the Online project.<p> 1466 * 1467 * @param cms the CMS context to check 1468 * 1469 * @return true if the project set in the CMS context is the Online project 1470 */ 1471 private boolean isOnline(CmsObject cms) { 1472 1473 return cms.getRequestContext().getCurrentProject().isOnlineProject(); 1474 } 1475 1476 /** 1477 * Saves an element list to the user additional infos.<p> 1478 * 1479 * @param cms the cms context 1480 * @param elementList the element list 1481 * @param listKey the list key 1482 * 1483 * @throws CmsException if something goes wrong 1484 */ 1485 private void saveElementList(CmsObject cms, List<CmsContainerElementBean> elementList, String listKey) 1486 throws CmsException { 1487 1488 // limit the favorite list size to avoid the additional info size limit 1489 if (elementList.size() > DEFAULT_ELEMENT_LIST_SIZE) { 1490 elementList = elementList.subList(0, DEFAULT_ELEMENT_LIST_SIZE); 1491 } 1492 1493 JSONArray data = new JSONArray(); 1494 1495 Set<String> excludedSettings = new HashSet<String>(); 1496 // do not store the template contexts, since dragging an element into the page which might be invisible 1497 // doesn't make sense 1498 excludedSettings.add(CmsTemplateContextInfo.SETTING); 1499 1500 for (CmsContainerElementBean element : elementList) { 1501 data.put(elementToJson(element, excludedSettings)); 1502 } 1503 CmsUser user = cms.getRequestContext().getCurrentUser(); 1504 user.setAdditionalInfo(listKey, data.toString()); 1505 cms.writeUser(user); 1506 } 1507}