1 package org.apache.turbine.services.template.mapper;
2
3
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 */
22
23
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.List;
27
28 import org.apache.commons.lang.StringUtils;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.turbine.modules.Assembler;
32 import org.apache.turbine.modules.Loader;
33 import org.apache.turbine.services.template.TemplateService;
34 import org.apache.turbine.util.TurbineException;
35
36 /**
37 * This mapper tries to map Template names to class names. If no direct match
38 * is found, it tries matches "upwards" in the package hierarchy until either
39 * a match is found or the root is hit. Then it returns the name of the
40 * default class from the TemplateEngineService.
41 *
42 * 1. about.directions.Driving <- direct matching the template to the class name
43 * 2. about.directions.Default <- matching the package, class name is Default
44 * 3. about.Default <- stepping up in the package hierarchy, looking for Default
45 * 4. Default <- Class called "Default" without package
46 * 5. VelocityScreen <- The class configured by the Service (VelocityService) to
47 *
48 * Please note, that no actual packages are searched. This is the scope of the
49 * TemplateEngine Loader which is passed at construction time.
50 *
51 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
52 * @version $Id: ClassMapper.java 1768528 2016-11-07 15:13:26Z gk $
53 */
54
55 public class ClassMapper
56 extends BaseMapper
57 implements Mapper
58 {
59 /** The loader for actually trying out the package names */
60 private Loader<? extends Assembler> loader = null;
61
62 /** Logging */
63 private static Log log = LogFactory.getLog(ClassMapper.class);
64
65 /**
66 * Default C'tor. If you use this C'tor, you must use
67 * the bean setter to set the various properties needed for
68 * this mapper before first usage.
69 */
70 public ClassMapper()
71 {
72 // empty
73 }
74
75 /**
76 * Get the Loader value.
77 * @return the Loader value.
78 */
79 public Loader<? extends Assembler> getLoader()
80 {
81 return loader;
82 }
83
84 /**
85 * Set the Loader value.
86 * @param loader The new Loader value.
87 */
88 public void setLoader(Loader<? extends Assembler> loader)
89 {
90 this.loader = loader;
91 log.debug("Loader is " + this.loader);
92 }
93
94 /**
95 * Strip off a possible extension, replace all "," with "."
96 * Look through the given package path until a match is found.
97 *
98 * @param template The template name.
99 * @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<String>(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