001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.xml.containerpage; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.configuration.CmsElementView; 032import org.opencms.ade.containerpage.shared.CmsContainer; 033import org.opencms.ade.galleries.shared.CmsGallerySearchBean; 034import org.opencms.ade.sitemap.shared.CmsSitemapData.EditorMode; 035import org.opencms.configuration.preferences.CmsElementViewPreference; 036import org.opencms.file.CmsObject; 037import org.opencms.jsp.util.CmsJspStandardContextBean.TemplateBean; 038import org.opencms.main.CmsLog; 039import org.opencms.util.CmsUUID; 040import org.opencms.workplace.CmsWorkplace; 041import org.opencms.xml.content.CmsXmlContent; 042 043import java.util.ArrayList; 044import java.util.Arrays; 045import java.util.HashMap; 046import java.util.HashSet; 047import java.util.List; 048import java.util.Map; 049import java.util.Set; 050import java.util.concurrent.ConcurrentHashMap; 051 052import javax.servlet.http.HttpServletRequest; 053 054import org.apache.commons.logging.Log; 055 056/** 057 * ADE's session cache.<p> 058 * 059 * @since 8.0.0 060 */ 061public final class CmsADESessionCache { 062 063 /** 064 * Stores information about the container page which was last edited, so we can jump back to it later.<p> 065 */ 066 public static class LastPageBean { 067 068 /** The detail id (may be null). */ 069 private CmsUUID m_detailId; 070 071 /** The page structure id. */ 072 private CmsUUID m_pageId; 073 074 /** The site root. */ 075 private String m_siteRoot; 076 077 /** 078 * Creates a new instance.<p> 079 * 080 * @param siteRoot the site root 081 * @param pageId the page id 082 * @param detailId the detail content id (may be null) 083 */ 084 public LastPageBean(String siteRoot, CmsUUID pageId, CmsUUID detailId) { 085 086 super(); 087 m_siteRoot = siteRoot; 088 m_pageId = pageId; 089 m_detailId = detailId; 090 } 091 092 /** 093 * Returns the detailId.<p> 094 * 095 * @return the detailId 096 */ 097 public CmsUUID getDetailId() { 098 099 return m_detailId; 100 } 101 102 /** 103 * Returns the pageId.<p> 104 * 105 * @return the pageId 106 */ 107 public CmsUUID getPageId() { 108 109 return m_pageId; 110 } 111 112 /** 113 * Returns the siteRoot.<p> 114 * 115 * @return the siteRoot 116 */ 117 public String getSiteRoot() { 118 119 return m_siteRoot; 120 } 121 122 } 123 124 /** Session attribute name constant. */ 125 public static final String SESSION_ATTR_ADE_CACHE = "__OCMS_ADE_CACHE__"; 126 127 /** The log instance for this class. */ 128 private static final Log LOG = CmsLog.getLog(CmsADESessionCache.class); 129 130 /** The list size for recently used formatters. */ 131 private static final int RECENT_FORMATTERS_SIZE = 10; 132 133 /** The container elements. */ 134 private Map<String, CmsContainerElementBean> m_containerElements; 135 136 /** The current values of dynamically loaded attributes in the Acacia editor. */ 137 private Map<String, String> m_dynamicValues; 138 139 /** The current element view id. */ 140 private CmsUUID m_elementView; 141 142 /** Flag which controls whether small elements should be shown. */ 143 private boolean m_isEditSmallElements; 144 145 /** Bean containing last page info. */ 146 private LastPageBean m_lastPage; 147 148 /** The last stored gallery search for the page editor. */ 149 private CmsGallerySearchBean m_lastPageEditorGallerySearch; 150 151 /** The recently used formatters by resource type. */ 152 private Map<String, List<String>> m_recentFormatters = new ConcurrentHashMap<String, List<String>>(); 153 154 /** The sitemap editor mode. */ 155 private EditorMode m_sitemapEditorMode; 156 157 /** Template bean cache. */ 158 private Map<String, TemplateBean> m_templateBeanCache = new HashMap<String, TemplateBean>(); 159 160 /** The tool-bar visibility flag. */ 161 private boolean m_toolbarVisible; 162 163 /** The cached XML content documents by structure id. */ 164 private Map<CmsUUID, CmsXmlContent> m_xmlContents; 165 166 /** 167 * Initializes the session cache.<p> 168 * 169 * @param cms the cms context 170 * @param request the current request 171 */ 172 protected CmsADESessionCache(CmsObject cms, HttpServletRequest request) { 173 174 // container element cache 175 m_containerElements = new ConcurrentHashMap<String, CmsContainerElementBean>(); 176 177 // XML content cache, used during XML content edit 178 m_xmlContents = new ConcurrentHashMap<CmsUUID, CmsXmlContent>(); 179 180 String elementView = null; 181 // within the test cases the request will be null 182 if (request != null) { 183 elementView = CmsWorkplace.getWorkplaceSettings(cms, request).getUserSettings().getAdditionalPreference( 184 CmsElementViewPreference.PREFERENCE_NAME, 185 false); 186 } 187 if (elementView == null) { 188 // use the default element view 189 m_elementView = CmsElementView.DEFAULT_ELEMENT_VIEW.getId(); 190 } else { 191 try { 192 m_elementView = new CmsUUID(elementView); 193 } catch (NumberFormatException e) { 194 // use the default element view 195 m_elementView = CmsElementView.DEFAULT_ELEMENT_VIEW.getId(); 196 LOG.warn("Malformed element view id '" + elementView + "'.", e); 197 } 198 } 199 // toolbar should be visible initially 200 m_toolbarVisible = true; 201 } 202 203 /** 204 * Gets the session cache for the current session.<p> 205 * In case the request is not editable, <code>null</code> will be returned.<p> 206 * 207 * @param request the current request 208 * @param cms the current CMS context 209 * 210 * @return the ADE session cache for the current session 211 */ 212 public static CmsADESessionCache getCache(HttpServletRequest request, CmsObject cms) { 213 214 CmsADESessionCache cache = (CmsADESessionCache)request.getSession().getAttribute( 215 CmsADESessionCache.SESSION_ATTR_ADE_CACHE); 216 if (cache == null) { 217 cache = new CmsADESessionCache(cms, request); 218 request.getSession().setAttribute(CmsADESessionCache.SESSION_ATTR_ADE_CACHE, cache); 219 } 220 return cache; 221 } 222 223 /** 224 * Adds the formatter id to the recently used list for the given type.<p> 225 * 226 * @param resType the resource type 227 * @param keyOrId the formatter id 228 */ 229 public void addRecentFormatter(String resType, String keyOrId) { 230 231 List<String> formatterIds = m_recentFormatters.get(resType); 232 if (formatterIds == null) { 233 formatterIds = new ArrayList<String>(); 234 m_recentFormatters.put(resType, formatterIds); 235 } 236 formatterIds.remove(keyOrId); 237 if (formatterIds.size() >= (RECENT_FORMATTERS_SIZE)) { 238 formatterIds.remove(RECENT_FORMATTERS_SIZE - 1); 239 } 240 formatterIds.add(0, keyOrId); 241 } 242 243 /** 244 * Clear the cache values that are dynamically loaded in the Acacia content editor. 245 */ 246 public void clearDynamicValues() { 247 248 m_dynamicValues = null; 249 } 250 251 /** 252 * Removes the information about the last edited container page.<p> 253 */ 254 public void clearLastPage() { 255 256 m_lastPage = null; 257 } 258 259 /** 260 * Returns the cached container element under the given key.<p> 261 * 262 * @param key the cache key 263 * 264 * @return the cached container element or <code>null</code> if not found 265 */ 266 public CmsContainerElementBean getCacheContainerElement(String key) { 267 268 return m_containerElements.get(key); 269 } 270 271 /** 272 * Returns the cached XML content document.<p> 273 * 274 * @param structureId the structure id 275 * 276 * @return the XML document 277 */ 278 public CmsXmlContent getCacheXmlContent(CmsUUID structureId) { 279 280 return m_xmlContents.get(structureId); 281 } 282 283 /** 284 * Get cached value that is dynamically loaded by the Acacia content editor. 285 * 286 * @param attribute the attribute to load the value to 287 * @return the cached value 288 */ 289 public String getDynamicValue(String attribute) { 290 291 return null == m_dynamicValues ? null : m_dynamicValues.get(attribute); 292 } 293 294 /** 295 * Returns the current element view id.<p> 296 * 297 * @return the current element view id 298 */ 299 public CmsUUID getElementView() { 300 301 return m_elementView; 302 } 303 304 /** 305 * Returns the lastPage.<p> 306 * 307 * @return the lastPage 308 */ 309 public LastPageBean getLastPage() { 310 311 return m_lastPage; 312 } 313 314 /** 315 * Returns the lastPageEditorGallerySearch.<p> 316 * 317 * @return the lastPageEditorGallerySearch 318 */ 319 public CmsGallerySearchBean getLastPageEditorGallerySearch() { 320 321 return m_lastPageEditorGallerySearch; 322 } 323 324 /** 325 * Returns the least recently used matching formatter for the given resource type.<p> 326 * 327 * @param resType the resource type 328 * @param container the container to match 329 * @param config the config data 330 * 331 * @return the formatter if any 332 */ 333 public I_CmsFormatterBean getRecentFormatter(String resType, CmsContainer container, CmsADEConfigData config) { 334 335 I_CmsFormatterBean result = null; 336 List<String> formatterKeys = m_recentFormatters.get(resType); 337 if (formatterKeys != null) { 338 Set<String> types = new HashSet<String>(Arrays.asList(container.getType().trim().split(" *, *"))); 339 for (String key : formatterKeys) { 340 I_CmsFormatterBean formatter = config.findFormatter(key); 341 if ((formatter != null) 342 && CmsUUID.isValidUUID(formatter.getId()) 343 && config.getActiveFormatters().containsKey(new CmsUUID(formatter.getId())) // findFormatter may return inactive formatters, but here we only want active ones 344 && CmsFormatterConfiguration.matchFormatter(formatter, types, container.getWidth())) { 345 result = formatter; 346 break; 347 } 348 } 349 } 350 351 return result; 352 } 353 354 /** 355 * Returns the sitemap editor mode.<p> 356 * 357 * @return the sitemap editor mode 358 */ 359 public EditorMode getSitemapEditorMode() { 360 361 return m_sitemapEditorMode; 362 } 363 364 /** 365 * Gets the cached template bean for a given container page uri.<p> 366 * 367 * @param uri the container page uri 368 * @param safe if true, return a valid template bean even if it hasn't been cached before 369 * 370 * @return the template bean 371 */ 372 public TemplateBean getTemplateBean(String uri, boolean safe) { 373 374 TemplateBean templateBean = m_templateBeanCache.get(uri); 375 if ((templateBean != null) || !safe) { 376 return templateBean; 377 } 378 return new TemplateBean("", ""); 379 } 380 381 /** 382 * Returns true if, in this session, a newly opened container page editor window should display edit points for 383 * small elements initially.<p> 384 * 385 * @return true if small elements should be editable initially 386 */ 387 public boolean isEditSmallElements() { 388 389 return m_isEditSmallElements; 390 } 391 392 /** 393 * Returns the tool-bar visibility.<p> 394 * 395 * @return the tool-bar visibility 396 */ 397 public boolean isToolbarVisible() { 398 399 return m_toolbarVisible; 400 } 401 402 /** 403 * Caches the given container element under the given key.<p> 404 * 405 * @param key the cache key 406 * @param containerElement the object to cache 407 */ 408 public void setCacheContainerElement(String key, CmsContainerElementBean containerElement) { 409 410 if ((containerElement != null) && !containerElement.isDoNotCache()) { 411 m_containerElements.put(key, containerElement); 412 } 413 } 414 415 /** 416 * Caches the given XML content document.<p> 417 * 418 * @param structureId the structure id 419 * @param xmlContent the XML document 420 */ 421 public void setCacheXmlContent(CmsUUID structureId, CmsXmlContent xmlContent) { 422 423 m_xmlContents.put(structureId, xmlContent); 424 } 425 426 /** 427 * Set cached value for the attribute. Used for dynamically loaded values in the Acacia content editor. 428 * 429 * @param attribute the attribute for which the value should be cached 430 * @param value the value to cache 431 */ 432 public void setDynamicValue(String attribute, String value) { 433 434 if (null == m_dynamicValues) { 435 m_dynamicValues = new ConcurrentHashMap<String, String>(); 436 } 437 m_dynamicValues.put(attribute, value); 438 } 439 440 /** 441 * Sets the default initial setting for small element editability in this session.<p> 442 * 443 * @param editSmallElements true if small elements should be initially editable 444 */ 445 public void setEditSmallElements(boolean editSmallElements) { 446 447 m_isEditSmallElements = editSmallElements; 448 } 449 450 /** 451 * Sets the current element view id.<p> 452 * 453 * @param elementView the current element view id 454 */ 455 public void setElementView(CmsUUID elementView) { 456 457 m_elementView = elementView; 458 } 459 460 /** 461 * Stores information about the last edited container page.<p> 462 * 463 * @param cms the CMS context 464 * @param pageId the page id 465 * @param detailId the detail content id 466 */ 467 public void setLastPage(CmsObject cms, CmsUUID pageId, CmsUUID detailId) { 468 469 m_lastPage = new LastPageBean(cms.getRequestContext().getSiteRoot(), pageId, detailId); 470 471 } 472 473 /** 474 * Sets the last stored gallery search from the page editor.<p> 475 * 476 * @param searchObj the search to store 477 */ 478 public void setLastPageEditorGallerySearch(CmsGallerySearchBean searchObj) { 479 480 m_lastPageEditorGallerySearch = searchObj; 481 } 482 483 /** 484 * Sets the sitemap editor mode.<p> 485 * 486 * @param sitemapEditorMode the sitemap editor mode 487 */ 488 public void setSitemapEditorMode(EditorMode sitemapEditorMode) { 489 490 m_sitemapEditorMode = sitemapEditorMode; 491 } 492 493 /** 494 * Caches a template bean for a given container page URI.<p> 495 * 496 * @param uri the container page uri 497 * @param templateBean the template bean to cache 498 */ 499 public void setTemplateBean(String uri, TemplateBean templateBean) { 500 501 m_templateBeanCache.put(uri, templateBean); 502 } 503 504 /** 505 * Sets the tool-bar visibility flag.<p> 506 * 507 * @param toolbarVisible the tool-bar visibility to set 508 */ 509 public void setToolbarVisible(boolean toolbarVisible) { 510 511 m_toolbarVisible = toolbarVisible; 512 } 513 514 /** 515 * Purges the XML content document by the given id from the cache.<p> 516 * 517 * @param structureId the structure id 518 */ 519 public void uncacheXmlContent(CmsUUID structureId) { 520 521 m_xmlContents.remove(structureId); 522 m_dynamicValues = null; 523 } 524}