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<CmsUUID>> m_recentFormatters = new ConcurrentHashMap<String, List<CmsUUID>>(); 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 formatterId the formatter id 228 */ 229 public void addRecentFormatter(String resType, CmsUUID formatterId) { 230 231 List<CmsUUID> formatterIds = m_recentFormatters.get(resType); 232 if (formatterIds == null) { 233 formatterIds = new ArrayList<CmsUUID>(); 234 m_recentFormatters.put(resType, formatterIds); 235 } 236 formatterIds.remove(formatterId); 237 if (formatterIds.size() >= (RECENT_FORMATTERS_SIZE)) { 238 formatterIds.remove(RECENT_FORMATTERS_SIZE - 1); 239 } 240 formatterIds.add(0, formatterId); 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<CmsUUID> formatterIds = m_recentFormatters.get(resType); 337 if (formatterIds != null) { 338 Map<CmsUUID, I_CmsFormatterBean> availableFormatters = config.getActiveFormatters(); 339 Set<String> types = new HashSet<String>(Arrays.asList(container.getType().trim().split(" *, *"))); 340 for (CmsUUID id : formatterIds) { 341 I_CmsFormatterBean formatter = availableFormatters.get(id); 342 if ((formatter != null) 343 && CmsFormatterConfiguration.matchFormatter(formatter, types, container.getWidth())) { 344 result = formatter; 345 break; 346 } 347 } 348 } 349 350 return result; 351 } 352 353 /** 354 * Returns the sitemap editor mode.<p> 355 * 356 * @return the sitemap editor mode 357 */ 358 public EditorMode getSitemapEditorMode() { 359 360 return m_sitemapEditorMode; 361 } 362 363 /** 364 * Gets the cached template bean for a given container page uri.<p> 365 * 366 * @param uri the container page uri 367 * @param safe if true, return a valid template bean even if it hasn't been cached before 368 * 369 * @return the template bean 370 */ 371 public TemplateBean getTemplateBean(String uri, boolean safe) { 372 373 TemplateBean templateBean = m_templateBeanCache.get(uri); 374 if ((templateBean != null) || !safe) { 375 return templateBean; 376 } 377 return new TemplateBean("", ""); 378 } 379 380 /** 381 * Returns true if, in this session, a newly opened container page editor window should display edit points for 382 * small elements initially.<p> 383 * 384 * @return true if small elements should be editable initially 385 */ 386 public boolean isEditSmallElements() { 387 388 return m_isEditSmallElements; 389 } 390 391 /** 392 * Returns the tool-bar visibility.<p> 393 * 394 * @return the tool-bar visibility 395 */ 396 public boolean isToolbarVisible() { 397 398 return m_toolbarVisible; 399 } 400 401 /** 402 * Caches the given container element under the given key.<p> 403 * 404 * @param key the cache key 405 * @param containerElement the object to cache 406 */ 407 public void setCacheContainerElement(String key, CmsContainerElementBean containerElement) { 408 409 m_containerElements.put(key, containerElement); 410 } 411 412 /** 413 * Caches the given XML content document.<p> 414 * 415 * @param structureId the structure id 416 * @param xmlContent the XML document 417 */ 418 public void setCacheXmlContent(CmsUUID structureId, CmsXmlContent xmlContent) { 419 420 m_xmlContents.put(structureId, xmlContent); 421 } 422 423 /** 424 * Set cached value for the attribute. Used for dynamically loaded values in the Acacia content editor. 425 * 426 * @param attribute the attribute for which the value should be cached 427 * @param value the value to cache 428 */ 429 public void setDynamicValue(String attribute, String value) { 430 431 if (null == m_dynamicValues) { 432 m_dynamicValues = new ConcurrentHashMap<String, String>(); 433 } 434 m_dynamicValues.put(attribute, value); 435 } 436 437 /** 438 * Sets the default initial setting for small element editability in this session.<p> 439 * 440 * @param editSmallElements true if small elements should be initially editable 441 */ 442 public void setEditSmallElements(boolean editSmallElements) { 443 444 m_isEditSmallElements = editSmallElements; 445 } 446 447 /** 448 * Sets the current element view id.<p> 449 * 450 * @param elementView the current element view id 451 */ 452 public void setElementView(CmsUUID elementView) { 453 454 m_elementView = elementView; 455 } 456 457 /** 458 * Stores information about the last edited container page.<p> 459 * 460 * @param cms the CMS context 461 * @param pageId the page id 462 * @param detailId the detail content id 463 */ 464 public void setLastPage(CmsObject cms, CmsUUID pageId, CmsUUID detailId) { 465 466 m_lastPage = new LastPageBean(cms.getRequestContext().getSiteRoot(), pageId, detailId); 467 468 } 469 470 /** 471 * Sets the last stored gallery search from the page editor.<p> 472 * 473 * @param searchObj the search to store 474 */ 475 public void setLastPageEditorGallerySearch(CmsGallerySearchBean searchObj) { 476 477 m_lastPageEditorGallerySearch = searchObj; 478 } 479 480 /** 481 * Sets the sitemap editor mode.<p> 482 * 483 * @param sitemapEditorMode the sitemap editor mode 484 */ 485 public void setSitemapEditorMode(EditorMode sitemapEditorMode) { 486 487 m_sitemapEditorMode = sitemapEditorMode; 488 } 489 490 /** 491 * Caches a template bean for a given container page URI.<p> 492 * 493 * @param uri the container page uri 494 * @param templateBean the template bean to cache 495 */ 496 public void setTemplateBean(String uri, TemplateBean templateBean) { 497 498 m_templateBeanCache.put(uri, templateBean); 499 } 500 501 /** 502 * Sets the tool-bar visibility flag.<p> 503 * 504 * @param toolbarVisible the tool-bar visibility to set 505 */ 506 public void setToolbarVisible(boolean toolbarVisible) { 507 508 m_toolbarVisible = toolbarVisible; 509 } 510 511 /** 512 * Purges the XML content document by the given id from the cache.<p> 513 * 514 * @param structureId the structure id 515 */ 516 public void uncacheXmlContent(CmsUUID structureId) { 517 518 m_xmlContents.remove(structureId); 519 m_dynamicValues = null; 520 } 521}