View Javadoc
1 /* 2 * ValueResolver.java 3 * Created on September 18, 2003 4 * 5 * The Blues Framework - A lightweight application framework 6 * Copyright (C) 2003 Lonnie Pryor 7 * http://blues.lonniepryor.com 8 * 9 * This library is free software; you can redistribute it and/or modify it under the 10 * terms of the GNU Lesser General Public License as published by the Free Software 11 * Foundation; either version 2.1 of the License, or (at your option) any later 12 * version. 13 * 14 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License along 19 * with this library; if not, write to: 20 * 21 * The Free Software Foundation, Inc. 22 * 59 Temple Place, Suite 330 23 * Boston, MA 02111-1307 USA 24 * 25 */ 26 package com.lonniepryor.blues.xml; 27 28 import java.net.URL; 29 30 import java.util.HashMap; 31 import java.util.Map; 32 import java.util.StringTokenizer; 33 34 /*** 35 * Transforms the values of attributes in an XML document into JavaBean property 36 * values. NOTE: this class is NOT thread-safe and instances may only be used on a 37 * single thread at a time. 38 * 39 * @author Lonnie Pryor 40 * @version $Revision: 1.1 $ 41 */ 42 public class ValueResolver { 43 /*** The ClassLoader to load classes from. */ 44 private final ClassLoader classLoader; 45 /*** The relative path base to resolve Resource paths against. */ 46 private final String relativePathBase; 47 /*** The first element in the chained sequence of class imports. */ 48 private final Import importsChain; 49 /*** The short class name cache. */ 50 private final Map classCache = new HashMap(); 51 52 /*** 53 * Creates a new ValueResolver object. 54 * 55 * @param classLoader The ClassLoader to load classes from. 56 * @param relativePathBase The relative path base to resolve Resource paths 57 * against. 58 * @param imports A whitespace-delimeted sequence of Java import statements 59 * (minus the 'import' keyword and line-ending semi-colon). 60 */ 61 public ValueResolver ( 62 ClassLoader classLoader, String relativePathBase, String imports) { 63 if (classLoader == null) 64 throw new NullPointerException("classLoader"); 65 if (relativePathBase == null) 66 throw new NullPointerException("relativePathBase"); 67 this.classLoader = classLoader; 68 if (relativePathBase.startsWith("/")) 69 relativePathBase = relativePathBase.substring(1); 70 if ((relativePathBase.length() > 0) && !relativePathBase.endsWith("/")) 71 relativePathBase = relativePathBase + "/"; 72 this.relativePathBase = relativePathBase; 73 Import tmpImport = null; 74 if (imports != null) { 75 for (StringTokenizer st = new StringTokenizer(imports); st.hasMoreTokens();) { 76 String importStr = st.nextToken(); 77 if (importStr.endsWith("*")) 78 tmpImport = newPackageImport( 79 importStr.substring(0, importStr.length() - 1), tmpImport); 80 else 81 tmpImport = newClassImport(importStr, tmpImport); 82 } 83 } 84 this.importsChain = tmpImport; 85 } 86 87 /*** 88 * Resolves the supplied path into an absoulte path, prepending the relative path 89 * base if the resource name does not begin with a '/'. 90 * 91 * @param path The path to resolve. 92 * 93 * @return The supplied path resolved into an absoulte path. 94 */ 95 public String resolvePath (String path) { 96 if (path == null) 97 throw new NullPointerException("path"); 98 return path.startsWith("/") ? path.substring(1) : (relativePathBase + path); 99 } 100 101 /*** 102 * Resolves the supplied resource name path and loads the requested resource from 103 * the class loader. 104 * 105 * @param name The name of the resource to load. 106 * 107 * @return The URL of the resource or null if it is not found. 108 */ 109 public URL resolveResource (String name) { 110 if (name == null) 111 throw new NullPointerException("name"); 112 URL resource = classLoader.getResource(resolvePath(name)); 113 if (resource == null) 114 throw new XmlException("Resource '" + name + "' not found"); 115 return resource; 116 } 117 118 /*** 119 * Resolves the supplied class name into a Class instance, searching this 120 * resolver's import statements for the approprite fully-qualified name. 121 * 122 * @param name The name of the class to load. 123 * 124 * @return The requested class or null if it is not found. 125 */ 126 public Class resolveClass (String name) { 127 if (classCache.containsKey(name)) 128 return (Class)classCache.get(name); 129 Class result = null; 130 try { 131 result = classLoader.loadClass(name); 132 } catch (ClassNotFoundException cnfe) { 133 if (importsChain != null) 134 result = importsChain.loadClass(name); 135 } 136 if (result == null) 137 throw new XmlException("Class '" + name + "' not found"); 138 classCache.put(name, result); 139 return result; 140 } 141 142 /*** 143 * Transforms the supplied string value into the specified type. 144 * 145 * @param toType The type to transform to. 146 * @param stringValue The string value to transform. 147 * 148 * @return The transformed property value. 149 */ 150 public Object resolve (Class toType, String stringValue) { 151 if (toType == null) 152 throw new NullPointerException("toType"); 153 if (stringValue == null) 154 throw new NullPointerException("stringValue"); 155 if (toType.equals(Class.class)) 156 return resolveClass(stringValue); 157 if (toType.equals(URL.class)) 158 return resolveResource(stringValue); 159 return null; 160 } 161 162 /*** 163 * Creates a new Import for the specified class name. 164 * 165 * @param className The fully-qualified class name. 166 * @param next The next import in the chain. 167 * 168 * @return A new Import for the specified class name. 169 */ 170 private Import newClassImport (final String className, Import next) { 171 return new Import(next) { 172 Class findClass (String name) 173 throws ClassNotFoundException { 174 return className.endsWith(name) ? classLoader.loadClass(className) : null; 175 } 176 }; 177 } 178 179 /*** 180 * Creates a new Import for the specified package name. 181 * 182 * @param packageName The fully-qualified package name ending with a dot. 183 * @param next The next import in the chain. 184 * 185 * @return A new Import for the specified package name. 186 */ 187 private Import newPackageImport (final String packageName, Import next) {/package-summary.html">b> Import newPackageImport (final String packageName, Import next) { 188 return new Import(next) { 189 Class findClass (String name) 190 throws ClassNotFoundException { 191 return classLoader.loadClass(packageName + name); 192 } 193 }; 194 } 195 196 /*** 197 * Chained strategy class for loading classes against a set of import statements. 198 * 199 * @author Lonnie Pryor 200 * @version $Revision: 1.1 $ 201 */ 202 private abstract class Import { 203 /*** The next import in the chain. */ 204 private final Import next; 205 206 /*** 207 * Creates a new Import object. 208 * 209 * @param next The next import in the chain. 210 */ 211 Import (Import next) { 212 this.next = next; 213 } 214 215 /*** 216 * Loads a class from this import chain. 217 * 218 * @param name The name of the class to load. 219 * 220 * @return The requested class or null if it is not found. 221 */ 222 final Class loadClass (String name) { 223 Class nextClass = (next == null) ? null : next.loadClass(name); 224 try { 225 Class myClass = findClass(name); 226 if (myClass == null) 227 return nextClass; 228 if (nextClass != null) 229 throw new IllegalArgumentException( 230 "Ambigous class name '" + name + "' matches " + nextClass.getName() 231 + " and " + myClass.getName()); 232 return myClass; 233 } catch (ClassNotFoundException cnfe) { 234 return nextClass; 235 } 236 } 237 238 /*** 239 * Overridden by subclasses to specialize searching behaviour. 240 * 241 * @param name The name of the class to load. 242 * 243 * @return The requested class. 244 * 245 * @throws ClassNotFoundException if the requested class is not found. 246 */ 247 abstract Class findClass (String name) 248 throws ClassNotFoundException; 249 } 250 }

This page was automatically generated by Maven