View Javadoc
1 package attrib4j; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.lang.reflect.InvocationTargetException; 8 import java.lang.reflect.Method; 9 import java.security.AccessController; 10 import java.security.PrivilegedAction; 11 import java.util.Hashtable; 12 import java.util.Properties; 13 14 /*** 15 * <p>Factory for creating {@link AttributeCompiler} instances, with discovery and 16 * configuration features similar to that employed by standard Java APIs 17 * such as JAXP. Current implementations are based on Javadoc and ??? 18 * libraries.</p> 19 * 20 * <p>Implementation taken from the jakarata commons logging package.</p> 21 * 22 * TODO Put common impl in a base class. 23 * 24 * @author <a href="mailto:mpollack@speakeasy.net">Mark Pollack</a> 25 * @version $Revision: 1.1 $ $Date: 2003/04/10 03:36:16 $ 26 */ 27 28 public abstract class AttributeCompilerFactory { 29 30 // ----------------------------------------------------- Manifest Constants 31 32 /*** 33 * The name of the property used to identify the AttributeCompilerFactory 34 * implementation class name. 35 */ 36 public static final String FACTORY_PROPERTY = 37 "attrib4j.AttributeCompilerFactory"; 38 39 /*** 40 * The fully qualified class name of the fallback 41 * <code>AttributeCompilerFactory</code> 42 * implementation class to use, if no other can be found. 43 */ 44 public static final String FACTORY_DEFAULT = 45 "attrib4j.compiler.JavadocFactory"; 46 47 /*** 48 * The name of the properties file to search for. 49 */ 50 public static final String FACTORY_PROPERTIES = "attrib4j.properties"; 51 52 /*** 53 * JDK1.3+ 'Service Provider' specification 54 * ( http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html ) 55 */ 56 protected static final String SERVICE_ID = 57 "META-INF/services/attrib4j.AttributeCompilerFactory"; 58 59 // ----------------------------------------------------------- Constructors 60 61 /*** 62 * Protected constructor that is not available for public use. 63 */ 64 protected AttributeCompilerFactory() { 65 } 66 67 // --------------------------------------------------------- Public Methods 68 69 // ------------------------------------------------------- Static Variables 70 71 /*** 72 * The previously constructed <code>AttributeCompilerFactory</code> instances, 73 * keyed by the <code>ClassLoader</code> with which it was created. 74 */ 75 protected static Hashtable factories = new Hashtable(); 76 77 // --------------------------------------------------------- Static Methods 78 79 /*** 80 * <p>Construct (if necessary) and return a <code>AttributeCompilerFactory</code> 81 * instance, using the following ordered lookup procedure to determine 82 * the name of the implementation class to be loaded.</p> 83 * <ul> 84 * <li>The <code>attrib4j.AttributeCompilerFactory</code> system property.</li> 85 * <li>The JDK 1.3 Service Discovery mechanism</li> 86 * <li>Use the properties file <code>attrib4j.properties</code> 87 * file, if found in the class path of this class. The configuration 88 * file is in standard <code>java.util.Properties</code> format and 89 * contains the fully qualified name of the implementation class 90 * with the key being the system property defined above.</li> 91 * <li>Fall back to a default implementation class 92 * (<code>attrib4j.compiler.JavadocFactory</code>).</li> 93 * </ul> 94 * 95 * 96 * @exception AttributeException if the implementation class is not 97 * available or cannot be instantiated. 98 */ 99 public static AttributeCompilerFactory getFactory() 100 throws AttributeException { 101 102 // Identify the class loader we will be using 103 ClassLoader contextClassLoader = 104 ( 105 ClassLoader) AccessController 106 .doPrivileged(new PrivilegedAction() { 107 public Object run() { 108 ClassLoader cl = null; 109 try { 110 cl = getContextClassLoader(); 111 } catch (AttributeException e) { 112 e.printStackTrace(); 113 } finally { 114 return cl; 115 } 116 } 117 }); 118 119 // Return any previously registered factory for this class loader 120 AttributeCompilerFactory factory = getCachedFactory(contextClassLoader); 121 if (factory != null) { 122 return factory; 123 } 124 125 // Load properties file.. 126 // will be used one way or another in the end. (well maybe not now) 127 128 Properties props = null; 129 try { 130 InputStream stream = 131 (contextClassLoader == null 132 ? ClassLoader.getSystemResourceAsStream(FACTORY_PROPERTIES) 133 : contextClassLoader.getResourceAsStream(FACTORY_PROPERTIES)); 134 if (stream != null) { 135 props = new Properties(); 136 props.load(stream); 137 stream.close(); 138 } 139 } catch (IOException e) { 140 } catch (SecurityException e) { 141 } 142 143 // First, try the system property 144 try { 145 String factoryClass = System.getProperty(FACTORY_PROPERTY); 146 if (factoryClass != null) { 147 factory = newFactory(factoryClass, contextClassLoader); 148 } 149 } catch (SecurityException e) { 150 ; // ignore 151 } 152 153 // Second, try to find a service by using the JDK1.3 jar 154 // discovery mechanism. This will allow users to plug a logger 155 // by just placing it in the lib/ directory of the webapp ( or in 156 // CLASSPATH or equivalent ). This is similar with the second 157 // step, except that it uses the (standard?) jdk1.3 location in the jar. 158 159 if (factory == null) { 160 try { 161 InputStream is = 162 (contextClassLoader == null 163 ? ClassLoader.getSystemResourceAsStream(SERVICE_ID) 164 : contextClassLoader.getResourceAsStream(SERVICE_ID)); 165 166 if (is != null) { 167 // This code is needed by EBCDIC and other strange systems. 168 // It's a fix for bugs reported in xerces 169 BufferedReader rd; 170 try { 171 rd = 172 new BufferedReader( 173 new InputStreamReader(is, "UTF-8")); 174 } catch (java.io.UnsupportedEncodingException e) { 175 rd = new BufferedReader(new InputStreamReader(is)); 176 } 177 178 String factoryClassName = rd.readLine(); 179 rd.close(); 180 181 if (factoryClassName != null 182 && !"".equals(factoryClassName)) { 183 184 factory = 185 newFactory(factoryClassName, contextClassLoader); 186 } 187 } 188 } catch (Exception ex) { 189 ; 190 } 191 } 192 193 // Third try a properties file. 194 // If the properties file exists, it'll be read and the properties 195 // used. IMHO ( costin ) System property and JDK1.3 jar service 196 // should be enough for detecting the class name. The properties 197 // should be used to set the attributes ( which may be specific to 198 // the webapp, even if a default logger is set at JVM level by a 199 // system property ) 200 201 if (factory == null && props != null) { 202 String factoryClass = props.getProperty(FACTORY_PROPERTY); 203 if (factoryClass != null) { 204 factory = newFactory(factoryClass, contextClassLoader); 205 } 206 } 207 208 // Fourth, try the fallback implementation class 209 210 if (factory == null) { 211 Log.debug( 212 "AttributeCompilerFactory", 213 "using default factory: " + FACTORY_DEFAULT); 214 factory = 215 newFactory( 216 FACTORY_DEFAULT, 217 AttributeCompilerFactory.class.getClassLoader()); 218 } 219 220 if (factory != null) { 221 /*** 222 * Always cache using context class loader.. 223 */ 224 cacheFactory(contextClassLoader, factory); 225 226 /* TODO MLP not saving properties from attrib4j.properties 227 with the AttributeCompilerFactory - yet. 228 if( props!=null ) { 229 Enumeration names = props.propertyNames(); 230 while (names.hasMoreElements()) { 231 String name = (String) names.nextElement(); 232 String value = props.getProperty(name); 233 factory.setAttribute(name, value); 234 } 235 } 236 */ 237 } 238 239 return factory; 240 } 241 242 /*** 243 * Method to return a {@link AttributeCompiler}. 244 * 245 * @exception AttributeException if a suitable <code>AttributeCompiler</code> 246 * instance cannot be returned 247 */ 248 public abstract AttributeCompiler getAttributeCompiler() 249 throws AttributeException; 250 251 // ------------------------------------------------------ Protected Methods 252 253 /*** 254 * Return the thread context class loader if available. 255 * Otherwise return null. 256 * 257 * The thread context class loader is available for JDK 1.2 258 * or later, if certain security conditions are met. 259 * 260 * @exception AttributeException if a suitable class loader 261 * cannot be identified. 262 */ 263 protected static ClassLoader getContextClassLoader() 264 throws AttributeException { 265 ClassLoader classLoader = null; 266 267 try { 268 // Are we running on a JDK 1.2 or later system? 269 Method method = 270 Thread.class.getMethod("getContextClassLoader", null); 271 272 // Get the thread context class loader (if there is one) 273 try { 274 classLoader = 275 (ClassLoader) method.invoke(Thread.currentThread(), null); 276 } catch (IllegalAccessException e) { 277 throw new AttributeException( 278 "Unexpected IllegalAccessException", 279 e); 280 } catch (InvocationTargetException e) { 281 /*** 282 * InvocationTargetException is thrown by 'invoke' when 283 * the method being invoked (getContextClassLoader) throws 284 * an exception. 285 * 286 * getContextClassLoader() throws SecurityException when 287 * the context class loader isn't an ancestor of the 288 * calling class's class loader, or if security 289 * permissions are restricted. 290 * 291 * In the first case (not related), we want to ignore and 292 * keep going. We cannot help but also ignore the second 293 * with the logic below, but other calls elsewhere (to 294 * obtain a class loader) will trigger this exception where 295 * we can make a distinction. 296 */ 297 if (e.getTargetException() instanceof SecurityException) { 298 ; // ignore 299 } else { 300 // Capture 'e.getTargetException()' exception for details 301 // alternate: log 'e.getTargetException()', and pass back 'e'. 302 throw new AttributeException( 303 "Unexpected InvocationTargetException", 304 e.getTargetException()); 305 } 306 } 307 } catch (NoSuchMethodException e) { 308 // Assume we are running on JDK 1.1 309 classLoader = AttributeCompilerFactory.class.getClassLoader(); 310 } 311 312 // Return the selected class loader 313 return classLoader; 314 } 315 316 /*** 317 * Check cached factories (keyed by classLoader) 318 */ 319 private static AttributeCompilerFactory getCachedFactory(ClassLoader contextClassLoader) { 320 AttributeCompilerFactory factory = null; 321 322 if (contextClassLoader != null) { 323 factory = 324 (AttributeCompilerFactory) factories.get(contextClassLoader); 325 } 326 327 return factory; 328 } 329 330 private static void cacheFactory( 331 ClassLoader classLoader, 332 AttributeCompilerFactory factory) { 333 if (classLoader != null && factory != null) { 334 factories.put(classLoader, factory); 335 } 336 } 337 338 /*** 339 * Return a new instance of the specified <code>AttributeCompilerFactory</code> 340 * implementation class, loaded by the specified class loader. 341 * If that fails, try the class loader used to load this 342 * (abstract) AttributeCompilerFactory. 343 * 344 * @param factoryClass Fully qualified name of the 345 * <code>AttributeCompilerFactory</code> implementation class 346 * @param classLoader ClassLoader from which to load this class 347 * 348 * @exception AttributeException if a suitable instance 349 * cannot be created 350 */ 351 protected static AttributeCompilerFactory newFactory( 352 String factoryClass, 353 ClassLoader classLoader) 354 throws AttributeException { 355 356 try { 357 if (classLoader != null) { 358 try { 359 // first the given class loader param (thread class loader) 360 return (AttributeCompilerFactory) classLoader 361 .loadClass(factoryClass) 362 .newInstance(); 363 } catch (ClassNotFoundException ex) { 364 if (classLoader 365 == AttributeCompilerFactory.class.getClassLoader()) { 366 // Nothing more to try, onwards. 367 throw ex; 368 } 369 // ignore exception, continue 370 } catch (NoClassDefFoundError e) { 371 if (classLoader 372 == AttributeCompilerFactory.class.getClassLoader()) { 373 // Nothing more to try, onwards. 374 throw e; 375 } 376 // ignore exception, continue 377 } 378 } 379 380 /* At this point, either classLoader == null, OR 381 * classLoader was unable to load factoryClass.. 382 * try the class loader that loaded this class: 383 * AttributeCompilerFactory.getClassLoader(). 384 * 385 * Notes: 386 * a) AttributeCompilerFactory.class.getClassLoader() may return 'null' 387 * if AttributeCompilerFactory is loaded by the bootstrap classloader. 388 * b) The Java endorsed library mechanism is instead 389 * Class.forName(factoryClass); 390 */ 391 return (AttributeCompilerFactory) Class 392 .forName(factoryClass) 393 .newInstance(); 394 } catch (Exception e) { 395 throw new AttributeException(e); 396 } 397 } 398 }

This page was automatically generated by Maven