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