001 /* 002 // $Id: //open/mondrian/src/main/mondrian/util/ObjectFactory.java#10 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2007-2007 Julian Hyde and others 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.util; 011 012 import org.eigenbase.util.property.StringProperty; 013 import java.lang.reflect.Constructor; 014 import java.lang.reflect.InvocationHandler; 015 import java.lang.reflect.Proxy; 016 import java.util.Properties; 017 018 /** 019 * Concrete derived classes of the generic <code>ObjectFactory</code> class 020 * are used to produce an implementation of an interface (a 021 * normal interface implementation or a Proxy). In general, a 022 * factory should produce a default implementation for general application 023 * use as well as particular implementations used during testing. 024 * During testing of application code and during normal execution, 025 * the application code uses one of the <code>ObjectFactory</code>'s 026 * methods for producing implementation instances - the same method is 027 * used both for test and non-test modes. There are two ways of 028 * modifying the implementation returned to the application code. 029 * The first is for the application to use Properties. 030 * The <code>ObjectFactory</code> implementation looks for a given 031 * property (by default the name of the property is the class name 032 * of the interfaceClass object) and if found uses it as the classname 033 * to create. 034 * A second approach is to use a ThreadLocal; if the ThreadLocal 035 * is non-empty then use it as the classname. 036 * <p> 037 * When to use a Factory? 038 * <p> 039 * Everyone has an opinion. For me, there are two criteria: enabling 040 * unit testing and providing end-user/developer-customizer overriding. 041 * <p> 042 * If a method has side-effects, either its result depends upon 043 * a side-effect or calling it causes a side-effect, then the Object 044 * hosting the method is a candidate for having a factory. Why? 045 * Well, consider the case where a method returns the value of 046 * a System property and the System property is determined only once 047 * and set to a static final variable: 048 * <pre> 049 * class OneValue { 050 * private static final boolean propValue; 051 * static { 052 * propValue = Boolean.getBoolean("com.app.info.value"); 053 * } 054 * ..... 055 * public boolean hasInfo() { 056 * return propValue; 057 * } 058 * } 059 * </pre> 060 * <p> 061 * In this case, only one value is ever returned. If you have a 062 * module, a client of the above code, that uses the value returned 063 * by a call to the 064 * <code>hasInfo()</code> method, how do you write a unit test of 065 * your module that tests both possible return values? 066 * You can not, its value is based upon a side-effect, an external 067 * value that can not be controled by the unit test. 068 * If the <code>OneValue</code> class was an interface and there was a factory, 069 * then the unit test could arrange that its own version of the 070 * <code>OneValue</code> 071 * interface was returned and in one test arrange that <code>true</code> 072 * was returned and in a second test, arrange that <code>false</code> 073 * was returned. 074 * <p> 075 * The above is a trivial example of code that disallows clients of the 076 * code from being properly tested. 077 * <p> 078 * Another example might be a module that directly initializes a JMS 079 * queue and receives JMS message 080 * from the JMS queue. This code can not be tested without having a live 081 * JMS queue. On the other hand, if one defines an interface allowing 082 * one to wrap access to the JMS queue and accesses the implementation 083 * via a factory, then unit tests can be create that use a mock 084 * JMS queue. 085 * <p> 086 * With regards to providing end-user/developer-customizer overriding, 087 * its generally good to have a flexible application framework. 088 * Experimental or just different implementations can be developed and 089 * tested without having to touch a lot of the application code itself. 090 * <p> 091 * There is, of course, a trade-off between the use of a factory 092 * and the size or simplicity of the object being created. 093 * <p> 094 * What are the requirements for a template ObjectFactory? 095 * <p> 096 * First, every implementation must support the writing of unit tests. 097 * What this means it that test cases can override what the factory 098 * produces. The test cases can all use the same produced Object or 099 * each can request an Object targeted to its particular test. All this 100 * without changing the <code>default</code> behavior of the factory. 101 * <p> 102 * Next, it should be possible to create a factory from the template that 103 * is intended to deliver the same Object each time it is called, a 104 * different, new Object each time it is called, or, based on the 105 * calling environment (parameters, properties, <code>ThreadLocal</code>, 106 * etc.) one of a set of Objects. These are possible <code>default</code> 107 * behaviors, but, again, they can be overridden for test purposes. 108 * <p> 109 * While a factory has a <code>default</code> behavior in an 110 * application, it must be possible for every factory's behavior 111 * in that application to be globally overridden. What that means is 112 * if the application designer has dictated a <code>default</code>, the 113 * application user should be able to change the default. An example of 114 * this is overriding what Object is returned based upon a 115 * <code>System</code> property value. 116 * <p> 117 * Lastly, every factory is a singleton - if an interface with 118 * an implementation whose creation is mediated by a factory, then 119 * there is a single factory that does that creating. 120 * This does not mean that such a factory always return the same value, 121 * rather that there is only one instance of the factory itself. 122 * <p> 123 * The following is an example class that generates a factory 124 * singleton. In this case, the factory extends the 125 * <code>ObjectFactory</code> 126 * rather than the <code>ObjectFactory.Singleton</code>: 127 * <pre> 128 * 129 * public final class FooFactory extends ObjectFactory<Foo> { 130 * // The single instance of the factory 131 * private static final FooFactory factory; 132 * static { 133 * factory = new FooFactory(); 134 * } 135 * public static FooFactory instance() { 136 * return factory; 137 * } 138 * .......... 139 * private FooFactory() { 140 * super(Foo.class); 141 * } 142 * .......... 143 * } 144 * 145 * </pre> 146 * <p> 147 * There are multiple ways of creating derived classes that have support 148 * for unit testing. A very simple way is to use <code>ThreadLocal</code>s. 149 * 150 * <pre> 151 * 152 * private static final ThreadLocal ClassName = new ThreadLocal(); 153 * private static String getThreadLocalClassName() { 154 * return (String) ClassName.get(); 155 * } 156 * public static void setThreadLocalClassName(String className) { 157 * ClassName.set(className); 158 * } 159 * public static void clearThreadLocalClassName() { 160 * ClassName.set(null); 161 * } 162 * .......... 163 * protected String getClassName() { 164 * return getThreadLocalClassName(); 165 * } 166 * 167 * </pre> 168 * <p> 169 * Here, the unit test will call the <code>setThreadLocalClassName</code> 170 * method setting it with the class name of a specialized implemetation of 171 * the template interface. In the <code>finally</code> clause of the 172 * unit test, it is very important that there be a call to the 173 * <code>clearThreadLocalClassName</code> method so that other 174 * tests, etc. do not get an instance of the test-specific specialized 175 * implementation. 176 * <p> 177 * The following is an example unit test that uses the factory's 178 * <code>ThreadLocal</code> to override the implementation that is returned. 179 * 180 * <pre> 181 * interface Boo { 182 * boolean getValue(); 183 * ....... 184 * } 185 * class NormalBooImpl implements Boo { 186 * public boolean getValue() { ... } 187 * ....... 188 * } 189 * class MyCode { 190 * private Boo boo; 191 * MyCode() { 192 * boo = BooFactory.instance().getObject(); 193 * } 194 * ....... 195 * int getValue() { 196 * if (boo.getValue()) { 197 * return 1; 198 * } else { 199 * return 0; 200 * } 201 * 202 * } 203 * } 204 * 205 * class MyCodeTest { 206 * private static boolean testValue; 207 * static class BooTest1 implements Boo { 208 * public boolean getValue() { 209 * return MyTest.testValue; 210 * } 211 * ..... 212 * } 213 * static class BooTest2 implements 214 * java.lang.reflect.InvocationHandler { 215 * private final Boo boo; 216 * public BooTest2() { 217 * // remove test class name 218 * BooFactory.clearThreadLocalClassName(); 219 * // get default Boo implementation 220 * this.boo = BooFactory.instance().getObject(); 221 * } 222 * public Object invoke(Object proxy, Method method, Object[] args) 223 * throws Throwable { 224 * if (method.getName().equals("getValue")) [ 225 * return new Boolean(MyTest.testValue); 226 * } else { 227 * return method.invoke(this.boo, args); 228 * } 229 * } 230 * } 231 * public void test1() { 232 * try { 233 * // Factory will creates test class 234 * BooFactory.setThreadLocalClassName("MyTest.BooTest1"); 235 * 236 * MyTest.testValue = true; 237 * MyCode myCode = new MyCode(); 238 * int value = myCode.getValue(); 239 * assertTrue("Value not 1", (value == 1)); 240 * 241 * MyTest.testValue = false; 242 * myCode = new MyCode(); 243 * value = myCode.getValue(); 244 * assertTrue("Value not 0", (value == 0)); 245 * } finally { 246 * BooFactory.clearThreadLocalClassName(); 247 * } 248 * } 249 * public void test2() { 250 * try { 251 * // Use InvocationHandler and Factory Proxy capability 252 * BooFactory.setThreadLocalClassName("MyTest.BooTest2"); 253 * 254 * MyTest.testValue = true; 255 * MyCode myCode = new MyCode(); 256 * int value = myCode.getValue(); 257 * assertTrue("Value not 1", (value == 1)); 258 * 259 * MyTest.testValue = false; 260 * myCode = new MyCode(); 261 * value = myCode.getValue(); 262 * assertTrue("Value not 0", (value == 0)); 263 * } finally { 264 * BooFactory.clearThreadLocalClassName(); 265 * } 266 * } 267 * } 268 * 269 * </pre> 270 * <p> 271 * While this is a very simple example, it shows how using such factories 272 * can aid in creating testable code. The MyCode method is a client of 273 * the Boo implementation. How to test the two different code branches the 274 * method can take? Because the Boo object is generated by a factory, 275 * one can override what object the factory returns. 276 * 277 * @author Richard M. Emberson 278 * @since Feb 01 2007 279 * @version $Id: //open/mondrian/src/main/mondrian/util/ObjectFactory.java#10 $ 280 */ 281 public abstract class ObjectFactory<V> { 282 283 private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; 284 private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; 285 286 /** 287 * The type of the object to be generated. 288 */ 289 private final Class<V> interfaceClass; 290 291 /** 292 * Creates a new factory object. The <code>interfaceClass</code> parameter 293 * is used to cast the object generated to type right type. 294 * 295 * @param interfaceClass the class object for the interface implemented 296 * by the objects returned by this factory 297 * 298 */ 299 protected ObjectFactory(final Class<V> interfaceClass) { 300 this.interfaceClass = interfaceClass; 301 } 302 303 /** 304 * Constructs an object where the System Properties can be used 305 * to look up a class name. 306 * The constructor for the object takes no parameters. 307 * 308 * @return the newly created object 309 * @throws CreationException if unable to create the object 310 */ 311 protected final V getObject() throws CreationException { 312 return getObject(System.getProperties()); 313 } 314 315 /** 316 * Constructs an object where the <code>Properties</code> parameter can 317 * be used to look up a class name. 318 * The constructor for the object takes no parameters. 319 * 320 * @param props the property definitions to use to determine the 321 * implementation class 322 * 323 * @return the newly created object 324 * @throws CreationException if unable to create the object 325 */ 326 protected final V getObject(final Properties props) throws CreationException { 327 return getObject(props, EMPTY_CLASS_ARRAY, EMPTY_OBJECT_ARRAY); 328 } 329 330 /** 331 * Constructs an object where the <code>parameterTypes</code> and 332 * <code>parameterValues</code> are constructor parameters and 333 * System Properties are used to look up a class name. 334 * 335 * @param parameterTypes the class parameters that define the signature 336 * of the constructor to use 337 * @param parameterValues the values to use to construct the current 338 * instance of the object 339 * @return the newly created object 340 * @throws CreationException if unable to create the object 341 */ 342 protected final V getObject(final Class[] parameterTypes, 343 final Object[] parameterValues) 344 throws CreationException { 345 return getObject(System.getProperties(), 346 parameterTypes, 347 parameterValues); 348 } 349 350 /** 351 * Constructs an object where the <code>parameterTypes</code> and 352 * <code>parameterValues</code> are constructor parameters and 353 * Properties parameter is used to look up a class name. 354 * <p> 355 * This returns a new instance of the Object each time its 356 * called (assuming that if the method <code>getDefault</code>, 357 * which derived classes implement), if called, creates a new 358 * object each time. 359 * 360 * @param props the property definitions to use to determine the 361 * @param parameterTypes the class parameters that define the signature 362 * of the constructor to use 363 * @param parameterValues the values to use to construct the current 364 * instance of the object 365 * @return the newly created object 366 * @throws CreationException if unable to create the object 367 */ 368 protected V getObject(final Properties props, 369 final Class[] parameterTypes, 370 final Object[] parameterValues) 371 throws CreationException { 372 373 // Unit test override 374 final String className = getClassName(); 375 if (className != null) { 376 return getObject(className, parameterTypes, parameterValues); 377 } 378 379 final String propClassName = getClassName(props); 380 return (propClassName != null) 381 // User overriding application default 382 ? getObject(propClassName, parameterTypes, parameterValues) 383 // Get application default 384 : getDefault(parameterTypes, parameterValues); 385 } 386 387 /** 388 * Creates an instance with the given <code>className</code>, 389 * <code>parameterTypes</code> and <code>parameterValues</code> or 390 * throw a <code>CreationException</code>. There are two different 391 * mechanims available. The first is to uses reflection 392 * to create the instance typing the generated Object based upon 393 * the <code>interfaceClass</code> factory instance object. 394 * With the second the <code>className</code> is an class that implements 395 * the <code>InvocationHandler</code> interface and in this case 396 * the <code>java.lang.reflect.Proxy</code> class is used to 397 * generate a proxy. 398 * 399 * @param className the class name used to create Object instance 400 * @param parameterTypes the class parameters that define the signature 401 * of the constructor to use 402 * @param parameterValues the values to use to construct the current 403 * instance of the object 404 * @return the newly created object 405 * @throws CreationException if unable to create the object 406 */ 407 protected V getObject(final String className, 408 final Class[] parameterTypes, 409 final Object[] parameterValues) 410 throws CreationException { 411 try { 412 // As a place to begin google: 413 // org.apache.cxf.BusFactoryHelper.java 414 final ClassLoader loader = 415 Thread.currentThread().getContextClassLoader(); 416 final Class<?> genericClass = 417 Class.forName(className, true, loader); 418 419 // Are we creating a Proxy or an instance? 420 if (InvocationHandler.class.isAssignableFrom(genericClass)) { 421 final Constructor constructor = 422 genericClass.getConstructor(parameterTypes); 423 InvocationHandler handler = (InvocationHandler) 424 constructor.newInstance(parameterValues); 425 return (V) Proxy.newProxyInstance( 426 loader, 427 new Class[] { this.interfaceClass }, 428 handler); 429 } else { 430 final Class<? extends V> specificClass = 431 asSubclass(this.interfaceClass, genericClass); 432 final Constructor<? extends V> constructor = 433 specificClass.getConstructor(parameterTypes); 434 435 return constructor.newInstance(parameterValues); 436 } 437 438 } catch (Exception exc) { 439 throw new CreationException("Error creating object of type \"" + 440 this.interfaceClass.getName() + "\"" , exc); 441 } 442 } 443 444 /** 445 * This is a back port of a 1.5 version Class method. 446 * 447 * @param clazz the base class which the genericClass will be case 448 * @param genericClass the class to be cast to the base clazz 449 * @return this <tt>Class</tt> object, cast to represent a subclass of 450 * the specified class object. 451 * @throws ClassCastException if this <tt>Class</tt> object does 452 * not represent a subclass of the specified class (here "subclass" 453 * includes the class itself). 454 */ 455 private static <V> Class<? extends V> asSubclass(final Class<V> clazz, 456 final Class<?> genericClass) { 457 if (clazz.isAssignableFrom(genericClass)) { 458 return (Class<? extends V>) genericClass; 459 } else { 460 throw new ClassCastException(genericClass.toString()); 461 } 462 } 463 464 /** 465 * Returns the name of a class to use to create an object. 466 * The default implementation returns null but derived 467 * classes can return a class name. 468 * <p> 469 * This method is the primary mechanism for supporting Unit testing. 470 * A derived class can have, as an example, this method return 471 * the value of a <code>ThreadLocal</code>. For testing it 472 * return a class name while for normal use it returns <code>null</code>. 473 * 474 * @return <code>null</code> or a class name 475 */ 476 protected String getClassName() { 477 return null; 478 } 479 480 /** 481 * Returns the name of a class to use to create an object. 482 * The factory's <code>StringProperty</code> is gotten and 483 * if it has a non-null value, then that is returned. Otherwise, 484 * the <code>StringProperty</code>'s name (path) is used as the 485 * name to probe the <code>Properties</code> object for a value. 486 * This method is allowed to return null. 487 * 488 * @return <code>null</code> or a class name 489 */ 490 protected String getClassName(final Properties props) { 491 final StringProperty stringProp = getStringProperty(); 492 final String className = stringProp.get(); 493 return (className != null) 494 ? className 495 : (props == null) 496 ? null : props.getProperty(stringProp.getPath()); 497 } 498 499 /** 500 * Return the <code>StringProperty</code> associated with this factory. 501 * 502 * @return the <code>StringProperty</code> 503 */ 504 protected abstract StringProperty getStringProperty(); 505 506 /** 507 * For most uses (other than testing) this is the method that derived 508 * classes implement that return the desired object. 509 * 510 * @param parameterTypes the class parameters that define the signature 511 * of the constructor to use 512 * @param parameterValues the values to use to construct the current 513 * instance of the object 514 * @return the newly created object 515 * @throws CreationException if unable to create the object 516 */ 517 protected abstract V getDefault(Class[] parameterTypes, 518 Object[] parameterValues) 519 throws CreationException; 520 521 /** 522 * Factory method which creates an exception to be thrown 523 * if an object can not be created. 524 * 525 * @return an exception to be thrown if an object can not be created 526 */ 527 // REVIEW: jhyde, 2007/2/4: CreationException is superfluous, since it's 528 // unlikely that anyone will want to handle it. This code should wrap the 529 // error using Util.newError, just like elsewhere in mondrian. 530 protected CreationException defaultCreationException() { 531 return new CreationException("Error creating object of type \"" + 532 this.interfaceClass.getName() + "\""); 533 } 534 535 /** 536 * Get the current override values in the opaque context object and 537 * clear those values within the Factory. 538 * <p> 539 * This is used in testing. 540 * 541 * @return the test <code>Context</code> object. 542 */ 543 public Object removeContext() { 544 return null; 545 } 546 547 /** 548 * Restore the context object resetting override values. 549 * <p> 550 * This is used in testing. 551 * 552 * @param context the context object to be restored. 553 */ 554 public void restoreContext(final Object context) { 555 // empty 556 } 557 558 559 /** 560 * Implementation of ObjectFactory 561 * that returns only a single instance of the Object. 562 */ 563 public abstract static class Singleton<T> extends ObjectFactory<T> { 564 565 /** 566 * The single instance of the object created by the factory. 567 */ 568 protected T singleInstance; 569 570 /** 571 * The test single instance of the object created by the factory. 572 * Creating this <code>testSingleInstance</code> does not change the 573 * current value of the <code>singleInstance</code> variable. 574 */ 575 protected T testSingleInstance; 576 577 /** 578 * Creates a new singleton factory object. The 579 * <code>interfaceClass</code> parameter 580 * is used to cast the object generated to type right type. 581 * 582 * @param interfaceClass the class object for the interface implemented 583 * by the objects returned by this factory 584 */ 585 protected Singleton(final Class<T> interfaceClass) { 586 super(interfaceClass); 587 } 588 589 /** 590 * Returns the singleton Object. 591 * The first time this is called, an object is created where 592 * the <code>parameterTypes</code> and 593 * <code>parameterValues</code> are constructor parameters and 594 * Properties parameter is used to look up a class name. 595 * <p> 596 * This returns a same instance of the Object each time its 597 * called except if the <code>getClassName</code> method 598 * returns a non-null class name which should only 599 * happen as needed for unit testing. 600 * 601 * @param props the property definitions to use to determine the 602 * @param parameterTypes the class parameters that define the signature 603 * of the constructor to use 604 * @param parameterValues the values to use to construct the current 605 * instance of the object 606 * @return the newly created object 607 * @throws CreationException if unable to create the object 608 */ 609 protected T getObject(final Properties props, 610 final Class[] parameterTypes, 611 final Object[] parameterValues) 612 throws CreationException { 613 614 // Unit test override, do not use application instance. 615 final String className = getClassName(); 616 if (className != null) { 617 if (this.testSingleInstance == null) { 618 this.testSingleInstance = getTestObject(className, 619 parameterTypes, 620 parameterValues); 621 } 622 return this.testSingleInstance; 623 } 624 625 // NOTE: Should we distinguish between any Properties Object 626 // and that returned by System? When its the System's 627 // Properties Object (which is not a final instance variable 628 // within the System class), then its for sure the user 629 // providing a global override. If its not the System 630 // Properties object, then it may or may not be a global 631 // override so we may not want to set the singleInstance 632 // to it. For now I am ignoring the issue. 633 if (this.singleInstance == null) { 634 final String propClassName = getClassName(props); 635 636 this.singleInstance = (propClassName != null) 637 // The user overriding application default 638 ? getObject(propClassName, parameterTypes, parameterValues) 639 // Get application default 640 : getDefault(parameterTypes, parameterValues); 641 642 } 643 return this.singleInstance; 644 } 645 646 /** 647 * Create an instance for test purposes. 648 * 649 * @param className the class name used to create Object instance 650 * @param parameterTypes the class parameters that define the signature 651 * of the constructor to use 652 * @param parameterValues the values to use to construct the current 653 * instance of the object 654 * @return the newly created object 655 * @throws CreationException if unable to create the object 656 */ 657 protected T getTestObject(final String className, 658 final Class[] parameterTypes, 659 final Object[] parameterValues) 660 throws CreationException { 661 return getObject(className, parameterTypes, parameterValues); 662 } 663 } 664 665 /** 666 * This is for testing only. 667 * <p> 668 * <code>Context</code> contain the Factory implementation specific 669 * non-default values and mechanism for overriding the default 670 * instance type returned by the Factory. 671 * Factory implementation can extend the <code>Context</code> interface 672 * to capture its specific override values. 673 * If, for example, a Factory implementation uses a <code>ThreadLocal</code> 674 * to override the default instance type for unit tests, then the 675 * <code>Context</code> 676 * will hold the current value of the <code>ThreadLocal</code>. 677 * Getting the Context, clears the <code>ThreadLocal</code> value. 678 * This allows the tester who wishes to create code that will provide 679 * a wrapper around the default instance type to register their 680 * wrapper class name with the <code>ThreadLocal</code>, and, within 681 * the wrapper constructor, get the <code>Context</code>, get 682 * a default instance, and then restore the <code>Context</code>. 683 */ 684 public interface Context { 685 } 686 } 687 688 // End ObjectFactory.java