1 | /* |
2 | * jDTAUS Core RI Client Container |
3 | * Copyright (C) 2005 Christian Schulte |
4 | * <cs@schulte.it> |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2.1 of the License, or any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
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 | * {@code Container} reference implementation. |
51 | * |
52 | * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> |
53 | * @version $JDTAUS: DefaultContainer.java 8743 2012-10-07 03:06:20Z schulte $ |
54 | * |
55 | * @see org.jdtaus.core.container.ContainerFactory |
56 | */ |
57 | public class DefaultContainer implements Container |
58 | { |
59 | //--Constants--------------------------------------------------------------- |
60 | |
61 | /** Empty Class-Array. */ |
62 | private static final Class[] EMPTY = |
63 | { |
64 | }; |
65 | |
66 | /** Implementation Class-Array. */ |
67 | private static final Class[] IMPL_CTOR = |
68 | { |
69 | Implementation.class |
70 | }; |
71 | |
72 | /** Dependency Class-Array. */ |
73 | private static final Class[] DEP_CTOR = |
74 | { |
75 | Dependency.class |
76 | }; |
77 | |
78 | /** Array of scope implementations. */ |
79 | private static final Scope[] SCOPES = |
80 | { |
81 | null, new ContextScope(), new SingletonScope() |
82 | }; |
83 | |
84 | //---------------------------------------------------------------Constants-- |
85 | //--Container--------------------------------------------------------------- |
86 | |
87 | /** Mutex used to detect cyclic instantiations. */ |
88 | private final Object cycle = new Object(); |
89 | |
90 | /** Maps objects to model object. */ |
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 | //---------------------------------------------------------------Container-- |
298 | //--DefaultContainer-------------------------------------------------------- |
299 | |
300 | /** Creates a new {@code DefaultContainer} instance. */ |
301 | public DefaultContainer() |
302 | { |
303 | super(); |
304 | } |
305 | |
306 | /** |
307 | * Creates a new instance of an implementation. |
308 | * <p>The reference implementation loads the class corresponding to the |
309 | * implementation and creates a new instance of that class by calling the |
310 | * constructor taking an {@code Implementation} as an argument.</p> |
311 | * |
312 | * @param classLoader The classloader to use for loading classes. |
313 | * @param impl the implementation to return a new instance for. |
314 | * |
315 | * @return a new instance of the class corresponding to {@code impl}. |
316 | * |
317 | * @throws NullPointerException if {@code classLoader} or {@code impl} is |
318 | * {@code null}. |
319 | * @throws org.jdtaus.core.container.InstantiationException |
320 | * if no instance can be created. |
321 | * @deprecated Replaced by {@link #instantiateObject(org.jdtaus.core.container.ri.client.Instance) |
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 | * Creates a new instance of a dependency. |
369 | * <p>The reference implementation loads the class corresponding to the |
370 | * dependency and creates a new instance of that class by calling the |
371 | * constructor taking a {@code Dependency} as an argument.</p> |
372 | * |
373 | * @param classLoader The classloader to use for loading classes. |
374 | * @param dep the dependency to return a new instance for. |
375 | * |
376 | * @return a new instance of the class corresponding to {@code dep}. |
377 | * |
378 | * @throws NullPointerException if {@code classLoader} or {@code dep} is |
379 | * {@code null}. |
380 | * @throws org.jdtaus.core.container.InstantiationException |
381 | * if no instance can be created. |
382 | * @deprecated Replaced by {@link #instantiateObject(org.jdtaus.core.container.ri.client.Instance) |
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 | * Performs initialization of an object. |
430 | * |
431 | * @param object The object to initialize. |
432 | * |
433 | * @throws NullPointerException if {@code object} is {@code null}. |
434 | * @throws Exception if initialization fails. |
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 | * Performs context initialization of an object. |
451 | * |
452 | * @param object The object to perform context initialization with. |
453 | * |
454 | * @throws NullPointerException if {@code object} is {@code null}. |
455 | * @throws org.jdtaus.core.container.ContextError for unrecoverable context |
456 | * errors. |
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 | // Cannot happen - method got set accessible. |
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 | // Automatically discovered default implementations must use |
611 | // the static getDefault method. |
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 | //--------------------------------------------------------DefaultContainer-- |
1013 | } |