View Javadoc

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