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.ade.configuration.plugins; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.containerpage.CmsDetailOnlyContainerUtil; 032import org.opencms.file.CmsObject; 033import org.opencms.file.CmsResource; 034import org.opencms.file.CmsResourceFilter; 035import org.opencms.jsp.CmsJspTagContainer; 036import org.opencms.jsp.Messages; 037import org.opencms.jsp.util.CmsJspStandardContextBean; 038import org.opencms.main.CmsException; 039import org.opencms.main.CmsLog; 040import org.opencms.main.OpenCms; 041import org.opencms.relations.CmsLinkInfo; 042import org.opencms.xml.containerpage.CmsContainerBean; 043import org.opencms.xml.containerpage.CmsContainerElementBean; 044import org.opencms.xml.containerpage.CmsContainerPageBean; 045import org.opencms.xml.containerpage.CmsFormatterConfiguration; 046import org.opencms.xml.containerpage.I_CmsFormatterBean; 047 048import java.util.ArrayList; 049import java.util.Collections; 050import java.util.HashSet; 051import java.util.List; 052import java.util.Set; 053 054import javax.servlet.http.HttpServletRequest; 055 056import org.apache.commons.logging.Log; 057 058import com.google.common.collect.ArrayListMultimap; 059import com.google.common.collect.Multimap; 060 061/** 062 * Helper class for finding the list of active template plugins for the current page. 063 */ 064public class CmsTemplatePluginFinder { 065 066 /** Log instance for this class. */ 067 private static final Log LOG = CmsLog.getLog(CmsTemplatePluginFinder.class); 068 069 /** Current standard context bean. */ 070 private CmsJspStandardContextBean m_standardContextBean; 071 072 /** 073 * Creates a new instance. 074 * 075 * @param standardContextBean the current standard context bean 076 */ 077 public CmsTemplatePluginFinder(CmsJspStandardContextBean standardContextBean) { 078 079 m_standardContextBean = standardContextBean; 080 } 081 082 /** 083 * Gets the active plugins from site plugins only. 084 * 085 * @param config the sitemap configuration for which to get the plugins 086 * 087 * @return the multimap of active plugins by group 088 */ 089 public static Multimap<String, CmsTemplatePlugin> getActiveTemplatePluginsFromSitePlugins(CmsADEConfigData config) { 090 091 List<CmsTemplatePlugin> plugins = new ArrayList<>(); 092 for (CmsSitePlugin sitePlugin : config.getSitePlugins()) { 093 plugins.addAll(sitePlugin.getPlugins()); 094 } 095 return getActivePlugins(plugins); 096 } 097 098 /** 099 * Collects the referenced plugins from the current page (from container elements, detail elements, etc.). 100 * 101 * @param standardContext the standard context bean 102 * @return the list of plugins (unsorted, with duplicates) 103 * 104 * @throws CmsException if something goes wrong 105 */ 106 private static List<CmsTemplatePlugin> collectPluginsForCurrentPage(CmsJspStandardContextBean standardContext) 107 throws CmsException { 108 109 List<CmsTemplatePlugin> plugins = new ArrayList<>(); 110 CmsObject cms = standardContext.getVfs().getCmsObject(); 111 HttpServletRequest req = (HttpServletRequest)(standardContext.getRequest()); 112 standardContext.initPage(); 113 114 CmsContainerPageBean containerPage = standardContext.getPage(); 115 CmsADEConfigData config = OpenCms.getADEManager().lookupConfigurationWithCache( 116 cms, 117 cms.getRequestContext().getRootUri()); 118 if ((containerPage != null) && (containerPage.getElements() != null)) { 119 List<CmsContainerBean> containers = new ArrayList<CmsContainerBean>(containerPage.getContainers().values()); 120 // add detail only containers if available 121 if (standardContext.isDetailRequest()) { 122 CmsContainerPageBean detailOnly = CmsDetailOnlyContainerUtil.getDetailOnlyPage( 123 cms, 124 req, 125 cms.getRequestContext().getRootUri()); 126 if (detailOnly != null) { 127 containers.addAll(detailOnly.getContainers().values()); 128 } 129 } 130 for (CmsContainerBean container : containers) { 131 for (CmsContainerElementBean element : container.getElements()) { 132 try { 133 element.initResource(cms); 134 if (!standardContext.getIsOnlineProject() 135 || element.getResource().isReleasedAndNotExpired( 136 cms.getRequestContext().getRequestTime())) { 137 if (element.isGroupContainer(cms) || element.isInheritedContainer(cms)) { 138 List<CmsContainerElementBean> subElements; 139 if (element.isGroupContainer(cms)) { 140 subElements = CmsJspTagContainer.getGroupContainerElements( 141 cms, 142 element, 143 req, 144 container.getType()); 145 } else { 146 subElements = CmsJspTagContainer.getInheritedContainerElements(cms, element); 147 } 148 for (CmsContainerElementBean subElement : subElements) { 149 subElement.initResource(cms); 150 if (!standardContext.getIsOnlineProject() 151 || subElement.getResource().isReleasedAndNotExpired( 152 cms.getRequestContext().getRequestTime())) { 153 I_CmsFormatterBean formatter = getFormatterBeanForElement( 154 cms, 155 config, 156 subElement, 157 container); 158 if (formatter != null) { 159 plugins.addAll(formatter.getTemplatePlugins()); 160 } 161 } 162 } 163 } else { 164 I_CmsFormatterBean formatter = getFormatterBeanForElement( 165 cms, 166 config, 167 element, 168 container); 169 if (formatter != null) { 170 plugins.addAll(formatter.getTemplatePlugins()); 171 } 172 } 173 } 174 } catch (CmsException e) { 175 LOG.error( 176 Messages.get().getBundle().key( 177 Messages.ERR_READING_REQUIRED_RESOURCE_1, 178 element.getSitePath()), 179 e); 180 } 181 } 182 } 183 } 184 if (standardContext.getDetailContentId() != null) { 185 try { 186 CmsResource detailContent = cms.readResource( 187 standardContext.getDetailContentId(), 188 CmsResourceFilter.ignoreExpirationOffline(cms)); 189 CmsFormatterConfiguration detailContentFormatters = config.getFormatters(cms, detailContent); 190 for (I_CmsFormatterBean formatter : detailContentFormatters.getDetailFormatters()) { 191 plugins.addAll(formatter.getTemplatePlugins()); 192 } 193 } catch (CmsException e) { 194 LOG.error( 195 Messages.get().getBundle().key( 196 Messages.ERR_READING_REQUIRED_RESOURCE_1, 197 standardContext.getDetailContentId()), 198 e); 199 } 200 } 201 for (CmsSitePlugin sitePlugin : config.getSitePlugins()) { 202 plugins.addAll(sitePlugin.getPlugins()); 203 } 204 return plugins; 205 } 206 207 /** 208 * Gets the active plugins by group as a multimap, with each group sorted by descending order. 209 * 210 * @param plugins unsorted list of plugins, possibly with duplicates 211 * @return multimap of plugins by group 212 */ 213 private static Multimap<String, CmsTemplatePlugin> getActivePlugins(List<CmsTemplatePlugin> plugins) { 214 215 Multimap<String, CmsTemplatePlugin> pluginsByGroup = ArrayListMultimap.create(); 216 for (CmsTemplatePlugin plugin : plugins) { 217 pluginsByGroup.put(plugin.getGroup(), plugin); 218 } 219 Multimap<String, CmsTemplatePlugin> result = ArrayListMultimap.create(); 220 for (String group : pluginsByGroup.keySet()) { 221 List<CmsTemplatePlugin> active = sortAndDeduplicatePlugins( 222 (List<CmsTemplatePlugin>)(pluginsByGroup.get(group))); 223 result.putAll(group, active); 224 } 225 return result; 226 } 227 228 /** 229 * Returns the formatter configuration for the given element, will return <code>null</code> for schema formatters.<p> 230 * 231 * @param cms the current CMS context 232 * @param config the current sitemap configuration 233 * @param element the element bean 234 * @param container the container bean 235 * 236 * @return the formatter configuration bean 237 */ 238 private static I_CmsFormatterBean getFormatterBeanForElement( 239 CmsObject cms, 240 CmsADEConfigData config, 241 CmsContainerElementBean element, 242 CmsContainerBean container) { 243 244 int containerWidth = -1; 245 if (container.getWidth() == null) { 246 // the container width has not been set yet 247 containerWidth = CmsFormatterConfiguration.MATCH_ALL_CONTAINER_WIDTH; 248 } else { 249 try { 250 containerWidth = Integer.parseInt(container.getWidth()); 251 } catch (NumberFormatException e) { 252 // do nothing, set width to -1 253 } 254 } 255 I_CmsFormatterBean result = CmsJspTagContainer.getFormatterConfigurationForElement( 256 cms, 257 element, 258 config, 259 container.getName(), 260 container.getType(), 261 containerWidth); 262 return result; 263 } 264 265 /** 266 * Sorts and de-duplicates a list of plugins. 267 * 268 * <p>This returns a new list and does not modify the input list. 269 * 270 * @param plugins the list of plugins 271 * @return the sorted and de-duplicated plugins 272 */ 273 private static List<CmsTemplatePlugin> sortAndDeduplicatePlugins(List<CmsTemplatePlugin> plugins) { 274 275 List<CmsTemplatePlugin> result = new ArrayList<>(); 276 Set<CmsLinkInfo> seenTargets = new HashSet<>(); 277 // sort in descending order 278 Collections.sort(plugins, (p1, p2) -> Integer.compare(p2.getOrder(), p1.getOrder())); 279 for (CmsTemplatePlugin plugin : plugins) { 280 try { 281 // only add the first occurrence of a given target 282 CmsLinkInfo target = plugin.getTarget(); 283 if (!seenTargets.contains(target)) { 284 seenTargets.add(target); 285 result.add(plugin); 286 } 287 } catch (Exception e) { 288 LOG.error(e.getLocalizedMessage(), e); 289 } 290 } 291 return result; 292 } 293 294 /** 295 * Gets the multimap of plugins for the current page by group, with each group sorted and de-duplicated. 296 * 297 * @return the multimap of plugins 298 */ 299 public Multimap<String, CmsTemplatePlugin> getTemplatePlugins() { 300 301 try { 302 return getActivePlugins(collectPluginsForCurrentPage(m_standardContextBean)); 303 } catch (Exception e) { 304 LOG.error(e.getLocalizedMessage(), e); 305 return ArrayListMultimap.create(); 306 } 307 } 308 309}