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    }