001 package org.apache.turbine.services.jsp; 002 003 004 /* 005 * Licensed to the Apache Software Foundation (ASF) under one 006 * or more contributor license agreements. See the NOTICE file 007 * distributed with this work for additional information 008 * regarding copyright ownership. The ASF licenses this file 009 * to you under the Apache License, Version 2.0 (the 010 * "License"); you may not use this file except in compliance 011 * with the License. You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, 016 * software distributed under the License is distributed on an 017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 018 * KIND, either express or implied. See the License for the 019 * specific language governing permissions and limitations 020 * under the License. 021 */ 022 023 024 import java.io.File; 025 import java.io.IOException; 026 027 import javax.servlet.RequestDispatcher; 028 import javax.servlet.ServletConfig; 029 import javax.servlet.http.HttpServletRequest; 030 031 import org.apache.commons.configuration.Configuration; 032 import org.apache.commons.lang.StringUtils; 033 import org.apache.commons.logging.Log; 034 import org.apache.commons.logging.LogFactory; 035 import org.apache.turbine.Turbine; 036 import org.apache.turbine.services.InitializationException; 037 import org.apache.turbine.services.pull.ApplicationTool; 038 import org.apache.turbine.services.pull.tools.TemplateLink; 039 import org.apache.turbine.services.template.BaseTemplateEngineService; 040 import org.apache.turbine.util.RunData; 041 import org.apache.turbine.util.TurbineException; 042 043 /** 044 * This is a Service that can process JSP templates from within a Turbine 045 * screen. 046 * 047 * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a> 048 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> 049 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> 050 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> 051 */ 052 public class TurbineJspService 053 extends BaseTemplateEngineService 054 implements JspService 055 { 056 /** The base path[s] prepended to filenames given in arguments */ 057 private String[] templatePaths; 058 059 /** The relative path[s] prepended to filenames */ 060 private String[] relativeTemplatePaths; 061 062 /** The buffer size for the output stream. */ 063 private int bufferSize; 064 065 /** Logging */ 066 private static Log log = LogFactory.getLog(TurbineJspService.class); 067 068 /** 069 * Load all configured components and initialize them. This is 070 * a zero parameter variant which queries the Turbine Servlet 071 * for its config. 072 * 073 * @throws InitializationException Something went wrong in the init 074 * stage 075 */ 076 @Override 077 public void init() 078 throws InitializationException 079 { 080 try 081 { 082 initJsp(); 083 registerConfiguration(JspService.JSP_EXTENSION); 084 setInit(true); 085 } 086 catch (Exception e) 087 { 088 throw new InitializationException( 089 "TurbineJspService failed to initialize", e); 090 } 091 } 092 093 /** 094 * Performs early initialization of this Turbine service. 095 * 096 * @param config The ServletConfiguration from Turbine 097 * 098 * @throws InitializationException Something went wrong when starting up. 099 * @deprecated use init() instead. 100 */ 101 @Deprecated 102 public void init(ServletConfig config) 103 throws InitializationException 104 { 105 init(); 106 } 107 108 /** 109 * Adds some convenience objects to the request. For example an instance 110 * of TemplateLink which can be used to generate links to other templates. 111 * 112 * @param data the turbine rundata object 113 */ 114 public void addDefaultObjects(RunData data) 115 { 116 HttpServletRequest req = data.getRequest(); 117 118 // 119 // This is a place where an Application Pull Tool is used 120 // in a regular Java Context. We have no Pull Service with the 121 // Jsp Paging stuff, but we can run our Application Tool by Hand: 122 // 123 ApplicationTool templateLink = new TemplateLink(); 124 templateLink.init(data); 125 126 req.setAttribute(LINK, templateLink); 127 req.setAttribute(RUNDATA, data); 128 } 129 130 /** 131 * Returns the default buffer size of the JspService 132 * 133 * @return The default buffer size. 134 */ 135 public int getDefaultBufferSize() 136 { 137 return bufferSize; 138 } 139 140 /** 141 * executes the JSP given by templateName. 142 * 143 * @param data A RunData Object 144 * @param templateName the filename of the template. 145 * @throws TurbineException Any exception thrown while processing will be 146 * wrapped into a TurbineException and rethrown. 147 */ 148 public void handleRequest(RunData data, String templateName) 149 throws TurbineException 150 { 151 handleRequest(data, templateName, false); 152 } 153 154 /** 155 * executes the JSP given by templateName. 156 * 157 * @param data A RunData Object 158 * @param templateName the filename of the template. 159 * @param isForward whether to perform a forward or include. 160 * @throws TurbineException Any exception trown while processing will be 161 * wrapped into a TurbineException and rethrown. 162 */ 163 public void handleRequest(RunData data, String templateName, boolean isForward) 164 throws TurbineException 165 { 166 /** template name with relative path */ 167 String relativeTemplateName = getRelativeTemplateName(templateName); 168 169 if (StringUtils.isEmpty(relativeTemplateName)) 170 { 171 throw new TurbineException( 172 "Template " + templateName + " not found in template paths"); 173 } 174 175 // get the RequestDispatcher for the JSP 176 RequestDispatcher dispatcher = data.getServletContext() 177 .getRequestDispatcher(relativeTemplateName); 178 179 try 180 { 181 if (isForward) 182 { 183 // forward the request to the JSP 184 dispatcher.forward(data.getRequest(), data.getResponse()); 185 } 186 else 187 { 188 data.getResponse().getWriter().flush(); 189 // include the JSP 190 dispatcher.include(data.getRequest(), data.getResponse()); 191 } 192 } 193 catch (Exception e) 194 { 195 // as JSP service is in Alpha stage, let's try hard to send the 196 // error message to the browser, to speed up debugging 197 try 198 { 199 data.getResponse().getWriter().print("Error encountered processing a template: " 200 + templateName); 201 e.printStackTrace(data.getResponse().getWriter()); 202 } 203 catch (IOException ignored) 204 { 205 // ignore 206 } 207 208 // pass the exception to the caller according to the general 209 // contract for tamplating services in Turbine 210 throw new TurbineException( 211 "Error encountered processing a template: " + templateName, e); 212 } 213 } 214 215 /** 216 * This method sets up the template cache. 217 */ 218 private void initJsp() 219 throws Exception 220 { 221 Configuration config = getConfiguration(); 222 223 // Set relative paths from config. 224 // Needed for javax.servlet.RequestDispatcher 225 relativeTemplatePaths = config.getStringArray(TEMPLATE_PATH_KEY); 226 227 // Use Turbine Servlet to translate the template paths. 228 templatePaths = new String [relativeTemplatePaths.length]; 229 for (int i=0; i < relativeTemplatePaths.length; i++) 230 { 231 relativeTemplatePaths[i] = warnAbsolute(relativeTemplatePaths[i]); 232 233 templatePaths[i] = Turbine.getRealPath(relativeTemplatePaths[i]); 234 } 235 236 bufferSize = config.getInt(JspService.BUFFER_SIZE_KEY, 237 JspService.BUFFER_SIZE_DEFAULT); 238 } 239 240 /** 241 * Determine whether a given template is available on the 242 * configured template pathes. 243 * 244 * @param template The name of the requested Template 245 * @return True if the template is available. 246 */ 247 @Override 248 public boolean templateExists(String template) 249 { 250 for (int i = 0; i < templatePaths.length; i++) 251 { 252 if (templateExists(templatePaths[i], template)) 253 { 254 return true; 255 } 256 } 257 return false; 258 } 259 260 /** 261 * Determine whether a given template exists on the supplied 262 * template path. This service ATM only supports file based 263 * templates so it simply checks for file existence. 264 * 265 * @param path The absolute (file system) template path 266 * @param template The name of the requested Template 267 * @return True if the template is available. 268 */ 269 private boolean templateExists(String path, String template) 270 { 271 return new File(path, template).exists(); 272 } 273 274 /** 275 * Searchs for a template in the default.template path[s] and 276 * returns the template name with a relative path which is 277 * required by <a href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletContext.html#getRequestDispatcher(java.lang.String)"> 278 * javax.servlet.RequestDispatcher</a> 279 * 280 * @param template 281 * @return String 282 */ 283 public String getRelativeTemplateName(String template) 284 { 285 template = warnAbsolute(template); 286 287 // Find which template path the template is in 288 // We have a 1:1 match between relative and absolute 289 // pathes so we can use the index for translation. 290 for (int i = 0; i < templatePaths.length; i++) 291 { 292 if (templateExists(templatePaths[i], template)) 293 { 294 return relativeTemplatePaths[i] + "/" + template; 295 } 296 } 297 return null; 298 } 299 300 /** 301 * Warn if a template name or path starts with "/". 302 * 303 * @param template The template to test 304 * @return The template name with a leading / stripped off 305 */ 306 private String warnAbsolute(String template) 307 { 308 if (template.startsWith("/")) 309 { 310 log.warn("Template " + template 311 + " has a leading /, which is wrong!"); 312 return template.substring(1); 313 } 314 return template; 315 } 316 }