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 }