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