    001    package org.apache.turbine.modules.pages;
    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.util.List;
    025
    026    import org.apache.commons.lang.StringUtils;
    027    import org.apache.commons.logging.Log;
    028    import org.apache.commons.logging.LogFactory;
    029    import org.apache.ecs.Doctype;
    030    import org.apache.turbine.Turbine;
    031    import org.apache.turbine.TurbineConstants;
    032    import org.apache.turbine.modules.Action;
    033    import org.apache.turbine.modules.ActionLoader;
    034    import org.apache.turbine.modules.Layout;
    035    import org.apache.turbine.modules.LayoutLoader;
    036    import org.apache.turbine.modules.Page;
    037    import org.apache.turbine.modules.Screen;
    038    import org.apache.turbine.modules.ScreenLoader;
    039    import org.apache.turbine.pipeline.PipelineData;
    040    import org.apache.turbine.services.assemblerbroker.TurbineAssemblerBroker;
    041    import org.apache.turbine.util.RunData;
    042    import org.apache.turbine.util.TurbineException;
    043
    044    /**
    045     * When building sites using templates, Screens need only be defined
    046     * for templates which require dynamic (database or object) data.
    047     *
    048     * <p>
    049     *
    050     * This page can be used on sites where the number of Screens can be
    051     * much less than the number of templates.  The templates can be
    052     * grouped in directories with common layouts.  Screen modules are
    053     * then expected to be placed in packages corresponding with the
    054     * templates' directories and follow a specific naming scheme.
    055     *
    056     * <p>
    057     *
    058     * The template parameter is parsed and and a Screen whose package
    059     * matches the templates path and shares the same name minus any
    060     * extension and beginning with a capital letter is searched for.  If
    061     * not found, a Screen in a package matching the template's path with
    062     * name Default is searched for.  If still not found, a Screen with
    063     * name Default is looked for in packages corresponding to parent
    064     * directories in the template's path until a match is found.
    065     *
    066     * <p>
    067     *
    068     * For example if data.getParameters().getString("template") returns
    069     * /about_us/directions/driving.wm, the search follows
    070     * about_us.directions.Driving, about_us.directions.Default,
    071     * about_us.Default, Default, VelocitySiteScreen.
    072     *
    073     * <p>
    074     *
    075     * Only one Layout module is used, since it is expected that any
    076     * dynamic content will be placed in navigations and screens.  The
    077     * layout template to be used is found in a similar way to the Screen.
    078     * For example the following paths will be searched in the layouts
    079     * subdirectory: /about_us/directions/driving.wm,
    080     * /about_us/directions/default.wm, /about_us/default.wm, /default.wm.
    081     *
    082     * <p>
    083     *
    084     * This approach allows a site with largely static content to be
    085     * updated and added to regularly by those with little Java
    086     * experience.
    087     *
    088     * <p>
    089     *
    090     * The code is an almost a complete clone of the FreeMarkerSitePage
    091     * written by John McNally.  I've only modified it for Template use.
    092     *
    093     * @author <a href="mailto:mbryson@mont.mindspring.com">Dave Bryson</a>
    094     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    095     * @author <a href="mailto:peter@courcoux.biz">Peter Courcoux</a>
    096     * @version $Id: DefaultPage.java 1078552 2011-03-06 19:58:46Z tv $
    097     */
    098    public class DefaultPage
    099        extends Page
    100    {
    101        /** Logging */
    102        protected Log log = LogFactory.getLog(this.getClass());
    103
    104        protected ActionLoader actionLoader;
    105        protected ScreenLoader screenLoader;
    106        protected LayoutLoader layoutLoader;
    107
    108        /**
    109         * Default constructor
    110         */
    111        public DefaultPage()
    112        {
    113            super();
    114
    115            this.actionLoader = (ActionLoader)TurbineAssemblerBroker.getLoader(Action.NAME);
    116            this.screenLoader = (ScreenLoader)TurbineAssemblerBroker.getLoader(Screen.NAME);
    117            this.layoutLoader = (LayoutLoader)TurbineAssemblerBroker.getLoader(Layout.NAME);
    118        }
    119
    120        /**
    121         * Builds the Page.
    122         *
    123         * @deprecated Use PipelineData version instead
    124         * @param data Turbine information.
    125         * @exception Exception, a generic exception.
    126         */
    127        @Deprecated
    128        @Override
    129        public void doBuild(RunData data)
    130                throws Exception
    131        {
    132            // Template pages can use this to set up the context, so it is
    133            // available to the Action and Screen.  It does nothing here.
    134            doBuildBeforeAction(data);
    135
    136            // If an action has been defined, execute it here.  Actions
    137            // can re-define the template definition.
    138            if (data.hasAction())
    139            {
    140                actionLoader.exec(data, data.getAction());
    141            }
    142
    143            // if a redirect was setup in data, don't do anything else
    144            if (StringUtils.isNotEmpty(data.getRedirectURI()))
    145            {
    146                return;
    147            }
    148
    149            // Set the default doctype from the value given in
    150            // TurbineResources.properties.
    151            setDefaultDoctype(data);
    152
    153            // Template pages can use this to set up default templates and
    154            // associated class modules.  It does nothing here.
    155            doBuildAfterAction(data);
    156
    157            String screenName = data.getScreen();
    158
    159            log.debug("Building " + screenName);
    160
    161            // Ask the Screen for its Layout and then execute the Layout.
    162            // The Screen can override the getLayout() method to re-define
    163            // the Layout depending on data passed in via the
    164            // data.parameters object.
    165            Screen aScreen = screenLoader.getAssembler(screenName);
    166            String layout = aScreen.getLayout(data);
    167
    168            // If the Layout has been set to be null, attempt to execute
    169            // the Screen that has been defined.
    170            if (layout != null)
    171            {
    172                layoutLoader.exec(data, layout);
    173            }
    174            else
    175            {
    176                screenLoader.exec(data, screenName);
    177            }
    178
    179            // Do any post build actions (overridable by subclasses -
    180            // does nothing here).
    181            doPostBuild(data);
    182        }
    183
    184        /**
    185         * Builds the Page.
    186         *
    187         * @param data Turbine information.
    188         * @exception Exception, a generic exception.
    189         */
    190        @Override
    191        public void doBuild(PipelineData pipelineData)
    192                throws Exception
    193        {
    194            RunData data = getRunData(pipelineData);
    195            // Template pages can use this to set up the context, so it is
    196            // available to the Action and Screen.  It does nothing here.
    197            doBuildBeforeAction(pipelineData);
    198
    199            // If an action has been defined, execute it here.  Actions
    200            // can re-define the template definition.
    201            if (data.hasAction())
    202            {
    203                actionLoader.exec(pipelineData, data.getAction());
    204            }
    205
    206            // if a redirect was setup in data, don't do anything else
    207            if (StringUtils.isNotEmpty(data.getRedirectURI()))
    208            {
    209                return;
    210            }
    211
    212            // Set the default doctype from the value given in
    213            // TurbineResources.properties.
    214            setDefaultDoctype(data);
    215
    216            // Template pages can use this to set up default templates and
    217            // associated class modules.  It does nothing here.
    218            doBuildAfterAction(pipelineData);
    219
    220            String screenName = data.getScreen();
    221
    222            log.debug("Building " + screenName);
    223
    224            // Ask the Screen for its Layout and then execute the Layout.
    225            // The Screen can override the getLayout() method to re-define
    226            // the Layout depending on data passed in via the
    227            // data.parameters object.
    228            Screen aScreen = screenLoader.getAssembler(screenName);
    229            String layout = aScreen.getLayout(pipelineData);
    230
    231            // If the Layout has been set to be null, attempt to execute
    232            // the Screen that has been defined.
    233            if (layout != null)
    234            {
    235                layoutLoader.exec(pipelineData, layout);
    236            }
    237            else
    238            {
    239                screenLoader.exec(pipelineData, screenName);
    240            }
    241
    242            // Do any post build actions (overridable by subclasses -
    243            // does nothing here).
    244            doPostBuild(pipelineData);
    245        }
    246
    247
    248
    249        /**
    250         * Can be used by template Pages to stuff the Context into the
    251         * RunData so that it is available to the Action module and the
    252         * Screen module via getContext().  It does nothing here.
    253         *
    254         * @deprecated Use PipelineData version instead
    255         * @param data Turbine information.
    256         * @exception Exception, a generic exception.
    257         */
    258        @Deprecated
    259        protected void doBuildBeforeAction(RunData data)
    260                throws Exception
    261        {
    262            // do nothing by default
    263        }
    264
    265        /**
    266         * Can be overridden by template Pages to set up data needed to
    267         * process a template.  It does nothing here.
    268         *
    269         * @deprecated Use PipelineData version instead
    270         * @param data Turbine information.
    271         * @exception Exception, a generic exception.
    272         */
    273        @Deprecated
    274        protected void doBuildAfterAction(RunData data)
    275                throws Exception
    276        {
    277            // do nothing by default
    278        }
    279
    280        /**
    281         * Can be overridden to perform actions when the request is
    282         * fully processed. It does nothing here.
    283         * @deprecated Use PipelineData version instead
    284         * @param data Turbine information.
    285         * @exception Exception, a generic exception.
    286         */
    287        @Deprecated
    288        protected void doPostBuild(RunData data)
    289                throws Exception
    290        {
    291            // do nothing by default
    292        }
    293
    294
    295        /**
    296         * Can be used by template Pages to stuff the Context into the
    297         * RunData so that it is available to the Action module and the
    298         * Screen module via getContext().  It does nothing here.
    299         *
    300         * @param data Turbine information.
    301         * @exception Exception, a generic exception.
    302         */
    303        protected void doBuildBeforeAction(PipelineData pipelineData)
    304                throws Exception
    305        {
    306            // do nothing by default
    307        }
    308
    309        /**
    310         * Can be overridden by template Pages to set up data needed to
    311         * process a template.  It does nothing here.
    312         *
    313         * @param data Turbine information.
    314         * @exception Exception, a generic exception.
    315         */
    316        protected void doBuildAfterAction(PipelineData pipelineData)
    317                throws Exception
    318        {
    319            // do nothing by default
    320        }
    321
    322        /**
    323         * Can be overridden to perform actions when the request is
    324         * fully processed. It does nothing here.
    325         *
    326         * @param data Turbine information.
    327         * @exception Exception, a generic exception.
    328         */
    329        protected void doPostBuild(PipelineData pipelineData)
    330                throws Exception
    331        {
    332            // do nothing by default
    333        }
    334
    335        /**
    336         * Set the default Doctype.  If Doctype is set to null, it will
    337         * not be added.  The default Doctype can be set in
    338         * TurbineResources by using the single strings: Html40Strict,
    339         * Html40Transitional, or Html40Frameset.  Additionally the
    340         * default can be supplied as two strings giving the dtd and uri.
    341         *
    342         * @param data Turbine information.
    343         * @exception Exception, a generic exception.
    344         */
    345        private void setDefaultDoctype(RunData data)
    346                throws Exception
    347        {
    348            String errMsg =
    349                    "default.doctype property not set properly in TurbineResources.properties!";
    350            List doctypeProperty =
    351                Turbine.getConfiguration().getList(TurbineConstants.DEFAULT_DOCUMENT_TYPE_KEY);
    352
    353            if (doctypeProperty != null)
    354            {
    355                switch(doctypeProperty.size())
    356                {
    357                case 0:
    358                    {
    359                        // Don't add a doctype.
    360                        break;
    361                    }
    362                case 1:
    363                    {
    364                        String doc = (String) doctypeProperty.get(0);
    365                        if (doc.equalsIgnoreCase(TurbineConstants.DOCUMENT_TYPE_HTML40TRANSITIONAL))
    366                        {
    367                            data.getPage().setDoctype(new Doctype.Html40Transitional());
    368                        }
    369                        else if (doc.equalsIgnoreCase(TurbineConstants.DOCUMENT_TYPE_HTML40STRICT))
    370                        {
    371                            data.getPage().setDoctype(new Doctype.Html40Strict());
    372                        }
    373                        else if (doc.equalsIgnoreCase(TurbineConstants.DOCUMENT_TYPE_HTML40FRAMESET))
    374                        {
    375                            data.getPage().setDoctype(new Doctype.Html40Frameset());
    376                        }
    377                        else
    378                        {
    379                            throw new TurbineException(errMsg);
    380                        }
    381                        break;
    382                    }
    383                case 2:
    384                    {
    385                        data.getPage()
    386                            .setDoctype(new Doctype()
    387                                        .setIdentifier((String) doctypeProperty.get(0))
    388                                        .setUri((String) doctypeProperty.get(1)));
    389                        break;
    390                    }
    391                default:
    392                    {
    393                        throw new TurbineException(errMsg);
    394                    }
    395                }
    396            }
    397        }
    398    }