View Javadoc

1   package org.apache.turbine.services.jsp;
2   
3   
4   /*
5    * Licensed to the Apache Software Foundation (ASF) under one
6    * or more contributor license agreements.  See the NOTICE file
7    * distributed with this work for additional information
8    * regarding copyright ownership.  The ASF licenses this file
9    * to you under the Apache License, Version 2.0 (the
10   * "License"); you may not use this file except in compliance
11   * with the License.  You may obtain a copy of the License at
12   *
13   *   http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing,
16   * software distributed under the License is distributed on an
17   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18   * KIND, either express or implied.  See the License for the
19   * specific language governing permissions and limitations
20   * under the License.
21   */
22  
23  
24  import java.io.File;
25  import java.io.IOException;
26  
27  import javax.servlet.RequestDispatcher;
28  import javax.servlet.ServletConfig;
29  import javax.servlet.http.HttpServletRequest;
30  
31  import org.apache.commons.configuration.Configuration;
32  import org.apache.commons.lang.StringUtils;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.turbine.Turbine;
36  import org.apache.turbine.services.InitializationException;
37  import org.apache.turbine.services.pull.ApplicationTool;
38  import org.apache.turbine.services.pull.tools.TemplateLink;
39  import org.apache.turbine.services.template.BaseTemplateEngineService;
40  import org.apache.turbine.util.RunData;
41  import org.apache.turbine.util.TurbineException;
42  
43  /**
44   * This is a Service that can process JSP templates from within a Turbine
45   * screen.
46   *
47   * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
48   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
49   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
50   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
51   */
52  public class TurbineJspService
53          extends BaseTemplateEngineService
54          implements JspService
55  {
56      /** The base path[s] prepended to filenames given in arguments */
57      private String[] templatePaths;
58  
59      /** The relative path[s] prepended to filenames */
60      private String[] relativeTemplatePaths;
61  
62      /** The buffer size for the output stream. */
63      private int bufferSize;
64  
65      /** Logging */
66      private static Log log = LogFactory.getLog(TurbineJspService.class);
67  
68      /**
69       * Load all configured components and initialize them. This is
70       * a zero parameter variant which queries the Turbine Servlet
71       * for its config.
72       *
73       * @throws InitializationException Something went wrong in the init
74       *         stage
75       */
76      @Override
77      public void init()
78          throws InitializationException
79      {
80          try
81          {
82              initJsp();
83              registerConfiguration(JspService.JSP_EXTENSION);
84              setInit(true);
85          }
86          catch (Exception e)
87          {
88              throw new InitializationException(
89                  "TurbineJspService failed to initialize", e);
90          }
91      }
92  
93      /**
94       * Performs early initialization of this Turbine service.
95       *
96       * @param config The ServletConfiguration from Turbine
97       *
98       * @throws InitializationException Something went wrong when starting up.
99       * @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 }