View Javadoc
1 package org.apache.turbine.services.factory; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Turbine" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache Turbine", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>;. 55 */ 56 57 import java.io.ByteArrayInputStream; 58 import java.io.ByteArrayOutputStream; 59 import java.io.ObjectOutputStream; 60 import java.util.ArrayList; 61 import java.util.HashMap; 62 import java.util.Iterator; 63 import java.util.Vector; 64 import org.apache.commons.configuration.Configuration; 65 import org.apache.turbine.services.InitializationException; 66 import org.apache.turbine.services.TurbineBaseService; 67 import org.apache.turbine.util.TurbineException; 68 import org.apache.turbine.util.pool.ObjectInputStreamForContext; 69 70 /*** 71 * The Factory Service instantiates objects using specified 72 * class loaders. If none is specified, the default one 73 * will be used. 74 * 75 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a> 76 * @version $Id: TurbineFactoryService.java,v 1.4 2002/07/11 16:53:28 mpoeschl Exp $ 77 */ 78 public class TurbineFactoryService 79 extends TurbineBaseService 80 implements FactoryService 81 { 82 /*** 83 * The property specifying a set of additional class loaders. 84 */ 85 public static final String CLASS_LOADERS = "class.loaders"; 86 87 /*** 88 * The property prefix specifying additional object factories. 89 */ 90 public static final String OBJECT_FACTORY = "factory."; 91 92 /*** 93 * Primitive classes for reflection of constructors. 94 */ 95 private static HashMap primitiveClasses; 96 97 { 98 primitiveClasses = new HashMap(8); 99 primitiveClasses.put(Boolean.TYPE.toString(), Boolean.TYPE); 100 primitiveClasses.put(Character.TYPE.toString(), Character.TYPE); 101 primitiveClasses.put(Byte.TYPE.toString(), Byte.TYPE); 102 primitiveClasses.put(Short.TYPE.toString(), Short.TYPE); 103 primitiveClasses.put(Integer.TYPE.toString(), Integer.TYPE); 104 primitiveClasses.put(Long.TYPE.toString(), Long.TYPE); 105 primitiveClasses.put(Float.TYPE.toString(), Float.TYPE); 106 primitiveClasses.put(Double.TYPE.toString(), Double.TYPE); 107 } 108 109 /*** 110 * Additional class loaders. 111 */ 112 private ArrayList classLoaders = new ArrayList(); 113 114 /*** 115 * Customized object factories. 116 */ 117 private HashMap objectFactories = new HashMap(); 118 119 /*** 120 * Gets the class of a primitive type. 121 * 122 * @param type a primitive type. 123 * @return the corresponding class, or null. 124 */ 125 protected static Class getPrimitiveClass(String type) 126 { 127 return (Class) primitiveClasses.get(type); 128 } 129 130 /*** 131 * Constructs a Factory Service. 132 */ 133 public TurbineFactoryService() 134 { 135 } 136 137 /*** 138 * Initializes the service by loading default class loaders 139 * and customized object factories. 140 * 141 * @throws InitializationException if initialization fails. 142 */ 143 public void init() throws InitializationException 144 { 145 Configuration conf = getConfiguration(); 146 if (conf != null) 147 { 148 Vector loaders = conf.getVector(CLASS_LOADERS); 149 if (loaders != null) 150 { 151 for (int i = 0; i < loaders.size(); i++) 152 { 153 try 154 { 155 classLoaders.add( 156 loadClass((String) loaders.get(i)).newInstance()); 157 } 158 catch (Exception x) 159 { 160 throw new InitializationException( 161 "No such class loader '" + 162 (String) loaders.get(i) + 163 "' for TurbinbeFactoryService",x); 164 } 165 } 166 } 167 168 String key,factory; 169 for (Iterator i = conf.getKeys(OBJECT_FACTORY); i.hasNext();) 170 { 171 key = (String) i.next(); 172 factory = conf.getString(key); 173 174 /* 175 * Store the factory to the table as a string and 176 * instantiate it by using the service when needed. 177 */ 178 objectFactories.put( 179 key.substring(OBJECT_FACTORY.length()),factory); 180 } 181 } 182 setInit(true); 183 } 184 185 /*** 186 * Gets an instance of a named class. 187 * 188 * @param className the name of the class. 189 * @return the instance. 190 * @throws TurbineException if instantiation fails. 191 */ 192 public Object getInstance(String className) 193 throws TurbineException 194 { 195 if (className == null) 196 { 197 throw new TurbineException( 198 new NullPointerException("String className")); 199 } 200 201 Factory factory = getFactory(className); 202 if (factory == null) 203 { 204 Class clazz; 205 try 206 { 207 clazz = loadClass(className); 208 } 209 catch (ClassNotFoundException x) 210 { 211 throw new TurbineException( 212 "Instantiation failed for class " + className,x); 213 } 214 return getInstance(clazz); 215 } 216 else 217 { 218 return factory.getInstance(); 219 } 220 } 221 222 /*** 223 * Gets an instance of a named class using a specified class loader. 224 * 225 * <p>Class loaders are supported only if the isLoaderSupported 226 * method returns true. Otherwise the loader parameter is ignored. 227 * 228 * @param className the name of the class. 229 * @param loader the class loader. 230 * @return the instance. 231 * @throws TurbineException if instantiation fails. 232 */ 233 public Object getInstance(String className, 234 ClassLoader loader) 235 throws TurbineException 236 { 237 if (className == null) 238 { 239 throw new TurbineException( 240 new NullPointerException("String className")); 241 } 242 243 Factory factory = getFactory(className); 244 if (factory == null) 245 { 246 if (loader != null) 247 { 248 Class clazz; 249 try 250 { 251 clazz = loadClass(className,loader); 252 } 253 catch (ClassNotFoundException x) 254 { 255 throw new TurbineException( 256 "Instantiation failed for class " + className,x); 257 } 258 return getInstance(clazz); 259 } 260 else 261 { 262 return getInstance(className); 263 } 264 } 265 else 266 { 267 return factory.getInstance(loader); 268 } 269 } 270 271 /*** 272 * Gets an instance of a named class. 273 * Parameters for its constructor are given as an array of objects, 274 * primitive types must be wrapped with a corresponding class. 275 * 276 * @param className the name of the class. 277 * @param params an array containing the parameters of the constructor. 278 * @param signature an array containing the signature of the constructor. 279 * @return the instance. 280 * @throws TurbineException if instantiation fails. 281 */ 282 public Object getInstance(String className, 283 Object[] params, 284 String[] signature) 285 throws TurbineException 286 { 287 if (className == null) 288 { 289 throw new TurbineException( 290 new NullPointerException("String className")); 291 } 292 293 Factory factory = getFactory(className); 294 if (factory == null) 295 { 296 Class clazz; 297 try 298 { 299 clazz = loadClass(className); 300 } 301 catch (ClassNotFoundException x) 302 { 303 throw new TurbineException( 304 "Instantiation failed for class " + className,x); 305 } 306 return getInstance(clazz,params,signature); 307 } 308 else 309 { 310 return factory.getInstance(params,signature); 311 } 312 } 313 314 /*** 315 * Gets an instance of a named class using a specified class loader. 316 * Parameters for its constructor are given as an array of objects, 317 * primitive types must be wrapped with a corresponding class. 318 * 319 * <p>Class loaders are supported only if the isLoaderSupported 320 * method returns true. Otherwise the loader parameter is ignored. 321 * 322 * @param className the name of the class. 323 * @param loader the class loader. 324 * @param params an array containing the parameters of the constructor. 325 * @param signature an array containing the signature of the constructor. 326 * @return the instance. 327 * @throws TurbineException if instantiation fails. 328 */ 329 public Object getInstance(String className, 330 ClassLoader loader, 331 Object[] params, 332 String[] signature) 333 throws TurbineException 334 { 335 if (className == null) 336 { 337 throw new TurbineException( 338 new NullPointerException("String className")); 339 } 340 341 Factory factory = getFactory(className); 342 if (factory == null) 343 { 344 if (loader != null) 345 { 346 Class clazz; 347 try 348 { 349 clazz = loadClass(className,loader); 350 } 351 catch (ClassNotFoundException x) 352 { 353 throw new TurbineException( 354 "Instantiation failed for class " + className,x); 355 } 356 return getInstance(clazz,params,signature); 357 } 358 else 359 { 360 return getInstance(className,params,signature); 361 } 362 } 363 else 364 { 365 return factory.getInstance(loader,params,signature); 366 } 367 } 368 369 /*** 370 * Tests if specified class loaders are supported for a named class. 371 * 372 * @param className the name of the class. 373 * @return true if class loaders are supported, false otherwise. 374 * @throws TurbineException if test fails. 375 */ 376 public boolean isLoaderSupported(String className) 377 throws TurbineException 378 { 379 Factory factory = getFactory(className); 380 return factory != null ? 381 factory.isLoaderSupported() : true; 382 } 383 384 /*** 385 * Gets an instance of a specified class. 386 * 387 * @param clazz the class. 388 * @return the instance. 389 * @throws TurbineException if instantiation fails. 390 */ 391 protected Object getInstance(Class clazz) 392 throws TurbineException 393 { 394 try 395 { 396 return clazz.newInstance(); 397 } 398 catch (Exception x) 399 { 400 throw new TurbineException( 401 "Instantiation failed for " + clazz.getName(),x); 402 } 403 } 404 405 /*** 406 * Gets an instance of a specified class. 407 * Parameters for its constructor are given as an array of objects, 408 * primitive types must be wrapped with a corresponding class. 409 * 410 * @param clazz the class. 411 * @param params an array containing the parameters of the constructor. 412 * @param signature an array containing the signature of the constructor. 413 * @return the instance. 414 * @throws TurbineException if instantiation fails. 415 */ 416 protected Object getInstance(Class clazz, 417 Object params[], 418 String signature[]) 419 throws TurbineException 420 { 421 /* Try to construct. */ 422 try 423 { 424 Class[] sign = getSignature(clazz,params,signature); 425 return clazz.getConstructor(sign).newInstance(params); 426 } 427 catch (Exception x) 428 { 429 throw new TurbineException( 430 "Instantiation failed for " + clazz.getName(),x); 431 } 432 } 433 434 /*** 435 * Gets the signature classes for parameters of a method of a class. 436 * 437 * @param clazz the class. 438 * @param params an array containing the parameters of the method. 439 * @param signature an array containing the signature of the method. 440 * @return an array of signature classes. Note that in some cases 441 * objects in the parameter array can be switched to the context 442 * of a different class loader. 443 * @throws ClassNotFoundException if any of the classes is not found. 444 */ 445 protected Class[] getSignature(Class clazz, 446 Object params[], 447 String signature[]) 448 throws ClassNotFoundException 449 { 450 if (signature != null) 451 { 452 /* We have parameters. */ 453 ClassLoader tempLoader; 454 ClassLoader loader = clazz.getClassLoader(); 455 Class[] sign = new Class[signature.length]; 456 for (int i= 0; i < signature.length; i++) 457 { 458 /* Check primitive types. */ 459 sign[i] = getPrimitiveClass(signature[i]); 460 if (sign[i] == null) 461 { 462 /* Not a primitive one, continue building. */ 463 if (loader != null) 464 { 465 /* Use the class loader of the target object. */ 466 sign[i] = loader.loadClass(signature[i]); 467 tempLoader = sign[i].getClassLoader(); 468 if ((params[i] != null) && 469 (tempLoader != null) && 470 !tempLoader.equals(params[i].getClass().getClassLoader())) 471 { 472 /* 473 * The class uses a different class loader, 474 * switch the parameter. 475 */ 476 params[i] = switchObjectContext(params[i],loader); 477 } 478 } 479 else 480 { 481 /* Use the default class loader. */ 482 sign[i] = loadClass(signature[i]); 483 } 484 } 485 } 486 return sign; 487 } 488 else 489 { 490 return null; 491 } 492 } 493 494 /*** 495 * Switches an object into the context of a different class loader. 496 * 497 * @param object an object to switch. 498 * @param loader the loader of the new context. 499 */ 500 protected Object switchObjectContext(Object object, 501 ClassLoader loader) 502 { 503 ByteArrayOutputStream bout = 504 new ByteArrayOutputStream(); 505 try 506 { 507 ObjectOutputStream out = 508 new ObjectOutputStream(bout); 509 out.writeObject(object); 510 out.flush(); 511 } 512 catch (Exception x) 513 { 514 return object; 515 } 516 517 try 518 { 519 ByteArrayInputStream bin = 520 new ByteArrayInputStream(bout.toByteArray()); 521 ObjectInputStreamForContext in = 522 new ObjectInputStreamForContext(bin,loader); 523 524 return in.readObject(); 525 } 526 catch (Exception x) 527 { 528 return object; 529 } 530 } 531 532 /*** 533 * Loads the named class using the default class loader. 534 * 535 * @param className the name of the class to load. 536 * @return the loaded class. 537 * @throws ClassNotFoundException if the class was not found. 538 */ 539 protected Class loadClass(String className) 540 throws ClassNotFoundException 541 { 542 ClassLoader loader = this.getClass().getClassLoader(); 543 try 544 { 545 return loader != null ? 546 loader.loadClass(className) : Class.forName(className); 547 } 548 catch (ClassNotFoundException x) 549 { 550 /* Go through additional loaders. */ 551 for (Iterator i = classLoaders.iterator(); i.hasNext();) 552 { 553 try 554 { 555 return ((ClassLoader) i.next()).loadClass(className); 556 } 557 catch (ClassNotFoundException xx) { } 558 } 559 560 /* Give up. */ 561 throw x; 562 } 563 } 564 565 /*** 566 * Loads the named class using a specified class loader. 567 * 568 * @param className the name of the class to load. 569 * @param loader the loader to use. 570 * @return the loaded class. 571 * @throws ClassNotFoundException if the class was not found. 572 */ 573 protected Class loadClass(String className, 574 ClassLoader loader) 575 throws ClassNotFoundException 576 { 577 return loader != null ? 578 loader.loadClass(className) : loadClass(className); 579 } 580 581 /*** 582 * Gets a customized factory for a named class. 583 * 584 * @param className the name of the class to load. 585 * @return the factory or null if not specified. 586 * @throws TurbineException if instantiation of the factory fails. 587 */ 588 protected Factory getFactory(String className) 589 throws TurbineException 590 { 591 HashMap factories = objectFactories; 592 Object factory = factories.get(className); 593 if (factory != null) 594 { 595 if (factory instanceof String) 596 { 597 /* Not yet instantiated... */ 598 try 599 { 600 factory = (Factory) getInstance((String) factory); 601 ((Factory) factory).init(className); 602 } 603 catch (TurbineException x) 604 { 605 throw x; 606 } 607 catch (ClassCastException x) 608 { 609 throw new TurbineException( 610 "Incorrect factory " + (String) factory + 611 " for class " + className,x); 612 } 613 factories = (HashMap) factories.clone(); 614 factories.put(className,factory); 615 objectFactories = factories; 616 } 617 return (Factory) factory; 618 } 619 else 620 { 621 return null; 622 } 623 } 624 }

This page was automatically generated by Maven