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