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.Loader; 32 import org.apache.turbine.services.template.TemplateService; 33 34 /** 35 * This mapper tries to map Template names to class names. If no direct match 36 * is found, it tries matches "upwards" in the package hierarchy until either 37 * a match is found or the root is hit. Then it returns the name of the 38 * default class from the TemplateEngineService. 39 * 40 * 1. about.directions.Driving <- direct matching the template to the class name 41 * 2. about.directions.Default <- matching the package, class name is Default 42 * 3. about.Default <- stepping up in the package hierarchy, looking for Default 43 * 4. Default <- Class called "Default" without package 44 * 5. VelocityScreen <- The class configured by the Service (VelocityService) to 45 * 46 * Please note, that no actual packages are searched. This is the scope of the 47 * TemplateEngine Loader which is passed at construction time. 48 * 49 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> 50 * @version $Id: ClassMapper.java 1071091 2011-02-15 22:06:55Z tv $ 51 */ 52 53 public class ClassMapper 54 extends BaseMapper 55 implements Mapper 56 { 57 /** The loader for actually trying out the package names */ 58 private Loader loader = null; 59 60 /** Logging */ 61 private static Log log = LogFactory.getLog(ClassMapper.class); 62 63 /** 64 * Default C'tor. If you use this C'tor, you must use 65 * the bean setter to set the various properties needed for 66 * this mapper before first usage. 67 */ 68 public ClassMapper() 69 { 70 // empty 71 } 72 73 /** 74 * Get the Loader value. 75 * @return the Loader value. 76 */ 77 public Loader getLoader() 78 { 79 return loader; 80 } 81 82 /** 83 * Set the Loader value. 84 * @param loader The new Loader value. 85 */ 86 public void setLoader(Loader loader) 87 { 88 this.loader = loader; 89 log.debug("Loader is " + this.loader); 90 } 91 92 /** 93 * Strip off a possible extension, replace all "," with "." 94 * Look through the given package path until a match is found. 95 * 96 * @param template The template name. 97 * @return A class name for the given template. 98 */ 99 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