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.jsp.util; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.cache.CmsVfsMemoryObjectCache; 032import org.opencms.file.CmsObject; 033import org.opencms.file.CmsResource; 034import org.opencms.file.types.CmsResourceTypeFunctionConfig; 035import org.opencms.flex.CmsFlexController; 036import org.opencms.jsp.CmsJspTagInclude; 037import org.opencms.main.CmsException; 038import org.opencms.main.CmsLog; 039import org.opencms.main.CmsRuntimeException; 040import org.opencms.main.OpenCms; 041import org.opencms.util.CmsRequestUtil; 042import org.opencms.util.CmsUUID; 043import org.opencms.xml.containerpage.CmsContainerElementBean; 044import org.opencms.xml.containerpage.CmsDynamicFunctionBean; 045import org.opencms.xml.containerpage.CmsDynamicFunctionParser; 046import org.opencms.xml.containerpage.CmsFunctionFormatterBean; 047import org.opencms.xml.containerpage.I_CmsFormatterBean; 048import org.opencms.xml.content.CmsXmlContent; 049import org.opencms.xml.content.CmsXmlContentFactory; 050 051import java.io.IOException; 052import java.util.HashMap; 053import java.util.Locale; 054import java.util.Map; 055import java.util.Map.Entry; 056 057import javax.servlet.http.HttpServletRequest; 058import javax.servlet.http.HttpServletResponse; 059import javax.servlet.jsp.JspException; 060import javax.servlet.jsp.PageContext; 061 062import org.apache.commons.logging.Log; 063 064/** 065 * Class used for rendering dynamic functions (v2).<p> 066 */ 067public class CmsFunctionRenderer { 068 069 /** The logger instance for this class. */ 070 private static final Log LOG = CmsLog.getLog(CmsFunctionRenderer.class); 071 072 /** The current cms context. */ 073 private CmsObject m_cms; 074 075 /** The page context. */ 076 private PageContext m_context; 077 078 /** The JSP context bean. */ 079 private CmsJspStandardContextBean m_contextBean; 080 081 /** The element to render. */ 082 private CmsContainerElementBean m_element; 083 084 /** The request. */ 085 private HttpServletRequest m_request; 086 087 /** The response. */ 088 private HttpServletResponse m_response; 089 090 /** 091 * Constructor.<p> 092 * 093 * @param context the page context 094 * @param req the request 095 * @param res the response 096 */ 097 public CmsFunctionRenderer(PageContext context, HttpServletRequest req, HttpServletResponse res) { 098 099 m_context = context; 100 m_request = req; 101 m_response = res; 102 CmsFlexController controller = CmsFlexController.getController(req); 103 if (controller == null) { 104 handleMissingFlexController(); 105 return; 106 } 107 m_cms = controller.getCmsObject(); 108 m_contextBean = CmsJspStandardContextBean.getInstance(m_request); 109 m_element = m_contextBean.getElement(); 110 } 111 112 /** 113 * Returns the default output for functions without configured JSPs. 114 * 115 * @param request the current request 116 * @return the default HTML output 117 */ 118 public static String defaultHtml(HttpServletRequest request) { 119 120 CmsObject cms = CmsFlexController.getController(request).getCmsObject(); 121 122 // We only want the big red warning in Offline mode 123 if (cms.getRequestContext().getCurrentProject().isOnlineProject()) { 124 return "<div><!--Dynamic function not configured--></div>"; 125 } else { 126 Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms); 127 String message = Messages.get().getBundle(locale).key(Messages.GUI_FUNCTION_DEFAULT_HTML_0); 128 return "<div style=\"border: 2px solid red; padding: 10px;\">" + message + "</div>"; 129 } 130 } 131 132 /** 133 * Cached method for accessing the default function formatter.<p> 134 * 135 * @param cms the current CMS context 136 * @return the default function formatter resource 137 */ 138 public static CmsResource getDefaultFunctionInstance(CmsObject cms) { 139 140 String path = "/system/modules/org.opencms.base/formatters/function-default.xml"; 141 return getDefaultResource(cms, path); 142 } 143 144 /** 145 * Cached method for accessing the default function formatter JSP.<p> 146 * 147 * @param cms the current CMS context 148 * @return the default function formatter JSP 149 */ 150 public static CmsResource getDefaultFunctionJsp(CmsObject cms) { 151 152 return getDefaultResource(cms, "/system/modules/org.opencms.base/formatters/function-default.jsp"); 153 } 154 155 /** 156 * Helper method for cached reading of resources under specific, fixed paths.<p> 157 * 158 * @param cms the current CMS context 159 * @param path the path to read 160 * 161 * @return the resource which has been read 162 */ 163 private static CmsResource getDefaultResource(CmsObject cms, String path) { 164 165 CmsResource resource = (CmsResource)CmsVfsMemoryObjectCache.getVfsMemoryObjectCache().getCachedObject( 166 cms, 167 path); 168 if (resource == null) { 169 try { 170 resource = cms.readResource(path); 171 CmsVfsMemoryObjectCache.getVfsMemoryObjectCache().putCachedObject(cms, path, resource); 172 } catch (CmsException e) { 173 LOG.warn(e.getLocalizedMessage(), e); 174 } 175 } 176 return resource; 177 } 178 179 /** 180 * Renders the requested element content with the flex formatter string template.<p> 181 * 182 * @throws IOException in case writing to to page context out fails 183 * @throws JspException in case something goes wrong during the JSP include 184 */ 185 public void render() throws IOException, JspException { 186 187 boolean isNewFunctionType = OpenCms.getResourceManager().matchResourceType( 188 CmsResourceTypeFunctionConfig.TYPE_NAME, 189 m_element.getResource().getTypeId()); 190 if (isNewFunctionType) { 191 CmsFunctionFormatterBean function = getFormatterBean(m_cms); 192 if (function != null) { 193 CmsUUID jspId = function.getRealJspId(); 194 if (jspId != null) { 195 CmsJspTagInclude.includeTagAction( 196 m_context, 197 m_cms.getRequestContext().removeSiteRoot(function.getRealJspRootPath()), 198 null, 199 m_cms.getRequestContext().getLocale(), 200 false, 201 m_cms.getRequestContext().getCurrentProject().isOnlineProject(), 202 function.getParameters(), 203 CmsRequestUtil.getAttributeMap(m_request), 204 m_request, 205 m_response); 206 } else { 207 m_context.getOut().print(defaultHtml(m_request)); 208 } 209 } else { 210 m_context.getOut().print(defaultHtml(m_request)); 211 } 212 } else { 213 CmsDynamicFunctionBean.Format format = getFunctionFormat(); 214 if ((format != null) && m_cms.existsResource(format.getJspStructureId())) { 215 try { 216 CmsResource jspResource = m_cms.readResource(format.getJspStructureId()); 217 Map<String, String[]> params = new HashMap<>(); 218 for (Entry<String, String> paramEntry : format.getParameters().entrySet()) { 219 params.put(paramEntry.getKey(), new String[] {paramEntry.getValue()}); 220 } 221 CmsJspTagInclude.includeTagAction( 222 m_context, 223 224 m_cms.getSitePath(jspResource), 225 null, 226 m_cms.getRequestContext().getLocale(), 227 false, 228 m_cms.getRequestContext().getCurrentProject().isOnlineProject(), 229 params, 230 CmsRequestUtil.getAttributeMap(m_request), 231 m_request, 232 m_response); 233 } catch (CmsException e) { 234 LOG.error(e.getLocalizedMessage(), e); 235 } 236 } else { 237 m_context.getOut().print(defaultHtml(m_request)); 238 } 239 } 240 } 241 242 /** 243 * Gets the formatter bean for the current element.<p> 244 * 245 * @param cms the current CMS contxt 246 * @return the formatter bean for the current element 247 */ 248 private CmsFunctionFormatterBean getFormatterBean(CmsObject cms) { 249 250 CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration( 251 cms, 252 cms.getRequestContext().getRootUri()); 253 // Using getId(), *not* getFormatterId() here , since the former is the id of the function formatter configuration, 254 // and the latter is just the id of the internal JSP used to render it 255 I_CmsFormatterBean formatterConfig = config.findFormatter(m_element.getId()); 256 CmsFunctionFormatterBean function = (CmsFunctionFormatterBean)formatterConfig; 257 return function; 258 } 259 260 /** 261 * Returns the function format for the current element.<p> 262 * 263 * @return the function format 264 */ 265 private CmsDynamicFunctionBean.Format getFunctionFormat() { 266 267 CmsDynamicFunctionBean functionBean = null; 268 try { 269 CmsXmlContent content = CmsXmlContentFactory.unmarshal(m_cms, m_cms.readFile(m_element.getResource())); 270 CmsDynamicFunctionParser parser = new CmsDynamicFunctionParser(); 271 functionBean = parser.parseFunctionBean(m_cms, content); 272 } catch (CmsException e) { 273 LOG.debug(e.getLocalizedMessage(), e); 274 return null; 275 } 276 CmsJspStandardContextBean contextBean = CmsJspStandardContextBean.getInstance(m_request); 277 String type = contextBean.getContainer().getType(); 278 String width = contextBean.getContainer().getWidth(); 279 int widthNum = -1; 280 try { 281 widthNum = Integer.parseInt(width); 282 } catch (NumberFormatException e) { 283 LOG.debug(e.getLocalizedMessage(), e); 284 } 285 return functionBean.getFormatForContainer(m_cms, type, widthNum); 286 } 287 288 /** 289 * This method is called when the flex controller can not be found during initialization.<p> 290 * 291 * Override this if you are reusing old workplace classes in a context where no flex controller is available. 292 */ 293 private void handleMissingFlexController() { 294 295 // controller not found - this request was not initialized properly 296 throw new CmsRuntimeException( 297 org.opencms.jsp.Messages.get().container( 298 org.opencms.jsp.Messages.ERR_MISSING_CMS_CONTROLLER_1, 299 CmsMacroFormatterResolver.class.getName())); 300 } 301 302}