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     <- direct matching the template to the class name
041     * 2. about.directions.Default     <- matching the package, class name is Default
042     * 3. about.Default                <- stepping up in the package hierarchy, looking for Default
043     * 4. Default                      <- Class called "Default" without package
044     * 5. VelocityScreen               <- 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