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