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.ServletConfig;
    29  import javax.servlet.http.HttpServletRequest;
    30
    31  import org.apache.commons.configuration.Configuration;
    32  import org.apache.commons.lang.StringUtils;
    33  import org.apache.commons.logging.Log;
    34  import org.apache.commons.logging.LogFactory;
    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      @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       * Performs early initialization of this Turbine service.
    95       *
    96       * @param config The ServletConfiguration from Turbine
    97       *
    98       * @throws InitializationException Something went wrong when starting up.
    99       * @deprecated use init() instead.
    100      */
    101     @Deprecated
    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.getResponse().getWriter().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.getResponse().getWriter().print("Error encountered processing a template: "
    200                     + templateName);
    201                 e.printStackTrace(data.getResponse().getWriter());
    202             }
    203             catch (IOException ignored)
    204             {
    205                 // ignore
    206             }
    207
    208             // pass the exception to the caller according to the general
    209             // contract for tamplating services in Turbine
    210             throw new TurbineException(
    211                 "Error encountered processing a template: " + templateName, e);
    212         }
    213     }
    214
    215     /**
    216      * This method sets up the template cache.
    217      */
    218     private void initJsp()
    219         throws Exception
    220     {
    221         Configuration config = getConfiguration();
    222
    223         // Set relative paths from config.
    224         // Needed for javax.servlet.RequestDispatcher
    225         relativeTemplatePaths = config.getStringArray(TEMPLATE_PATH_KEY);
    226
    227         // Use Turbine Servlet to translate the template paths.
    228         templatePaths = new String [relativeTemplatePaths.length];
    229         for (int i=0; i < relativeTemplatePaths.length; i++)
    230         {
    231             relativeTemplatePaths[i] = warnAbsolute(relativeTemplatePaths[i]);
    232
    233             templatePaths[i] = Turbine.getRealPath(relativeTemplatePaths[i]);
    234         }
    235
    236         bufferSize = config.getInt(JspService.BUFFER_SIZE_KEY,
    237             JspService.BUFFER_SIZE_DEFAULT);
    238     }
    239
    240     /**
    241      * Determine whether a given template is available on the
    242      * configured template pathes.
    243      *
    244      * @param template The name of the requested Template
    245      * @return True if the template is available.
    246      */
    247     @Override
    248     public boolean templateExists(String template)
    249     {
    250         for (int i = 0; i < templatePaths.length; i++)
    251         {
    252             if (templateExists(templatePaths[i], template))
    253             {
    254                 return true;
    255             }
    256         }
    257         return false;
    258     }
    259
    260     /**
    261      * Determine whether a given template exists on the supplied
    262      * template path. This service ATM only supports file based
    263      * templates so it simply checks for file existence.
    264      *
    265      * @param path The absolute (file system) template path
    266      * @param template The name of the requested Template
    267      * @return True if the template is available.
    268      */
    269     private boolean templateExists(String path, String template)
    270     {
    271         return new File(path, template).exists();
    272     }
    273
    274     /**
    275      * Searchs for a template in the default.template path[s] and
    276      * returns the template name with a relative path which is
    277      * required by <a href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletContext.html#getRequestDispatcher(java.lang.String)">
    278      * javax.servlet.RequestDispatcher</a>
    279      *
    280      * @param template
    281      * @return String
    282      */
    283     public String getRelativeTemplateName(String template)
    284     {
    285         template = warnAbsolute(template);
    286
    287         // Find which template path the template is in
    288         // We have a 1:1 match between relative and absolute
    289         // pathes so we can use the index for translation.
    290         for (int i = 0; i < templatePaths.length; i++)
    291         {
    292             if (templateExists(templatePaths[i], template))
    293             {
    294                 return relativeTemplatePaths[i] + "/" + template;
    295             }
    296         }
    297         return null;
    298     }
    299
    300     /**
    301      * Warn if a template name or path starts with "/".
    302      *
    303      * @param template The template to test
    304      * @return The template name with a leading / stripped off
    305      */
    306     private String warnAbsolute(String template)
    307     {
    308         if (template.startsWith("/"))
    309         {
    310             log.warn("Template " + template
    311                 + " has a leading /, which is wrong!");
    312             return template.substring(1);
    313         }
    314         return template;
    315     }
    316 }