View Javadoc

1   package org.apache.turbine.services.jsp;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  
25  import javax.servlet.RequestDispatcher;
26  import javax.servlet.ServletConfig;
27  import javax.servlet.http.HttpServletRequest;
28  
29  import org.apache.commons.configuration.Configuration;
30  
31  import org.apache.commons.lang.StringUtils;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  import org.apache.turbine.Turbine;
37  import org.apache.turbine.services.InitializationException;
38  import org.apache.turbine.services.pull.ApplicationTool;
39  import org.apache.turbine.services.pull.tools.TemplateLink;
40  import org.apache.turbine.services.template.BaseTemplateEngineService;
41  import org.apache.turbine.util.RunData;
42  import org.apache.turbine.util.TurbineException;
43  
44  /***
45   * This is a Service that can process JSP templates from within a Turbine
46   * screen.
47   *
48   * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
49   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
50   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
51   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
52   * @version $Id: TurbineJspService.java 534527 2007-05-02 16:10:59Z tv $
53   */
54  public class TurbineJspService
55          extends BaseTemplateEngineService
56          implements JspService
57  {
58      /*** The base path[s] prepended to filenames given in arguments */
59      private String[] templatePaths;
60  
61      /*** The relative path[s] prepended to filenames */
62      private String[] relativeTemplatePaths;
63  
64      /*** The buffer size for the output stream. */
65      private int bufferSize;
66  
67      /*** Logging */
68      private static Log log = LogFactory.getLog(TurbineJspService.class);
69  
70      /***
71       * Load all configured components and initialize them. This is
72       * a zero parameter variant which queries the Turbine Servlet
73       * for its config.
74       *
75       * @throws InitializationException Something went wrong in the init
76       *         stage
77       */
78      public void init()
79          throws InitializationException
80      {
81          try
82          {
83              initJsp();
84              registerConfiguration(JspService.JSP_EXTENSION);
85              setInit(true);
86          }
87          catch (Exception e)
88          {
89              throw new InitializationException(
90                  "TurbineJspService failed to initialize", e);
91          }
92      }
93  
94      /***
95       * Performs early initialization of this Turbine service.
96       *
97       * @param config The ServletConfiguration from Turbine
98       *
99       * @throws InitializationException Something went wrong when starting up.
100      * @deprecated use init() instead.
101      */
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.getOut().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.getOut().print("Error encountered processing a template: "
200                     + templateName);
201                 e.printStackTrace(data.getOut());
202             }
203             catch (IOException ignored)
204             {
205             }
206 
207             // pass the exception to the caller according to the general
208             // contract for tamplating services in Turbine
209             throw new TurbineException(
210                 "Error encountered processing a template: " + templateName, e);
211         }
212     }
213 
214     /***
215      * This method sets up the template cache.
216      */
217     private void initJsp()
218         throws Exception
219     {
220         Configuration config = getConfiguration();
221 
222         // Set relative paths from config.
223         // Needed for javax.servlet.RequestDispatcher
224         relativeTemplatePaths = config.getStringArray(TEMPLATE_PATH_KEY);
225 
226         // Use Turbine Servlet to translate the template paths.
227         templatePaths = new String [relativeTemplatePaths.length];
228         for (int i=0; i < relativeTemplatePaths.length; i++)
229         {
230             relativeTemplatePaths[i] = warnAbsolute(relativeTemplatePaths[i]);
231 
232             templatePaths[i] = Turbine.getRealPath(relativeTemplatePaths[i]);
233         }
234 
235         bufferSize = config.getInt(JspService.BUFFER_SIZE_KEY,
236             JspService.BUFFER_SIZE_DEFAULT);
237     }
238 
239     /***
240      * Determine whether a given template is available on the
241      * configured template pathes.
242      *
243      * @param template The name of the requested Template
244      * @return True if the template is available.
245      */
246     public boolean templateExists(String template)
247     {
248         for (int i = 0; i < templatePaths.length; i++)
249         {
250             if (templateExists(templatePaths[i], template))
251             {
252                 return true;
253             }
254         }
255         return false;
256     }
257 
258     /***
259      * Determine whether a given template exists on the supplied
260      * template path. This service ATM only supports file based
261      * templates so it simply checks for file existence.
262      *
263      * @param path The absolute (file system) template path
264      * @param template The name of the requested Template
265      * @return True if the template is available.
266      */
267     private boolean templateExists(String path, String template)
268     {
269         return new File(path, template).exists();
270     }
271 
272     /***
273      * Searchs for a template in the default.template path[s] and
274      * returns the template name with a relative path which is
275      * required by <a href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletContext.html#getRequestDispatcher(java.lang.String)">
276      * javax.servlet.RequestDispatcher</a>
277      *
278      * @param template
279      * @return String
280      */
281     public String getRelativeTemplateName(String template)
282     {
283         template = warnAbsolute(template);
284 
285         // Find which template path the template is in
286         // We have a 1:1 match between relative and absolute
287         // pathes so we can use the index for translation.
288         for (int i = 0; i < templatePaths.length; i++)
289         {
290             if (templateExists(templatePaths[i], template))
291             {
292                 return relativeTemplatePaths[i] + "/" + template;
293             }
294         }
295         return null;
296     }
297 
298     /***
299      * Warn if a template name or path starts with "/".
300      *
301      * @param template The template to test
302      * @return The template name with a leading / stripped off
303      */
304     private String warnAbsolute(String template)
305     {
306         if (template.startsWith("/"))
307         {
308             log.warn("Template " + template
309                 + " has a leading /, which is wrong!");
310             return template.substring(1);
311         }
312         return template;
313     }
314 }