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.http.HttpServletRequest;
29  
30  import org.apache.commons.configuration2.Configuration;
31  import org.apache.commons.lang3.StringUtils;
32  import org.apache.logging.log4j.LogManager;
33  import org.apache.logging.log4j.Logger;
34  import org.apache.turbine.Turbine;
35  import org.apache.turbine.pipeline.PipelineData;
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 Logger log = LogManager.getLogger(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       * Adds some convenience objects to the request.  For example an instance
95       * of TemplateLink which can be used to generate links to other templates.
96       *
97       * @param pipelineData the Turbine PipelineData object
98       */
99      @Override
100     public void addDefaultObjects(PipelineData pipelineData)
101     {
102         HttpServletRequest req = pipelineData.get(Turbine.class, HttpServletRequest.class);
103 
104         //
105         // This is a place where an Application Pull Tool is used
106         // in a regular Java Context. We have no Pull Service with the
107         // Jsp Paging stuff, but we can run our Application Tool by Hand:
108         //
109         ApplicationTool templateLink = new TemplateLink();
110         templateLink.init(pipelineData);
111 
112         req.setAttribute(LINK, templateLink);
113         req.setAttribute(PIPELINE_DATA, pipelineData);
114     }
115 
116     /**
117      * Returns the default buffer size of the JspService
118      *
119      * @return The default buffer size.
120      */
121     @Override
122     public int getDefaultBufferSize()
123     {
124         return bufferSize;
125     }
126 
127     /**
128      * executes the JSP given by templateName.
129      *
130      * @param pipelineData A PipelineData Object
131      * @param templateName The template to execute
132      * @param isForward whether to perform a forward or include.
133      *
134      * @throws TurbineException If a problem occurred while executing the JSP
135      */
136     @Override
137     public void handleRequest(PipelineData pipelineData, String templateName, boolean isForward)
138         throws TurbineException
139     {
140         if(!(pipelineData instanceof RunData))
141         {
142             throw new RuntimeException("Can't cast to rundata from pipeline data.");
143         }
144 
145         RunData"../../../../../org/apache/turbine/util/RunData.html#RunData">RunData data = (RunData)pipelineData;
146 
147         /** template name with relative path */
148         String relativeTemplateName = getRelativeTemplateName(templateName);
149 
150         if (StringUtils.isEmpty(relativeTemplateName))
151         {
152             throw new TurbineException(
153                 "Template " + templateName + " not found in template paths");
154         }
155 
156         // get the RequestDispatcher for the JSP
157         RequestDispatcher dispatcher = data.getServletContext()
158             .getRequestDispatcher(relativeTemplateName);
159 
160         try
161         {
162             if (isForward)
163             {
164                 // forward the request to the JSP
165                 dispatcher.forward(data.getRequest(), data.getResponse());
166             }
167             else
168             {
169                 data.getResponse().getWriter().flush();
170                 // include the JSP
171                 dispatcher.include(data.getRequest(), data.getResponse());
172             }
173         }
174         catch (Exception e)
175         {
176             // Let's try hard to send the error message to the browser, to speed up debugging
177             try
178             {
179                 data.getResponse().getWriter().print("Error encountered processing a template: "
180                     + templateName);
181                 e.printStackTrace(data.getResponse().getWriter());
182             }
183             catch (IOException ignored)
184             {
185                 // ignore
186             }
187 
188             // pass the exception to the caller according to the general
189             // contract for templating services in Turbine
190             throw new TurbineException(
191                 "Error encountered processing a template: " + templateName, e);
192         }
193     }
194 
195     /**
196      * executes the JSP given by templateName.
197      *
198      * @param pipelineData A PipelineData Object
199      * @param templateName The template to execute
200      *
201      * @throws TurbineException If a problem occurred while executing the JSP
202      */
203     @Override
204     public void handleRequest(PipelineData pipelineData, String templateName)
205         throws TurbineException
206     {
207         handleRequest(pipelineData, templateName, false);
208     }
209 
210     /**
211      * This method sets up the template cache.
212      */
213     private void initJsp()
214         throws Exception
215     {
216         Configuration config = getConfiguration();
217 
218         // Set relative paths from config.
219         // Needed for javax.servlet.RequestDispatcher
220         relativeTemplatePaths = config.getStringArray(TEMPLATE_PATH_KEY);
221 
222         // Use Turbine Servlet to translate the template paths.
223         templatePaths = new String [relativeTemplatePaths.length];
224         for (int i=0; i < relativeTemplatePaths.length; i++)
225         {
226             relativeTemplatePaths[i] = warnAbsolute(relativeTemplatePaths[i]);
227 
228             templatePaths[i] = Turbine.getRealPath(relativeTemplatePaths[i]);
229         }
230 
231         bufferSize = config.getInt(JspService.BUFFER_SIZE_KEY,
232             JspService.BUFFER_SIZE_DEFAULT);
233     }
234 
235     /**
236      * Determine whether a given template is available on the
237      * configured template pathes.
238      *
239      * @param template The name of the requested Template
240      * @return True if the template is available.
241      */
242     @Override
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      * Searches 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 the name of the template
276      * @return String
277      */
278     @Override
279     public String getRelativeTemplateName(String template)
280     {
281         String relativeTemplate = 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], relativeTemplate))
289             {
290                 return relativeTemplatePaths[i] + "/" + relativeTemplate;
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 {} has a leading /, which is wrong!", template);
307             return template.substring(1);
308         }
309         return template;
310     }
311 }