001package org.apache.turbine.services.template;
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
024import java.io.File;
025import java.util.Collections;
026import java.util.HashMap;
027import java.util.Map;
028
029import org.apache.commons.configuration.Configuration;
030import org.apache.commons.lang.StringUtils;
031import org.apache.commons.logging.Log;
032import org.apache.commons.logging.LogFactory;
033import org.apache.fulcrum.factory.FactoryException;
034import org.apache.fulcrum.factory.FactoryService;
035import org.apache.fulcrum.parser.ParameterParser;
036import org.apache.turbine.Turbine;
037import org.apache.turbine.TurbineConstants;
038import org.apache.turbine.modules.Assembler;
039import org.apache.turbine.modules.Layout;
040import org.apache.turbine.modules.Loader;
041import org.apache.turbine.modules.Navigation;
042import org.apache.turbine.modules.Page;
043import org.apache.turbine.modules.Screen;
044import org.apache.turbine.pipeline.PipelineData;
045import org.apache.turbine.services.InitializationException;
046import org.apache.turbine.services.TurbineBaseService;
047import org.apache.turbine.services.TurbineServices;
048import org.apache.turbine.services.assemblerbroker.AssemblerBrokerService;
049import org.apache.turbine.services.servlet.TurbineServlet;
050import org.apache.turbine.services.template.mapper.BaseTemplateMapper;
051import org.apache.turbine.services.template.mapper.ClassMapper;
052import org.apache.turbine.services.template.mapper.DirectMapper;
053import org.apache.turbine.services.template.mapper.DirectTemplateMapper;
054import org.apache.turbine.services.template.mapper.LayoutTemplateMapper;
055import org.apache.turbine.services.template.mapper.Mapper;
056import org.apache.turbine.services.template.mapper.ScreenTemplateMapper;
057import org.apache.turbine.util.uri.URIConstants;
058
059/**
060 * This service provides a method for mapping templates to their
061 * appropriate Screens or Navigations.  It also allows templates to
062 * define a layout/navigations/screen modularization within the
063 * template structure.  It also performs caching if turned on in the
064 * properties file.
065 *
066 * This service is not bound to a specific templating engine but we
067 * will use the Velocity templating engine for the examples. It is
068 * available by using the VelocityService.
069 *
070 * This assumes the following properties in the Turbine configuration:
071 *
072 * <pre>
073 * # Register the VelocityService for the "vm" extension.
074 * services.VelocityService.template.extension=vm
075 *
076 * # Default Java class for rendering a Page in this service
077 * # (must be found on the class path (org.apache.turbine.modules.page.VelocityPage))
078 * services.VelocityService.default.page = VelocityPage
079 *
080 * # Default Java class for rendering a Screen in this service
081 * # (must be found on the class path (org.apache.turbine.modules.screen.VelocityScreen))
082 * services.VelocityService.default.screen=VelocityScreen
083 *
084 * # Default Java class for rendering a Layout in this service
085 * # (must be found on the class path (org.apache.turbine.modules.layout.VelocityOnlyLayout))
086 * services.VelocityService.default.layout = VelocityOnlyLayout
087 *
088 * # Default Java class for rendering a Navigation in this service
089 * # (must be found on the class path (org.apache.turbine.modules.navigation.VelocityNavigation))
090 * services.VelocityService.default.navigation=VelocityNavigation
091 *
092 * # Default Template Name to be used as Layout. If nothing else is
093 * # found, return this as the default name for a layout
094 * services.VelocityService.default.layout.template = Default.vm
095 * </pre>
096 * If you want to render a template, a search path is used to find
097 * a Java class which might provide information for the context of
098 * this template.
099 *
100 * If you request e.g. the template screen
101 *
102 * about,directions,Driving.vm
103 *
104 * then the following class names are searched (on the module search
105 * path):
106 *
107 * 1. about.directions.Driving     &lt;- direct matching the template to the class name
108 * 2. about.directions.Default     &lt;- matching the package, class name is Default
109 * 3. about.Default                &lt;- stepping up in the package hierarchy, looking for Default
110 * 4. Default                      &lt;- Class called "Default" without package
111 * 5. VelocityScreen               &lt;- The class configured by the Service (VelocityService) to
112 *
113 * And if you have the following module packages configured:
114 *
115 * module.packages = org.apache.turbine.modules, com.mycorp.modules
116 *
117 * then the class loader will look for
118 *
119 * org.apache.turbine.modules.screens.about.directions.Driving
120 * com.mycorp.modules.screens.about.directions.Driving
121 * org.apache.turbine.modules.screens.about.directions.Default
122 * com.mycorp.modules.screens.about.directions.Default
123 * org.apache.turbine.modules.screens.about.Default
124 * com.mycorp.modules.screens.about.Default
125 * org.apache.turbine.modules.screens.Default
126 * com.mycorp.modules.screens.Default
127 * org.apache.turbine.modules.screens.VelocityScreen
128 * com.mycorp.modules.screens.VelocityScreen
129 *
130 * Most of the times, you don't have any backing Java class for a
131 * template screen, so the first match will be
132 * org.apache.turbine.modules.screens.VelocityScreen
133 * which then renders your screen.
134 *
135 * Please note, that your Screen Template (Driving.vm) must exist!
136 * If it does not exist, the Template Service will report an error.
137 *
138 * Once the screen is found, the template service will look for
139 * the Layout and Navigation templates of your Screen. Here, the
140 * template service looks for matching template names!
141 *
142 * Consider our example:  about,directions,Driving.vm (Screen Name)
143 *
144 * Now the template service will look for the following Navigation
145 * and Layout templates:
146 *
147 * 1. about,directions,Driving.vm      &lt;- exact match
148 * 2. about,directions,Default.vm      &lt;- package match, Default name
149 * 3. about,Default.vm                 &lt;- stepping up in the hierarchy
150 * 4. Default.vm                       &lt;- The name configured as default.layout.template
151 *                                        in the Velocity service.
152 *
153 * And now Hennings' two golden rules for using templates:
154 *
155 * Many examples and docs from older Turbine code show template pathes
156 * with a slashes. Repeat after me: "TEMPLATE NAMES NEVER CONTAIN SLASHES!"
157 *
158 * Many examples and docs from older Turbine code show templates that start
159 * with "/". This is not only a violation of the rule above but actively breaks
160 * things like loading templates from a jar with the velocity jar loader. Repeat
161 * after me: "TEMPLATE NAMES ARE NOT PATHES. THEY'RE NOT ABSOLUTE AND HAVE NO
162 * LEADING /".
163 *
164 * If you now wonder how a template name is mapped to a file name: This is
165 * scope of the templating engine. Velocity e.g. has this wonderful option to
166 * load templates from jar archives. There is no single file but you tell
167 * velocity "get about,directions,Driving.vm" and it returns the rendered
168 * template. This is not the job of the Templating Service but of the Template
169 * rendering services like VelocityService.
170 *
171 * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
172 * @author <a href="mailto:mbryson@mont.mindspring.com">Dave Bryson</a>
173 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
174 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
175 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
176 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
177 * @version $Id: TurbineTemplateService.java 1709648 2015-10-20 17:08:10Z tv $
178 */
179public class TurbineTemplateService
180    extends TurbineBaseService
181    implements TemplateService
182{
183    /** Logging */
184    private static Log log = LogFactory.getLog(TurbineTemplateService.class);
185
186    /** Represents Page Objects */
187    public static final int PAGE_KEY = 0;
188
189    /** Represents Screen Objects */
190    public static final int SCREEN_KEY = 1;
191
192    /** Represents Layout Objects */
193    public static final int LAYOUT_KEY = 2;
194
195    /** Represents Navigation Objects */
196    public static final int NAVIGATION_KEY = 3;
197
198    /** Represents Layout Template Objects */
199    public static final int LAYOUT_TEMPLATE_KEY = 4;
200
201    /** Represents Layout Template Objects */
202    public static final String LAYOUT_TEMPLATE_NAME = "layout.template";
203
204    /** Represents Screen Template Objects */
205    public static final int SCREEN_TEMPLATE_KEY = 5;
206
207    /** Represents Screen Template Objects */
208    public static final String SCREEN_TEMPLATE_NAME = "screen.template";
209
210    /** Represents Navigation Template Objects */
211    public static final int NAVIGATION_TEMPLATE_KEY = 6;
212
213    /** Represents Navigation Template Objects */
214    public static final String NAVIGATION_TEMPLATE_NAME = "navigation.template";
215
216    /** Number of different Template Types that we know of */
217    public static final int TEMPLATE_TYPES = 7;
218
219    /** Here we register the mapper objects for our various object types */
220    private Mapper [] mapperRegistry = null;
221
222    /**
223     * The default file extension used as a registry key when a
224     * template's file extension cannot be determined.
225     *
226     * @deprecated. Use TemplateService.DEFAULT_EXTENSION_VALUE.
227     */
228    protected static final String NO_FILE_EXT = TemplateService.DEFAULT_EXTENSION_VALUE;
229
230
231    /** Flag set if cache is to be used. */
232    private boolean useCache = false;
233
234    /** Default extension for templates. */
235    private String defaultExtension;
236
237    /** Default template without the default extension. */
238    private String defaultTemplate;
239
240    /**
241     * The mappings of template file extensions to {@link
242     * org.apache.turbine.services.template.TemplateEngineService}
243     * implementations. Implementing template engines can locate
244     * templates within the capability of any resource loaders they
245     * may possess, and other template engines are stuck with file
246     * based template hierarchy only.
247     */
248    private Map<String, TemplateEngineService> templateEngineRegistry = null;
249
250    /**
251     * C'tor
252     */
253    public TurbineTemplateService()
254    {
255        // empty
256    }
257
258    /**
259     * Called the first time the Service is used.
260     *
261     * @exception InitializationException Something went wrong when
262     *                                     setting up the Template Service.
263     */
264    @Override
265    public void init()
266        throws InitializationException
267    {
268        // Get the configuration for the template service.
269        Configuration config = getConfiguration();
270
271        // Get the default extension to use if nothing else is applicable.
272        defaultExtension = config.getString(TemplateService.DEFAULT_EXTENSION_KEY,
273            TemplateService.DEFAULT_EXTENSION_VALUE);
274
275        defaultTemplate =  config.getString(TemplateService.DEFAULT_TEMPLATE_KEY,
276            TemplateService.DEFAULT_TEMPLATE_VALUE);
277
278        // Check to see if we are going to be caching modules.
279        // Aaargh, who moved this _out_ of the TemplateService package?
280        useCache = Turbine.getConfiguration().getBoolean(TurbineConstants.MODULE_CACHE_KEY,
281            TurbineConstants.MODULE_CACHE_DEFAULT);
282
283        log.debug("Default Extension: " + defaultExtension);
284        log.debug("Default Template:  " + defaultTemplate);
285        log.debug("Use Caching:       " + useCache);
286
287        templateEngineRegistry = Collections.synchronizedMap(new HashMap<String, TemplateEngineService>());
288
289        initMapper(config);
290        setInit(true);
291    }
292
293    /**
294     * Returns true if the Template Service has caching activated
295     *
296     * @return true if Caching is active.
297     */
298    @Override
299    public boolean isCaching()
300    {
301        return useCache;
302    }
303
304    /**
305     * Get the default template name extension specified
306     * in the template service properties. If no extension
307     * is defined, return the empty string.
308     *
309     * @return The default extension.
310     */
311    @Override
312    public String getDefaultExtension()
313    {
314        return StringUtils.isNotEmpty(defaultExtension) ? defaultExtension : "";
315    }
316
317    /**
318     * Return Extension for a supplied template
319     *
320     * @param template The template name
321     *
322     * @return extension The extension for the supplied template
323     */
324    @Override
325    public String getExtension(String template)
326    {
327        if (StringUtils.isEmpty(template))
328        {
329            return getDefaultExtension();
330        }
331
332        int dotIndex = template.lastIndexOf(EXTENSION_SEPARATOR);
333
334        return (dotIndex < 0) ? getDefaultExtension() : template.substring(dotIndex + 1);
335    }
336
337
338    /**
339     * Returns the Default Template Name with the Default Extension.
340     * If the extension is unset, return only the template name
341     *
342     * @return The default template Name
343     */
344    @Override
345    public String getDefaultTemplate()
346    {
347        StringBuilder sb = new StringBuilder();
348        sb.append(defaultTemplate);
349        if (StringUtils.isNotEmpty(defaultExtension))
350        {
351            sb.append(EXTENSION_SEPARATOR);
352            sb.append(getDefaultExtension());
353        }
354        return sb.toString();
355    }
356
357    /**
358     * Get the default page module name of the template engine
359     * service corresponding to the default template name extension.
360     *
361     * @return The default page module name.
362     */
363    @Override
364    public String getDefaultPage()
365    {
366        return getDefaultPageName(getDefaultTemplate());
367    }
368
369    /**
370     * Get the default screen module name of the template engine
371     * service corresponding to the default template name extension.
372     *
373     * @return The default screen module name.
374     */
375    @Override
376    public String getDefaultScreen()
377    {
378        return getDefaultScreenName(getDefaultTemplate());
379    }
380
381    /**
382     * Get the default layout module name of the template engine
383     * service corresponding to the default template name extension.
384     *
385     * @return The default layout module name.
386     */
387    @Override
388    public String getDefaultLayout()
389    {
390        return getDefaultLayoutName(getDefaultTemplate());
391    }
392
393    /**
394     * Get the default navigation module name of the template engine
395     * service corresponding to the default template name extension.
396     *
397     * @return The default navigation module name.
398     */
399    @Override
400    public String getDefaultNavigation()
401    {
402        return getDefaultNavigationName(getDefaultTemplate());
403    }
404
405    /**
406     * Get the default layout template name of the template engine
407     * service corresponding to the default template name extension.
408     *
409     * @return The default layout template name.
410     */
411    @Override
412    public String getDefaultLayoutTemplate()
413    {
414        return getDefaultLayoutTemplateName(getDefaultTemplate());
415    }
416
417    /**
418     * Get the default page module name of the template engine
419     * service corresponding to the template name extension of
420     * the named template.
421     *
422     * @param template The template name.
423     * @return The default page module name.
424     */
425    @Override
426    public String getDefaultPageName(String template)
427    {
428        return (mapperRegistry[PAGE_KEY]).getDefaultName(template);
429    }
430
431    /**
432     * Get the default screen module name of the template engine
433     * service corresponding to the template name extension of
434     * the named template.
435     *
436     * @param template The template name.
437     * @return The default screen module name.
438     */
439    @Override
440    public String getDefaultScreenName(String template)
441    {
442        return (mapperRegistry[SCREEN_KEY]).getDefaultName(template);
443    }
444
445    /**
446     * Get the default layout module name of the template engine
447     * service corresponding to the template name extension of
448     * the named template.
449     *
450     * @param template The template name.
451     * @return The default layout module name.
452     */
453    @Override
454    public String getDefaultLayoutName(String template)
455    {
456        return (mapperRegistry[LAYOUT_KEY]).getDefaultName(template);
457    }
458
459    /**
460     * Get the default navigation module name of the template engine
461     * service corresponding to the template name extension of
462     * the named template.
463     *
464     * @param template The template name.
465     * @return The default navigation module name.
466     */
467    @Override
468    public String getDefaultNavigationName(String template)
469    {
470        return (mapperRegistry[NAVIGATION_KEY]).getDefaultName(template);
471    }
472
473    /**
474     * Get the default layout template name of the template engine
475     * service corresponding to the template name extension of
476     * the named template.
477     *
478     * @param template The template name.
479     * @return The default layout template name.
480     */
481    @Override
482    public String getDefaultLayoutTemplateName(String template)
483    {
484        return (mapperRegistry[LAYOUT_TEMPLATE_KEY]).getDefaultName(template);
485    }
486
487    /**
488     * Find the default page module name for the given request.
489     *
490     * @param pipelineData The encapsulation of the request to retrieve the
491     *             default page for.
492     * @return The default page module name.
493     */
494    @Override
495    public String getDefaultPageName(PipelineData pipelineData)
496    {
497        ParameterParser pp = pipelineData.get(Turbine.class, ParameterParser.class);
498        String template = pp.get(URIConstants.CGI_TEMPLATE_PARAM);
499        return (template != null) ?
500            getDefaultPageName(template) : getDefaultPage();
501    }
502
503    /**
504     * Find the default layout module name for the given request.
505     *
506     * @param pipelineData The encapsulation of the request to retrieve the
507     *             default layout for.
508     * @return The default layout module name.
509     */
510    @Override
511    public String getDefaultLayoutName(PipelineData pipelineData)
512    {
513        ParameterParser pp = pipelineData.get(Turbine.class, ParameterParser.class);
514        String template = pp.get(URIConstants.CGI_TEMPLATE_PARAM);
515        return (template != null) ?
516            getDefaultLayoutName(template) : getDefaultLayout();
517    }
518
519    /**
520     * Locate and return the name of the screen module to be used
521     * with the named screen template.
522     *
523     * @param template The screen template name.
524     * @return The found screen module name.
525     * @exception Exception, a generic exception.
526     */
527    @Override
528    public String getScreenName(String template)
529        throws Exception
530    {
531        return (mapperRegistry[SCREEN_KEY]).getMappedName(template);
532    }
533
534    /**
535     * Locate and return the name of the layout module to be used
536     * with the named layout template.
537     *
538     * @param template The layout template name.
539     * @return The found layout module name.
540     * @exception Exception, a generic exception.
541     */
542    @Override
543    public String getLayoutName(String template)
544        throws Exception
545    {
546        return (mapperRegistry[LAYOUT_KEY]).getMappedName(template);
547    }
548
549    /**
550     * Locate and return the name of the navigation module to be used
551     * with the named navigation template.
552     *
553     * @param template The navigation template name.
554     * @return The found navigation module name.
555     * @exception Exception, a generic exception.
556     */
557    @Override
558    public String getNavigationName(String template)
559        throws Exception
560    {
561        return (mapperRegistry[NAVIGATION_KEY]).getMappedName(template);
562    }
563
564    /**
565     * Locate and return the name of the screen template corresponding
566     * to the given template name parameter. This might return null if
567     * the screen is not found!
568     *
569     * @param template The template name parameter.
570     * @return The found screen template name.
571     * @exception Exception, a generic exception.
572     */
573    @Override
574    public String getScreenTemplateName(String template)
575        throws Exception
576    {
577        return (mapperRegistry[SCREEN_TEMPLATE_KEY]).getMappedName(template);
578    }
579
580    /**
581     * Locate and return the name of the layout template corresponding
582     * to the given screen template name parameter.
583     *
584     * @param template The template name parameter.
585     * @return The found screen template name.
586     * @exception Exception, a generic exception.
587     */
588    @Override
589    public String getLayoutTemplateName(String template)
590        throws Exception
591    {
592        return (mapperRegistry[LAYOUT_TEMPLATE_KEY]).getMappedName(template);
593    }
594
595    /**
596     * Locate and return the name of the navigation template corresponding
597     * to the given template name parameter. This might return null if
598     * the navigation is not found!
599     *
600     * @param template The template name parameter.
601     * @return The found navigation template name.
602     * @exception Exception, a generic exception.
603     */
604    @Override
605    public String getNavigationTemplateName(String template)
606        throws Exception
607    {
608        return (mapperRegistry[NAVIGATION_TEMPLATE_KEY]).getMappedName(template);
609    }
610
611    /**
612     * Translates the supplied template paths into their Turbine-canonical
613     * equivalent (probably absolute paths). This is used if the templating
614     * engine (e.g. JSP) does not provide any means to load a page but
615     * the page path is passed to the servlet container.
616     *
617     * @param templatePaths An array of template paths.
618     * @return An array of translated template paths.
619     * @deprecated Each template engine service should know how to translate
620     *             a request onto a file.
621     */
622    @Override
623    @Deprecated
624    public String[] translateTemplatePaths(String[] templatePaths)
625    {
626        for (int i = 0; i < templatePaths.length; i++)
627        {
628            templatePaths[i] = TurbineServlet.getRealPath(templatePaths[i]);
629        }
630        return templatePaths;
631    }
632
633    /**
634     * Delegates to the appropriate {@link
635     * org.apache.turbine.services.template.TemplateEngineService} to
636     * check the existance of the specified template.
637     *
638     * @param template The template to check for the existance of.
639     * @param templatePaths The paths to check for the template.
640     * @deprecated Use templateExists from the various Templating Engines
641     */
642    @Override
643    @Deprecated
644    public boolean templateExists(String template,
645        String[] templatePaths)
646    {
647        for (int i = 0; i < templatePaths.length; i++)
648        {
649            if (new File(templatePaths[i], template).exists())
650            {
651                return true;
652            }
653        }
654        return false;
655    }
656
657    /**
658     * Registers the provided template engine for use by the
659     * <code>TemplateService</code>.
660     *
661     * @param service The <code>TemplateEngineService</code> to register.
662     */
663    @Override
664    public synchronized void registerTemplateEngineService(TemplateEngineService service)
665    {
666        String[] exts = service.getAssociatedFileExtensions();
667
668        for (int i = 0; i < exts.length; i++)
669        {
670            templateEngineRegistry.put(exts[i], service);
671        }
672    }
673
674    /**
675     * The {@link org.apache.turbine.services.template.TemplateEngineService}
676     * associated with the specified template's file extension.
677     *
678     * @param template The template name.
679     * @return The template engine service.
680     */
681    @Override
682    public TemplateEngineService getTemplateEngineService(String template)
683    {
684        return templateEngineRegistry.get(getExtension(template));
685    }
686
687    /**
688     * Register a template Mapper to the service. This Mapper
689     * performs the template mapping and searching for a specific
690     * object type which is managed by the TemplateService.
691     *
692     * @param templateKey  One of the _KEY constants for the Template object types.
693     * @param mapper  An object which implements the Mapper interface.
694     */
695    private void registerMapper(int templateKey, Mapper mapper)
696    {
697        mapper.init();
698        mapperRegistry[templateKey] = mapper;
699    }
700
701    /**
702     * Load and configure the Template mappers for
703     * the Template Service.
704     *
705     * @param conf The current configuration object.
706     * @throws InitializationException A problem occurred trying to set up the mappers.
707     */
708    @SuppressWarnings("unchecked")
709    private void initMapper(Configuration conf)
710            throws InitializationException
711    {
712        // Create a registry with the number of Template Types managed by this service.
713        // We could use a List object here and extend the number of managed objects
714        // dynamically. However, by using an Object Array, we get much more performance
715        // out of the Template Service.
716        mapperRegistry = new Mapper[TEMPLATE_TYPES];
717
718        String [] mapperNames = new String [] {
719            Page.NAME, Screen.NAME, Layout.NAME, Navigation.NAME,
720            LAYOUT_TEMPLATE_NAME, SCREEN_TEMPLATE_NAME, NAVIGATION_TEMPLATE_NAME
721        };
722
723        Class<?> [] mapperKeys = new Class<?> [] {
724            Page.class, Screen.class, Layout.class, Navigation.class,
725            Layout.class, Screen.class, Navigation.class
726        };
727
728        String [] mapperClasses = new String [] {
729            DirectMapper.class.getName(),
730            ClassMapper.class.getName(),
731            ClassMapper.class.getName(),
732            ClassMapper.class.getName(),
733            LayoutTemplateMapper.class.getName(),
734            ScreenTemplateMapper.class.getName(),
735            DirectTemplateMapper.class.getName()
736        };
737
738        AssemblerBrokerService ab = (AssemblerBrokerService)TurbineServices.getInstance()
739                                        .getService(AssemblerBrokerService.SERVICE_NAME);
740
741        int [] mapperCacheSize = new int [mapperKeys.length];
742        Loader<? extends Assembler> [] mapperLoader = new Loader<?>[mapperKeys.length];
743
744        for (int i = 0; i < mapperKeys.length; i++)
745        {
746            mapperLoader[i] = ab.getLoader((Class<? extends Assembler>)mapperKeys[i]);
747            mapperCacheSize[i] = (mapperLoader[i] != null) ? mapperLoader[i].getCacheSize() : 0;
748        }
749
750        // HACK: to achieve the same behavior as before
751        mapperLoader[LAYOUT_TEMPLATE_KEY] = null;
752        mapperLoader[SCREEN_TEMPLATE_KEY] = null;
753        mapperLoader[NAVIGATION_TEMPLATE_KEY] = null;
754
755        String [] mapperDefaultProperty = new String [] {
756            TemplateEngineService.DEFAULT_PAGE,
757            TemplateEngineService.DEFAULT_SCREEN,
758            TemplateEngineService.DEFAULT_LAYOUT,
759            TemplateEngineService.DEFAULT_NAVIGATION,
760            TemplateEngineService.DEFAULT_LAYOUT_TEMPLATE,
761            TemplateEngineService.DEFAULT_SCREEN_TEMPLATE,
762            TemplateEngineService.DEFAULT_NAVIGATION_TEMPLATE
763        };
764
765        char [] mapperSeparator = new char [] { '.', '.', '.', '.', '/', '/', '/' };
766
767        String [] mapperPrefix = new String [] {
768            null, null, null, null,
769            Layout.PREFIX,
770            Screen.PREFIX,
771            Navigation.PREFIX  };
772
773        for (int i = 0; i < TEMPLATE_TYPES; i++)
774        {
775            StringBuilder mapperProperty = new StringBuilder();
776            mapperProperty.append("mapper.");
777            mapperProperty.append(mapperNames[i]);
778            mapperProperty.append(".class");
779
780            String mapperClass =
781                    conf.getString(mapperProperty.toString(), mapperClasses[i]);
782
783            log.info("Using " + mapperClass + " to map " + mapperNames[i] + " elements");
784
785            Mapper tm = null;
786
787            try
788            {
789                    FactoryService factory = (FactoryService)TurbineServices.getInstance().getService(FactoryService.ROLE);
790                    tm = (Mapper) factory.getInstance(mapperClass);
791            }
792            catch (FactoryException e)
793            {
794                        throw new InitializationException("", e);
795                    }
796
797            tm.setUseCache(useCache);
798            tm.setCacheSize(mapperCacheSize[i]);
799            tm.setDefaultProperty(mapperDefaultProperty[i]);
800            tm.setSeparator(mapperSeparator[i]);
801
802            if ((mapperLoader[i] != null) && (tm instanceof ClassMapper))
803            {
804                ((ClassMapper) tm).setLoader(mapperLoader[i]);
805            }
806
807            if ((mapperPrefix[i] != null) && (tm instanceof BaseTemplateMapper))
808            {
809                ((BaseTemplateMapper) tm).setPrefix(mapperPrefix[i]);
810            }
811
812            registerMapper(i, tm);
813        }
814    }
815}