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