001package org.apache.turbine.services.template.mapper;
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.util.ArrayList;
025import java.util.Arrays;
026import java.util.List;
027
028import org.apache.commons.lang.StringUtils;
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.apache.turbine.modules.Assembler;
032import org.apache.turbine.modules.Loader;
033import org.apache.turbine.services.template.TemplateService;
034
035/**
036 * This mapper tries to map Template names to class names. If no direct match
037 * is found, it tries matches "upwards" in the package hierarchy until either
038 * a match is found or the root is hit. Then it returns the name of the
039 * default class from the TemplateEngineService.
040 *
041 * 1. about.directions.Driving     <- direct matching the template to the class name
042 * 2. about.directions.Default     <- matching the package, class name is Default
043 * 3. about.Default                <- stepping up in the package hierarchy, looking for Default
044 * 4. Default                      <- Class called "Default" without package
045 * 5. VelocityScreen               <- The class configured by the Service (VelocityService) to
046 *
047 * Please note, that no actual packages are searched. This is the scope of the
048 * TemplateEngine Loader which is passed at construction time.
049 *
050 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
051 * @version $Id: ClassMapper.java 1709648 2015-10-20 17:08:10Z tv $
052 */
053
054public class ClassMapper
055    extends BaseMapper
056    implements Mapper
057{
058    /** The loader for actually trying out the package names */
059    private Loader<? extends Assembler> loader = null;
060
061    /** Logging */
062    private static Log log = LogFactory.getLog(ClassMapper.class);
063
064    /**
065     * Default C'tor. If you use this C'tor, you must use
066     * the bean setter to set the various properties needed for
067     * this mapper before first usage.
068     */
069    public ClassMapper()
070    {
071        // empty
072    }
073
074    /**
075     * Get the Loader value.
076     * @return the Loader value.
077     */
078    public Loader<? extends Assembler> getLoader()
079    {
080        return loader;
081    }
082
083    /**
084     * Set the Loader value.
085     * @param loader The new Loader value.
086     */
087    public void setLoader(Loader<? extends Assembler> loader)
088    {
089        this.loader = loader;
090        log.debug("Loader is " + this.loader);
091    }
092
093    /**
094     * Strip off a possible extension, replace all "," with "."
095     * Look through the given package path until a match is found.
096     *
097     * @param template The template name.
098     * @return A class name for the given template.
099     */
100    public String doMapping(String template)
101    {
102        log.debug("doMapping(" + template + ")");
103
104        // Copy our elements into an array
105        List<String> components
106            = new ArrayList<String>(Arrays.asList(StringUtils.split(
107                                              template,
108                                              String.valueOf(TemplateService.TEMPLATE_PARTS_SEPARATOR))));
109        int componentSize = components.size() - 1 ;
110
111        // This method never gets an empty string passed.
112        // So this is never < 0
113        String className = components.get(componentSize);
114        components.remove(componentSize--);
115
116        log.debug("className is " + className);
117
118        // Strip off a possible Extension
119        int dotIndex = className.lastIndexOf(TemplateService.EXTENSION_SEPARATOR);
120        className = (dotIndex < 0) ? className : className.substring(0, dotIndex);
121
122        // This is an optimization. If the name we're looking for is
123        // already the default name for the template, don't do a "first run"
124        // which looks for an exact match.
125        boolean firstRun = !className.equals(TemplateService.DEFAULT_NAME);
126
127        for(;;)
128        {
129            String pkg = StringUtils.join(components.iterator(), String.valueOf(separator));
130            StringBuilder testName = new StringBuilder();
131
132            log.debug("classPackage is now: " + pkg);
133
134            if (!components.isEmpty())
135            {
136                testName.append(pkg);
137                testName.append(separator);
138            }
139
140            testName.append((firstRun)
141                ? className
142                : TemplateService.DEFAULT_NAME);
143
144            log.debug("Looking for " + testName);
145            try
146            {
147                loader.getAssembler(testName.toString());
148                log.debug("Found it, returning " + testName);
149                return testName.toString();
150            }
151            catch (Exception e)
152            {
153                // Not found. Go on.
154            }
155
156            if (firstRun)
157            {
158                firstRun = false;
159            }
160            else
161            {
162                if (components.isEmpty())
163                {
164                    break; // for(;;)
165                }
166                components.remove(componentSize--);
167            }
168        }
169
170        log.debug("Returning default");
171        return getDefaultName(template);
172    }
173}
174
175
176
177