1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.jdtaus.core.container.ri.client;
22
23 import java.lang.reflect.Array;
24 import java.lang.reflect.Constructor;
25 import java.lang.reflect.InvocationTargetException;
26 import java.lang.reflect.Method;
27 import java.text.MessageFormat;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32 import java.util.logging.Level;
33 import java.util.logging.Logger;
34 import org.jdtaus.core.container.Container;
35 import org.jdtaus.core.container.ContainerError;
36 import org.jdtaus.core.container.ContainerInitializer;
37 import org.jdtaus.core.container.ContextFactory;
38 import org.jdtaus.core.container.ContextInitializer;
39 import org.jdtaus.core.container.Dependency;
40 import org.jdtaus.core.container.DependencyCycleException;
41 import org.jdtaus.core.container.Implementation;
42 import org.jdtaus.core.container.MissingImplementationException;
43 import org.jdtaus.core.container.Model;
44 import org.jdtaus.core.container.ModelFactory;
45 import org.jdtaus.core.container.MultiplicityConstraintException;
46 import org.jdtaus.core.container.Specification;
47 import org.jdtaus.core.container.ri.client.versioning.VersionParser;
48
49
50
51
52
53
54
55
56
57 public class DefaultContainer implements Container
58 {
59
60
61
62 private static final Class[] EMPTY =
63 {
64 };
65
66
67 private static final Class[] IMPL_CTOR =
68 {
69 Implementation.class
70 };
71
72
73 private static final Class[] DEP_CTOR =
74 {
75 Dependency.class
76 };
77
78
79 private static final Scope[] SCOPES =
80 {
81 null, new ContextScope(), new SingletonScope()
82 };
83
84
85
86
87
88 private final Object cycle = new Object();
89
90
91 private final Map objects = new WeakIdentityHashMap( 1024 );
92
93 public Object getObject( final Class specification )
94 {
95 if ( specification == null )
96 {
97 throw new NullPointerException( "specification" );
98 }
99
100 return this.getObjectInternal( this.getClassLoader( specification ),
101 specification.getName(), null, false );
102
103 }
104
105 public Object getObject( final Class specification,
106 final String implementationName )
107 {
108 if ( specification == null )
109 {
110 throw new NullPointerException( "specification" );
111 }
112 if ( implementationName == null )
113 {
114 throw new NullPointerException( "implementationName" );
115 }
116
117 return this.getObjectInternal( this.getClassLoader( specification ),
118 specification.getName(),
119 implementationName, true );
120
121 }
122
123 public Object getDependency( final Object object,
124 final String dependencyName )
125 {
126 if ( object == null )
127 {
128 throw new NullPointerException( "object" );
129 }
130 if ( dependencyName == null )
131 {
132 throw new NullPointerException( "dependencyName" );
133 }
134
135 try
136 {
137 final Implementation impl = this.getImplementation( object );
138 final Instance instance = this.getInstance( object, impl );
139
140 synchronized ( instance )
141 {
142 return this.getDependency(
143 instance.getClassLoader(), instance,
144 impl.getDependencies().getDependency( dependencyName ) );
145
146 }
147 }
148 catch ( final ClassNotFoundException e )
149 {
150 throw new ContainerError( e );
151 }
152 catch ( final NoSuchMethodException e )
153 {
154 throw new ContainerError( e );
155 }
156 catch ( final IllegalAccessException e )
157 {
158 throw new ContainerError( e );
159 }
160 catch ( final InvocationTargetException e )
161 {
162 throw new ContainerError( e );
163 }
164 }
165
166 public Object getProperty( final Object object,
167 final String propertyName )
168 {
169 if ( object == null )
170 {
171 throw new NullPointerException( "object" );
172 }
173 if ( propertyName == null )
174 {
175 throw new NullPointerException( "propertyName" );
176 }
177
178 return this.getInstance( object, this.getImplementation( object ) ).
179 getProperties().getProperty( propertyName ).getValue();
180
181 }
182
183 public String getMessage( final Object object, final String messageName,
184 final Locale locale, final Object arguments )
185 {
186 if ( object == null )
187 {
188 throw new NullPointerException( "object" );
189 }
190 if ( locale == null )
191 {
192 throw new NullPointerException( "locale" );
193 }
194 if ( messageName == null )
195 {
196 throw new NullPointerException( "messageName" );
197 }
198
199 return new MessageFormat(
200 this.getInstance( object, this.getImplementation( object ) ).
201 getMessages().getMessage( messageName ).getTemplate().
202 getValue( locale ), locale ).format( arguments );
203
204 }
205
206 public final Object getObject( final String specificationIdentifier )
207 {
208 return this.getObjectInternal( this.getClassLoader( this.getClass() ),
209 specificationIdentifier, null,
210 false );
211
212 }
213
214 public final Object getObject( final String specificationIdentifier,
215 final String implementationName )
216 {
217 return this.getObjectInternal( this.getClassLoader( this.getClass() ),
218 specificationIdentifier,
219 implementationName, true );
220
221 }
222
223 public final String getMessage( final Object object,
224 final String messageName,
225 final Object arguments )
226 {
227 if ( object == null )
228 {
229 throw new NullPointerException( "object" );
230 }
231 if ( messageName == null )
232 {
233 throw new NullPointerException( "messageName" );
234 }
235
236 return this.getMessage( object, messageName, Locale.getDefault(),
237 arguments );
238
239 }
240
241 public final Object getImplementation(
242 final Class specification, final String implementationName )
243 {
244 if ( specification == null )
245 {
246 throw new NullPointerException( "specification" );
247 }
248 if ( implementationName == null )
249 {
250 throw new NullPointerException( "implementationName" );
251 }
252
253 return this.getObject( specification, implementationName );
254 }
255
256 public final Object getDependency(
257 final Class implementation, final String dependencyName )
258 {
259 if ( implementation == null )
260 {
261 throw new NullPointerException( "implementation" );
262 }
263 if ( dependencyName == null )
264 {
265 throw new NullPointerException( "dependencyName" );
266 }
267
268 try
269 {
270 final Object dependencyObject = this.getDependency(
271 this.getClassLoader( implementation ), null,
272 ModelFactory.getModel().getModules().
273 getImplementation( implementation.getName() ).
274 getDependencies().getDependency( dependencyName ) );
275
276 this.initializeContext( dependencyObject );
277 return dependencyObject;
278 }
279 catch ( final ClassNotFoundException e )
280 {
281 throw new ContainerError( e );
282 }
283 catch ( final NoSuchMethodException e )
284 {
285 throw new ContainerError( e );
286 }
287 catch ( final IllegalAccessException e )
288 {
289 throw new ContainerError( e );
290 }
291 catch ( final InvocationTargetException e )
292 {
293 throw new ContainerError( e );
294 }
295 }
296
297
298
299
300
301 public DefaultContainer()
302 {
303 super();
304 }
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323 private Object instantiateImplementation( final ClassLoader classLoader,
324 final Implementation impl )
325 {
326 if ( classLoader == null )
327 {
328 throw new NullPointerException( "classLoader" );
329 }
330 if ( impl == null )
331 {
332 throw new NullPointerException( "impl" );
333 }
334
335 Constructor ctor = null;
336
337 try
338 {
339 final Class clazz = Class.forName( impl.getIdentifier(), true,
340 classLoader );
341
342 ctor = clazz.getDeclaredConstructor( IMPL_CTOR );
343 ctor.setAccessible( true );
344
345 final Object object = ctor.newInstance( new Object[]
346 {
347 impl
348 } );
349
350 return object;
351 }
352 catch ( final Throwable e )
353 {
354 throw new org.jdtaus.core.container.InstantiationException(
355 impl.getIdentifier(), e );
356
357 }
358 finally
359 {
360 if ( ctor != null )
361 {
362 ctor.setAccessible( false );
363 }
364 }
365 }
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384 private Object instantiateDependency( final ClassLoader classLoader,
385 final Dependency dep )
386 {
387 if ( classLoader == null )
388 {
389 throw new NullPointerException( "classLoader" );
390 }
391 if ( dep == null )
392 {
393 throw new NullPointerException( "dep" );
394 }
395
396 Constructor ctor = null;
397
398 try
399 {
400 final Class clazz = Class.forName( dep.getImplementation().
401 getIdentifier(), true, classLoader );
402
403 ctor = clazz.getDeclaredConstructor( DEP_CTOR );
404 ctor.setAccessible( true );
405
406 final Object object = ctor.newInstance( new Object[]
407 {
408 dep
409 } );
410
411 return object;
412 }
413 catch ( final Throwable e )
414 {
415 throw new org.jdtaus.core.container.InstantiationException(
416 dep.getImplementation().getIdentifier(), e );
417
418 }
419 finally
420 {
421 if ( ctor != null )
422 {
423 ctor.setAccessible( false );
424 }
425 }
426 }
427
428
429
430
431
432
433
434
435
436 private void initializeObject( final Object object ) throws Exception
437 {
438 if ( object == null )
439 {
440 throw new NullPointerException( "object" );
441 }
442
443 if ( object instanceof ContainerInitializer )
444 {
445 ( (ContainerInitializer) object ).initialize();
446 }
447 }
448
449
450
451
452
453
454
455
456
457
458 private void initializeContext( final Object object )
459 {
460 if ( object == null )
461 {
462 throw new NullPointerException( "object" );
463 }
464
465 if ( object instanceof ContextInitializer &&
466 !( (ContextInitializer) object ).isInitialized(
467 ContextFactory.getContext() ) )
468 {
469 ( (ContextInitializer) object ).initialize(
470 ContextFactory.getContext() );
471
472 }
473 }
474
475 private Object getObjectInternal( final ClassLoader classLoader,
476 final String specificationIdentifier,
477 final String implementationName,
478 final boolean implementationNameWarning )
479 {
480 if ( classLoader == null )
481 {
482 throw new NullPointerException( "classLoader" );
483 }
484 if ( specificationIdentifier == null )
485 {
486 throw new NullPointerException( "specificationIdentifier" );
487 }
488
489 try
490 {
491 final Object object;
492 final Specification specification = ModelFactory.getModel().
493 getModules().getSpecification( specificationIdentifier );
494
495 if ( implementationName != null )
496 {
497 final Class specClass =
498 Class.forName( specification.getIdentifier(), true,
499 classLoader );
500
501 final Implementation implementation =
502 specification.getImplementation( implementationName );
503
504 final Instance instance = new Instance(
505 classLoader, specification.getScope(),
506 implementation.getIdentifier(),
507 implementation.getModelVersion(),
508 implementation.getModuleName() );
509
510 instance.setImplementation( implementation );
511 object = this.requestImplementation(
512 specClass, specification, this.getObject( instance ) );
513
514 }
515 else
516 {
517 if ( implementationNameWarning )
518 {
519 final Throwable x = new Throwable();
520 final StackTraceElement[] elements = x.getStackTrace();
521
522 String cname = "unknown";
523 String method = "unknown";
524 StackTraceElement caller = null;
525
526 if ( elements != null && elements.length > 2 )
527 {
528 caller = elements[2];
529 cname = caller.getClassName();
530 method = caller.getMethodName();
531 }
532
533 Logger.getLogger( DefaultContainer.class.getName() ).
534 log( Level.SEVERE, DefaultContainerBundle.getInstance().
535 getNullImplementationNameWarningMessage(
536 Locale.getDefault(), specificationIdentifier, cname,
537 method ), x );
538
539 }
540
541 object = this.resolveImplementation( classLoader,
542 specification );
543
544 }
545
546 return object;
547 }
548 catch ( final IllegalAccessException e )
549 {
550
551 throw new AssertionError( e );
552 }
553 catch ( final InvocationTargetException e )
554 {
555 throw new ContainerError( e );
556 }
557 catch ( final NoSuchMethodException e )
558 {
559 throw new ContainerError( e );
560 }
561 catch ( final ClassNotFoundException e )
562 {
563 throw new ContainerError( e );
564 }
565 }
566
567 private Object getObject( final Instance instance )
568 {
569 return this.getScopedObject(
570 SCOPES[instance.getScope() - Specification.SCOPE_MULTITON],
571 instance );
572
573 }
574
575 private Object instantiateObject( final Instance instance )
576 {
577 try
578 {
579 Object object = null;
580
581 if ( VersionParser.compare( instance.getModelVersion(),
582 "1.3" ) < 0 )
583 {
584 if ( instance.getImplementation() != null )
585 {
586 object = this.instantiateImplementation(
587 instance.getClassLoader(),
588 instance.getImplementation() );
589
590 }
591 else if ( instance.getDependency() != null )
592 {
593 object = this.instantiateDependency(
594 instance.getClassLoader(),
595 instance.getDependency() );
596
597 }
598 else
599 {
600 throw new AssertionError();
601 }
602 }
603 else
604 {
605 final Class clazz = Class.forName(
606 instance.getClassName(), true, instance.getClassLoader() );
607
608 if ( Model.class.getName().equals( instance.getModuleName() ) )
609 {
610
611
612 final Method accessor =
613 clazz.getMethod( "getDefault", EMPTY );
614
615 object = accessor.invoke( null, EMPTY );
616 }
617 else
618 {
619 object = clazz.newInstance();
620 }
621 }
622
623 synchronized ( this.objects )
624 {
625 this.objects.put( object, instance );
626 }
627
628 this.initializeObject( object );
629 return object;
630 }
631 catch ( final Throwable t )
632 {
633 if ( t instanceof Error )
634 {
635 throw (Error) t;
636 }
637 else if ( t instanceof RuntimeException )
638 {
639 throw (RuntimeException) t;
640 }
641 else
642 {
643 throw new org.jdtaus.core.container.InstantiationException(
644 instance.getClassName(), t );
645
646 }
647 }
648 }
649
650 private Implementation getImplementation( final Object object )
651 {
652 MissingImplementationException exception = null;
653 Implementation implementation = null;
654 Class clazz = object.getClass();
655
656 do
657 {
658 try
659 {
660 implementation = ModelFactory.getModel().getModules().
661 getImplementation( clazz.getName() );
662
663 break;
664 }
665 catch ( final MissingImplementationException e )
666 {
667 if ( exception == null )
668 {
669 exception = e;
670 }
671 }
672 }
673 while ( ( clazz = clazz.getSuperclass() ) != null );
674
675 if ( implementation == null )
676 {
677 throw exception;
678 }
679
680 return implementation;
681 }
682
683 private Instance getInstance( final Object object,
684 final Implementation impl )
685 {
686 synchronized ( this.objects )
687 {
688 Instance instance = (Instance) this.objects.get( object );
689
690 if ( instance == null )
691 {
692 instance =
693 new Instance( this.getClassLoader( object.getClass() ),
694 Specification.SCOPE_MULTITON,
695 impl.getIdentifier(),
696 impl.getModelVersion(),
697 impl.getModuleName() );
698
699 instance.setImplementation( impl );
700 this.objects.put( object, instance );
701 }
702
703 return instance;
704 }
705 }
706
707 private Object getDependency( final ClassLoader classLoader,
708 final Instance instance,
709 final Dependency dependency )
710 throws ClassNotFoundException, NoSuchMethodException,
711 IllegalAccessException, InvocationTargetException
712 {
713 Object dependencyObject =
714 instance != null
715 ? instance.getDependencyObject( dependency.getName() )
716 : null;
717
718 if ( dependencyObject == null )
719 {
720 if ( dependency.getImplementation() != null )
721 {
722 final Class specClass =
723 Class.forName( dependency.getSpecification().getIdentifier(),
724 true, classLoader );
725
726 final Instance dependencyInstance = new Instance(
727 classLoader, dependency.getSpecification().getScope(),
728 dependency.getImplementation().getIdentifier(),
729 dependency.getImplementation().getModelVersion(),
730 dependency.getImplementation().getModuleName() );
731
732 dependencyInstance.setDependency( dependency );
733 dependencyObject = this.requestImplementation(
734 specClass, dependency.getSpecification(),
735 this.getObject( dependencyInstance ) );
736
737 }
738 else
739 {
740 dependencyObject = this.resolveDependency( classLoader,
741 dependency );
742
743 }
744 }
745
746 if ( instance != null && dependency.isBound() )
747 {
748 instance.setDependencyObject( dependency.getName(),
749 dependencyObject );
750
751 }
752
753 return dependencyObject;
754 }
755
756 private Object resolveDependency( final ClassLoader classLoader,
757 final Dependency dependency )
758 throws ClassNotFoundException, NoSuchMethodException,
759 IllegalAccessException, InvocationTargetException
760 {
761 Implementation impl;
762 Instance dependencyInstance;
763 Dependency clone;
764 final Object resolved;
765
766 final Class specClass =
767 Class.forName( dependency.getSpecification().getIdentifier(),
768 true, classLoader );
769
770 switch ( dependency.getSpecification().getMultiplicity() )
771 {
772 case Specification.MULTIPLICITY_ONE:
773 if ( dependency.getSpecification().
774 getImplementations().size() != 1 )
775 {
776 throw new MultiplicityConstraintException(
777 dependency.getSpecification().
778 getIdentifier() );
779
780 }
781
782 impl = dependency.getSpecification().getImplementations().
783 getImplementation( 0 );
784
785 dependencyInstance = new Instance(
786 classLoader, dependency.getSpecification().getScope(),
787 impl.getIdentifier(), impl.getModelVersion(),
788 impl.getModuleName() );
789
790 clone = (Dependency) dependency.clone();
791 clone.setImplementation( impl );
792 dependencyInstance.setDependency( clone );
793 resolved = this.requestImplementation( specClass, dependency.
794 getSpecification(), this.getObject( dependencyInstance ) );
795
796 break;
797
798 case Specification.MULTIPLICITY_MANY:
799 final List list = new ArrayList( dependency.getSpecification().
800 getImplementations().size() );
801
802 for ( int i = dependency.getSpecification().
803 getImplementations().size() - 1; i >= 0; i-- )
804 {
805 impl = dependency.getSpecification().getImplementations().
806 getImplementation( i );
807
808 dependencyInstance = new Instance(
809 classLoader, dependency.getSpecification().getScope(),
810 impl.getIdentifier(), impl.getModelVersion(),
811 impl.getModuleName() );
812
813 clone = (Dependency) dependency.clone();
814 clone.setImplementation( impl );
815 dependencyInstance.setDependency( clone );
816 list.add( this.requestImplementation(
817 specClass, dependency.getSpecification(),
818 this.getObject( dependencyInstance ) ) );
819
820 }
821
822 final Object[] implementations =
823 (Object[]) Array.newInstance( specClass,
824 list.size() );
825
826 resolved = list.toArray( implementations );
827 break;
828
829 default:
830 throw new AssertionError( Integer.toString(
831 dependency.getSpecification().getMultiplicity() ) );
832
833 }
834
835 return resolved;
836 }
837
838 private Object resolveImplementation( final ClassLoader classLoader,
839 final Specification spec )
840 throws ClassNotFoundException, NoSuchMethodException,
841 IllegalAccessException, InvocationTargetException
842 {
843 Instance instance;
844 Implementation impl;
845
846 final Object resolved;
847 final Class specClass = Class.forName(
848 spec.getIdentifier(), true, classLoader );
849
850 switch ( spec.getMultiplicity() )
851 {
852 case Specification.MULTIPLICITY_ONE:
853 if ( spec.getImplementations().size() != 1 )
854 {
855 throw new MultiplicityConstraintException(
856 spec.getIdentifier() );
857
858 }
859
860 impl = spec.getImplementations().getImplementation( 0 );
861 instance = new Instance( classLoader,
862 spec.getScope(),
863 impl.getIdentifier(),
864 impl.getModelVersion(),
865 impl.getModuleName() );
866
867 instance.setImplementation( impl );
868 resolved = this.requestImplementation(
869 specClass, spec, this.getObject( instance ) );
870
871 break;
872
873 case Specification.MULTIPLICITY_MANY:
874 final List list = new ArrayList(
875 spec.getImplementations().size() );
876
877 for ( int i = spec.getImplementations().size() - 1; i >= 0;
878 i-- )
879 {
880 impl = spec.getImplementations().getImplementation( i );
881 instance = new Instance( classLoader,
882 spec.getScope(),
883 impl.getIdentifier(),
884 impl.getModelVersion(),
885 impl.getModuleName() );
886
887 instance.setImplementation( impl );
888 list.add( this.requestImplementation(
889 specClass, spec, this.getObject( instance ) ) );
890
891 }
892
893 final Object[] implementations =
894 (Object[]) Array.newInstance( specClass,
895 list.size() );
896
897 resolved = list.toArray( implementations );
898 break;
899
900 default:
901 throw new AssertionError( Integer.toString(
902 spec.getMultiplicity() ) );
903
904 }
905
906 return resolved;
907 }
908
909 private Object getScopedObject( final Scope scope, final Instance instance )
910 {
911 Object object;
912
913 if ( scope != null )
914 {
915 object = scope.getObject( instance.getClassName() );
916
917 if ( object == null || object instanceof Instance )
918 {
919 synchronized ( this.cycle )
920 {
921 object = scope.getObject( instance.getClassName() );
922
923 if ( object == null )
924 {
925 scope.putObject( instance.getClassName(), instance );
926
927 try
928 {
929 object = this.instantiateObject( instance );
930 }
931 catch ( final Throwable t )
932 {
933 scope.removeObject( instance.getClassName() );
934 if ( t instanceof Error )
935 {
936 throw (Error) t;
937 }
938 else if ( t instanceof RuntimeException )
939 {
940 throw (RuntimeException) t;
941 }
942 else
943 {
944 throw new org.jdtaus.core.container.InstantiationException(
945 instance.getClassName(), t );
946
947 }
948 }
949
950 scope.putObject( instance.getClassName(), object );
951 }
952 else if ( object instanceof Instance )
953 {
954 throw new DependencyCycleException(
955 ( (Instance) object ).getClassName(),
956 instance.getClassName() );
957
958 }
959 }
960 }
961 }
962 else
963 {
964 object = this.instantiateObject( instance );
965 }
966
967 return object;
968 }
969
970 private ClassLoader getClassLoader( final Class clazz )
971 {
972 ClassLoader classLoader = clazz.getClassLoader();
973 if ( classLoader == null )
974 {
975 classLoader = ClassLoader.getSystemClassLoader();
976 }
977
978 return classLoader;
979 }
980
981 private Object requestImplementation( final Class specClass,
982 final Specification spec,
983 final Object object )
984 throws NoSuchMethodException, IllegalAccessException,
985 InvocationTargetException
986 {
987 Object resolved = object;
988 Method accessor = null;
989
990 try
991 {
992 if ( !specClass.isAssignableFrom( object.getClass() ) )
993 {
994 accessor = object.getClass().getDeclaredMethod(
995 spec.getIdentifier().replace( '.', '_' ), EMPTY );
996
997 accessor.setAccessible( true );
998 resolved = accessor.invoke( object, EMPTY );
999 }
1000
1001 return resolved;
1002 }
1003 finally
1004 {
1005 if ( accessor != null )
1006 {
1007 accessor.setAccessible( false );
1008 }
1009 }
1010 }
1011
1012
1013 }