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.configuration.Configuration;
    31  import org.apache.commons.lang.StringUtils;
    32  import org.apache.commons.logging.Log;
    33  import org.apache.commons.logging.LogFactory;
    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 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       * 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 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
    276      * @return String
    277      */
    278     @Override
    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 }