View Javadoc

1   package org.apache.turbine.services.jsp;
2   
3   /*
4    * Copyright 2001-2005 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License")
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.io.File;
20  import java.io.IOException;
21  
22  import javax.servlet.RequestDispatcher;
23  import javax.servlet.ServletConfig;
24  import javax.servlet.http.HttpServletRequest;
25  
26  import org.apache.commons.configuration.Configuration;
27  
28  import org.apache.commons.lang.StringUtils;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  
33  import org.apache.turbine.Turbine;
34  import org.apache.turbine.services.InitializationException;
35  import org.apache.turbine.services.pull.ApplicationTool;
36  import org.apache.turbine.services.pull.tools.TemplateLink;
37  import org.apache.turbine.services.template.BaseTemplateEngineService;
38  import org.apache.turbine.util.RunData;
39  import org.apache.turbine.util.TurbineException;
40  
41  /***
42   * This is a Service that can process JSP templates from within a Turbine
43   * screen.
44   *
45   * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
46   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
47   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
48   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
49   * @version $Id: TurbineJspService.java 264148 2005-08-29 14:21:04Z henning $
50   */
51  public class TurbineJspService
52          extends BaseTemplateEngineService
53          implements JspService
54  {
55      /*** The base path[s] prepended to filenames given in arguments */
56      private String[] templatePaths;
57  
58      /*** The relative path[s] prepended to filenames */
59      private String[] relativeTemplatePaths;
60  
61      /*** The buffer size for the output stream. */
62      private int bufferSize;
63  
64      /*** Logging */
65      private static Log log = LogFactory.getLog(TurbineJspService.class);
66  
67      /***
68       * Load all configured components and initialize them. This is
69       * a zero parameter variant which queries the Turbine Servlet
70       * for its config.
71       *
72       * @throws InitializationException Something went wrong in the init
73       *         stage
74       */
75      public void init()
76          throws InitializationException
77      {
78          try
79          {
80              initJsp();
81              registerConfiguration(JspService.JSP_EXTENSION);
82              setInit(true);
83          }
84          catch (Exception e)
85          {
86              throw new InitializationException(
87                  "TurbineJspService failed to initialize", e);
88          }
89      }
90  
91      /***
92       * Performs early initialization of this Turbine service.
93       *
94       * @param config The ServletConfiguration from Turbine
95       *
96       * @throws InitializationException Something went wrong when starting up.
97       * @deprecated use init() instead.
98       */
99      public void init(ServletConfig config)
100         throws InitializationException
101     {
102         init();
103     }
104 
105     /***
106      * Adds some convenience objects to the request.  For example an instance
107      * of TemplateLink which can be used to generate links to other templates.
108      *
109      * @param data the turbine rundata object
110      */
111     public void addDefaultObjects(RunData data)
112     {
113         HttpServletRequest req = data.getRequest();
114 
115         //
116         // This is a place where an Application Pull Tool is used
117         // in a regular Java Context. We have no Pull Service with the
118         // Jsp Paging stuff, but we can run our Application Tool by Hand:
119         //
120         ApplicationTool templateLink = new TemplateLink();
121         templateLink.init(data);
122 
123         req.setAttribute(LINK, templateLink);
124         req.setAttribute(RUNDATA, data);
125     }
126 
127     /***
128      * Returns the default buffer size of the JspService
129      *
130      * @return The default buffer size.
131      */
132     public int getDefaultBufferSize()
133     {
134         return bufferSize;
135     }
136 
137     /***
138      * executes the JSP given by templateName.
139      *
140      * @param data A RunData Object
141      * @param templateName the filename of the template.
142      * @throws TurbineException Any exception thrown while processing will be
143      *         wrapped into a TurbineException and rethrown.
144      */
145     public void handleRequest(RunData data, String templateName)
146         throws TurbineException
147     {
148         handleRequest(data, templateName, false);
149     }
150 
151     /***
152      * executes the JSP given by templateName.
153      *
154      * @param data A RunData Object
155      * @param templateName the filename of the template.
156      * @param isForward whether to perform a forward or include.
157      * @throws TurbineException Any exception trown while processing will be
158      *         wrapped into a TurbineException and rethrown.
159      */
160     public void handleRequest(RunData data, String templateName, boolean isForward)
161         throws TurbineException
162     {
163         /*** template name with relative path */
164         String relativeTemplateName = getRelativeTemplateName(templateName);
165 
166         if (StringUtils.isEmpty(relativeTemplateName))
167         {
168             throw new TurbineException(
169                 "Template " + templateName + " not found in template paths");
170         }
171 
172         // get the RequestDispatcher for the JSP
173         RequestDispatcher dispatcher = data.getServletContext()
174             .getRequestDispatcher(relativeTemplateName);
175 
176         try
177         {
178             if (isForward)
179             {
180                 // forward the request to the JSP
181                 dispatcher.forward(data.getRequest(), data.getResponse());
182             }
183             else
184             {
185                 data.getOut().flush();
186                 // include the JSP
187                 dispatcher.include(data.getRequest(), data.getResponse());
188             }
189         }
190         catch (Exception e)
191         {
192             // as JSP service is in Alpha stage, let's try hard to send the
193             // error message to the browser, to speed up debugging
194             try
195             {
196                 data.getOut().print("Error encountered processing a template: "
197                     + templateName);
198                 e.printStackTrace(data.getOut());
199             }
200             catch (IOException ignored)
201             {
202             }
203 
204             // pass the exception to the caller according to the general
205             // contract for tamplating services in Turbine
206             throw new TurbineException(
207                 "Error encountered processing a template: " + templateName, e);
208         }
209     }
210 
211     /***
212      * This method sets up the template cache.
213      */
214     private void initJsp()
215         throws Exception
216     {
217         Configuration config = getConfiguration();
218 
219         // Set relative paths from config.
220         // Needed for javax.servlet.RequestDispatcher
221         relativeTemplatePaths = config.getStringArray(TEMPLATE_PATH_KEY);
222 
223         // Use Turbine Servlet to translate the template paths.
224         templatePaths = new String [relativeTemplatePaths.length];
225         for (int i=0; i < relativeTemplatePaths.length; i++)
226         {
227             relativeTemplatePaths[i] = warnAbsolute(relativeTemplatePaths[i]);
228 
229             templatePaths[i] = Turbine.getRealPath(relativeTemplatePaths[i]);
230         }
231 
232         bufferSize = config.getInt(JspService.BUFFER_SIZE_KEY,
233             JspService.BUFFER_SIZE_DEFAULT);
234     }
235 
236     /***
237      * Determine whether a given template is available on the
238      * configured template pathes.
239      *
240      * @param template The name of the requested Template
241      * @return True if the template is available.
242      */
243     public boolean templateExists(String template)
244     {
245         for (int i = 0; i < templatePaths.length; i++)
246         {
247             if (templateExists(templatePaths[i], template))
248             {
249                 return true;
250             }
251         }
252         return false;
253     }
254 
255     /***
256      * Determine whether a given template exists on the supplied
257      * template path. This service ATM only supports file based
258      * templates so it simply checks for file existence.
259      *
260      * @param path The absolute (file system) template path
261      * @param template The name of the requested Template
262      * @return True if the template is available.
263      */
264     private boolean templateExists(String path, String template)
265     {
266         return new File(path, template).exists();
267     }
268 
269     /***
270      * Searchs for a template in the default.template path[s] and
271      * returns the template name with a relative path which is
272      * required by <a href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletContext.html#getRequestDispatcher(java.lang.String)">
273      * javax.servlet.RequestDispatcher</a>
274      *
275      * @param template
276      * @return String
277      */
278     public String getRelativeTemplateName(String template)
279     {
280         template = warnAbsolute(template);
281 
282         // Find which template path the template is in
283         // We have a 1:1 match between relative and absolute
284         // pathes so we can use the index for translation.
285         for (int i = 0; i < templatePaths.length; i++)
286         {
287             if (templateExists(templatePaths[i], template))
288             {
289                 return relativeTemplatePaths[i] + "/" + template;
290             }
291         }
292         return null;
293     }
294 
295     /***
296      * Warn if a template name or path starts with "/".
297      *
298      * @param template The template to test
299      * @return The template name with a leading / stripped off
300      */
301     private String warnAbsolute(String template)
302     {
303         if (template.startsWith("/"))
304         {
305             log.warn("Template " + template
306                 + " has a leading /, which is wrong!");
307             return template.substring(1);
308         }
309         return template;
310     }
311 }