001 /* 002 * Copyright 2007 Tacos. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * under the License. 016 */ 017 package net.sf.tacos.resolvers; 018 019 import org.apache.commons.logging.Log; 020 import org.apache.hivemind.ApplicationRuntimeException; 021 import org.apache.hivemind.Location; 022 import org.apache.hivemind.Resource; 023 import org.apache.hivemind.impl.DefaultClassResolver; 024 import org.apache.hivemind.impl.LocationImpl; 025 import org.apache.hivemind.util.ClasspathResource; 026 import org.apache.hivemind.util.Defense; 027 import org.apache.tapestry.INamespace; 028 import org.apache.tapestry.IRequestCycle; 029 import org.apache.tapestry.resolver.AbstractSpecificationResolver; 030 import org.apache.tapestry.resolver.ComponentSpecificationResolver; 031 import org.apache.tapestry.services.ClassFinder; 032 import org.apache.tapestry.spec.ComponentSpecification; 033 import org.apache.tapestry.spec.IComponentSpecification; 034 035 /** 036 * An AbstractSpecificationResolver similar to tapestry's. Contains additional 037 * logic that can loads tapestry templates from the classpath. 038 * 039 * @author Howard Lewis Ship 040 * @author Andreas Andreou, amplafi.com 041 */ 042 043 public class ClasspathComponentSpecResolver extends 044 AbstractSpecificationResolver implements ComponentSpecificationResolver { 045 046 /** Set by container. */ 047 private Log log; 048 049 /** Set by resolve(). */ 050 private String type; 051 052 private ClassFinder classFinder; 053 054 protected void reset() { 055 type = null; 056 super.reset(); 057 } 058 059 /** 060 * Passed the namespace of a container (to resolve the type in) and the type 061 * to resolve, performs the processing. A "bare type" (without a library 062 * prefix) may be in the containerNamespace, or the framework namespace (a 063 * search occurs in that order). 064 * 065 * @param cycle 066 * current request cycle 067 * @param containerNamespace 068 * namespace that may contain a library referenced in the type 069 * @param componentType 070 * the component specification to find, either a simple name, or 071 * prefixed with a library id (defined for the container 072 * namespace) 073 * @see #getNamespace() 074 * @see #getSpecification() 075 */ 076 077 public void resolve(IRequestCycle cycle, INamespace containerNamespace, 078 String componentType, Location location) { 079 Defense.notNull(componentType, "type"); 080 081 int colonx = componentType.indexOf(':'); 082 083 if (colonx > 0) { 084 String libraryId = componentType.substring(0, colonx); 085 String simpleType = componentType.substring(colonx + 1); 086 087 resolve(cycle, containerNamespace, libraryId, simpleType, location); 088 } else { 089 resolve(cycle, containerNamespace, null, componentType, location); 090 } 091 } 092 093 /** 094 * Like #resolve(org.apache.tapestry.IRequestCycle, 095 * org.apache.tapestry.INamespace, java.lang.String, 096 * org.apache.tapestry.ILocation), but used when the type has already been 097 * parsed into a library id and a simple type. 098 * 099 * @param cycle 100 * current request cycle 101 * @param containerNamespace 102 * namespace that may contain a library referenced in the type 103 * @param libraryId 104 * the library id within the container namespace, or null 105 * @param componentType 106 * the component specification to find as a simple name (without 107 * a library prefix) 108 * @param location 109 * of reference to be resolved 110 * @throws ApplicationRuntimeException 111 * if the type cannot be resolved 112 */ 113 114 public void resolve(IRequestCycle cycle, INamespace containerNamespace, 115 String libraryId, String componentType, Location location) { 116 reset(); 117 this.type = componentType; 118 119 INamespace namespace = findNamespaceForId(containerNamespace, libraryId); 120 121 setNamespace(namespace); 122 123 if (namespace.containsComponentType(type)) { 124 setSpecification(namespace.getComponentSpecification(type)); 125 return; 126 } 127 128 IComponentSpecification spec = searchForComponent(cycle); 129 130 // If not found after search, check to see if it's in 131 // the framework instead. 132 if (spec == null) { 133 spec = doCustomSearch(cycle); 134 } 135 136 if (spec == null) { 137 throw new ApplicationRuntimeException("no Such Component Type:" + this.type, 138 location, null); 139 } 140 141 setSpecification(spec); 142 143 // Install it into the namespace, to short-circuit any future search. 144 install(); 145 } 146 147 /** 148 * Override to add custom behavior to component resolution - will be the last 149 * resolve logic to be executed. 150 * @param cycle 151 * @return 152 */ 153 protected IComponentSpecification doCustomSearch(IRequestCycle cycle) { 154 return null; 155 } 156 157 private IComponentSpecification searchForComponent(IRequestCycle cycle) { 158 INamespace namespace = getNamespace(); 159 160 // if (_log.isDebugEnabled()) 161 // _log.debug(ImplMessages.resolvingComponent(_type, namespace)); 162 163 String expectedName = type + ".jwc"; 164 Resource namespaceLocation = namespace.getSpecificationLocation(); 165 166 // Look for appropriate file in same folder as the library (or 167 // application) specification. 168 169 IComponentSpecification result = check(namespaceLocation.getRelativeResource(expectedName)); 170 171 if (result != null) { 172 return result; 173 } 174 if (namespace.isApplicationNamespace()) { 175 176 // The application namespace gets some extra searching. 177 178 result = check(getWebInfAppLocation().getRelativeResource( 179 expectedName)); 180 181 if (result == null) { 182 result = check(getWebInfLocation().getRelativeResource( 183 expectedName)); 184 } 185 if (result == null) { 186 result = check(getContextRoot() 187 .getRelativeResource(expectedName)); 188 } 189 if (result != null) { 190 return result; 191 } 192 } 193 194 result = searchForComponentClass(namespace, type); 195 196 if (result != null) { 197 return result; 198 } 199 200 // Not in the library or app spec; does it match a component 201 // provided by the Framework? 202 203 INamespace framework = getSpecificationSource().getFrameworkNamespace(); 204 205 if (framework.containsComponentType(type)) { 206 return framework.getComponentSpecification(type); 207 } 208 return getDelegate() 209 .findComponentSpecification(cycle, namespace, type); 210 } 211 212 IComponentSpecification searchForComponentClass(INamespace namespace, 213 String componentType) { 214 String packages = namespace 215 .getPropertyValue("org.apache.tapestry.component-class-packages"); 216 217 String className = componentType.replace('/', '.'); 218 219 Class componentClass = classFinder.findClass(packages, className); 220 221 if (componentClass == null) { 222 return null; 223 } 224 Resource componentResource = null; 225 Resource namespaceResource = namespace.getSpecificationLocation(); 226 227 String fullPath = componentClass.getName().replace('.', '/'); 228 ClasspathResource html = new ClasspathResource( 229 new DefaultClassResolver(), fullPath + ".html"); 230 231 // first check near the class, if the html is there then that's where 232 // the (fictional) jwc should be - need exploded wars for this 233 234 if (html.getResourceURL() != null && namespace.isApplicationNamespace()) { 235 componentResource = new ClasspathResource( 236 new DefaultClassResolver(), fullPath + ".jwc"); 237 } else { 238 componentResource = namespaceResource.getRelativeResource(componentType 239 + ".jwc"); 240 } 241 242 Location location = new LocationImpl(componentResource); 243 244 IComponentSpecification spec = new ComponentSpecification(); 245 spec.setLocation(location); 246 spec.setSpecificationLocation(componentResource); 247 spec.setComponentClassName(componentClass.getName()); 248 249 return spec; 250 } 251 252 private IComponentSpecification check(Resource resource) { 253 if (log.isDebugEnabled()) { 254 log.debug("Checking: " + resource); 255 } 256 if (resource.getResourceURL() == null) { 257 return null; 258 } 259 return getSpecificationSource().getComponentSpecification(resource); 260 } 261 262 private void install() { 263 INamespace namespace = getNamespace(); 264 IComponentSpecification specification = getSpecification(); 265 266 // if (_log.isDebugEnabled()) 267 // _log.debug(ImplMessages.installingComponent(_type, namespace, 268 // specification)); 269 270 namespace.installComponentSpecification(type, specification); 271 } 272 273 public String getType() { 274 return type; 275 } 276 277 public void setLog(Log log) { 278 this.log = log; 279 } 280 281 public void setClassFinder(ClassFinder classFinder) { 282 this.classFinder = classFinder; 283 } 284 285 }