    001    package org.apache.turbine.services.jsp;
    002
    003
    004    /*
    005     * Licensed to the Apache Software Foundation (ASF) under one
    006     * or more contributor license agreements.  See the NOTICE file
    007     * distributed with this work for additional information
    008     * regarding copyright ownership.  The ASF licenses this file
    009     * to you under the Apache License, Version 2.0 (the
    010     * "License"); you may not use this file except in compliance
    011     * with the License.  You may obtain a copy of the License at
    012     *
    013     *   http://www.apache.org/licenses/LICENSE-2.0
    014     *
    015     * Unless required by applicable law or agreed to in writing,
    016     * software distributed under the License is distributed on an
    017     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    018     * KIND, either express or implied.  See the License for the
    019     * specific language governing permissions and limitations
    020     * under the License.
    021     */
    022
    023
    024    import java.io.File;
    025    import java.io.IOException;
    026
    027    import javax.servlet.RequestDispatcher;
    028    import javax.servlet.ServletConfig;
    029    import javax.servlet.http.HttpServletRequest;
    030
    031    import org.apache.commons.configuration.Configuration;
    032    import org.apache.commons.lang.StringUtils;
    033    import org.apache.commons.logging.Log;
    034    import org.apache.commons.logging.LogFactory;
    035    import org.apache.turbine.Turbine;
    036    import org.apache.turbine.services.InitializationException;
    037    import org.apache.turbine.services.pull.ApplicationTool;
    038    import org.apache.turbine.services.pull.tools.TemplateLink;
    039    import org.apache.turbine.services.template.BaseTemplateEngineService;
    040    import org.apache.turbine.util.RunData;
    041    import org.apache.turbine.util.TurbineException;
    042
    043    /**
    044     * This is a Service that can process JSP templates from within a Turbine
    045     * screen.
    046     *
    047     * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
    048     * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
    049     * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
    050     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    051     */
    052    public class TurbineJspService
    053            extends BaseTemplateEngineService
    054            implements JspService
    055    {
    056        /** The base path[s] prepended to filenames given in arguments */
    057        private String[] templatePaths;
    058
    059        /** The relative path[s] prepended to filenames */
    060        private String[] relativeTemplatePaths;
    061
    062        /** The buffer size for the output stream. */
    063        private int bufferSize;
    064
    065        /** Logging */
    066        private static Log log = LogFactory.getLog(TurbineJspService.class);
    067
    068        /**
    069         * Load all configured components and initialize them. This is
    070         * a zero parameter variant which queries the Turbine Servlet
    071         * for its config.
    072         *
    073         * @throws InitializationException Something went wrong in the init
    074         *         stage
    075         */
    076        @Override
    077        public void init()
    078            throws InitializationException
    079        {
    080            try
    081            {
    082                initJsp();
    083                registerConfiguration(JspService.JSP_EXTENSION);
    084                setInit(true);
    085            }
    086            catch (Exception e)
    087            {
    088                throw new InitializationException(
    089                    "TurbineJspService failed to initialize", e);
    090            }
    091        }
    092
    093        /**
    094         * Performs early initialization of this Turbine service.
    095         *
    096         * @param config The ServletConfiguration from Turbine
    097         *
    098         * @throws InitializationException Something went wrong when starting up.
    099         * @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    }