View Javadoc
1   package org.codehaus.plexus.test;
2   
3   /*
4    * Copyright 2001-2006 Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.io.File;
20  import java.net.URL;
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.UUID;
26  import java.util.concurrent.CopyOnWriteArrayList;
27  import java.util.concurrent.CountDownLatch;
28  import java.util.concurrent.atomic.AtomicBoolean;
29  
30  import junit.framework.TestCase;
31  
32  import org.codehaus.plexus.ContainerConfiguration;
33  import org.codehaus.plexus.DefaultContainerConfiguration;
34  import org.codehaus.plexus.DefaultPlexusContainer;
35  import org.codehaus.plexus.classworlds.realm.ClassRealm;
36  import org.codehaus.plexus.component.discovery.DiscoveredComponent;
37  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
38  import org.codehaus.plexus.lifecycle.BasicLifecycleHandler;
39  import org.codehaus.plexus.lifecycle.LifecycleHandler;
40  import org.codehaus.plexus.test.lifecycle.phase.EenyPhase;
41  import org.codehaus.plexus.test.lifecycle.phase.MeenyPhase;
42  import org.codehaus.plexus.test.lifecycle.phase.MinyPhase;
43  import org.codehaus.plexus.test.lifecycle.phase.MoPhase;
44  import org.codehaus.plexus.test.list.Pipeline;
45  import org.codehaus.plexus.test.list.Valve;
46  import org.codehaus.plexus.test.list.ValveFour;
47  import org.codehaus.plexus.test.list.ValveOne;
48  import org.codehaus.plexus.test.list.ValveThree;
49  import org.codehaus.plexus.test.list.ValveTwo;
50  import org.codehaus.plexus.test.map.Activity;
51  import org.codehaus.plexus.test.map.ActivityManager;
52  
53  public class PlexusContainerTest
54      extends TestCase
55  {
56      private String basedir;
57  
58      private ClassLoader classLoader;
59  
60      private String configuration;
61  
62      private DefaultPlexusContainer container;
63  
64      public PlexusContainerTest( String name )
65      {
66          super( name );
67      }
68  
69      public void setUp()
70          throws Exception
71      {
72          basedir = System.getProperty( "basedir" );
73  
74          classLoader = getClass().getClassLoader();
75  
76          configuration = "/" + getClass().getName().replace( '.', '/' ) + ".xml";
77  
78          assertNotNull( classLoader );
79  
80          // ----------------------------------------------------------------------------
81          // Context
82          // ----------------------------------------------------------------------------
83  
84          Map<Object, Object> context = new HashMap<Object, Object>();
85  
86          context.put( "basedir", basedir );
87  
88          context.put( "plexus.home", basedir + "/target/plexus-home" );
89  
90          LifecycleHandler arbitrary = new BasicLifecycleHandler( "arbitrary" );
91          arbitrary.addBeginSegment( new EenyPhase() );
92          arbitrary.addBeginSegment( new MeenyPhase() );
93          arbitrary.addBeginSegment( new MinyPhase() );
94          arbitrary.addBeginSegment( new MoPhase() );
95  
96          ContainerConfiguration containerConfiguration = new DefaultContainerConfiguration()
97              .setName( "test" )
98              .setContext( context )
99              .setContainerConfiguration( configuration )
100             .addLifecycleHandler( arbitrary );
101 
102         container = new DefaultPlexusContainer( containerConfiguration );
103     }
104 
105     public void tearDown()
106         throws Exception
107     {
108         container.dispose();
109 
110         container = null;
111     }
112 
113     public void testDefaultPlexusContainerSetup()
114         throws Exception
115     {
116         assertEquals( "bar", System.getProperty( "foo" ) );
117     }
118 
119     // ----------------------------------------------------------------------
120     // Test the native plexus lifecycle. Note that the configuration for
121     // this TestCase supplies its own lifecycle, so this test verifies that
122     // the native lifecycle is available after configuration merging.
123     // ----------------------------------------------------------------------
124 
125     public void testNativeLifecyclePassage()
126         throws Exception
127     {
128         DefaultServiceB serviceB = (DefaultServiceB) container.lookup( ServiceB.class );
129 
130         // Make sure the component is alive.
131         assertNotNull( serviceB );
132 
133         // Make sure the component went through all the lifecycle phases
134         assertEquals( true, serviceB.enableLogging );
135 
136         assertEquals( true, serviceB.contextualize );
137 
138         assertEquals( true, serviceB.initialize );
139 
140         assertEquals( true, serviceB.start );
141 
142         assertEquals( false, serviceB.stop );
143 
144         container.release( serviceB );
145 
146         assertEquals( true, serviceB.stop );
147     }
148 
149     public void testConfigurableLifecyclePassage()
150         throws Exception
151     {
152         DefaultServiceE serviceE = (DefaultServiceE) container.lookup( ServiceE.class );
153 
154         // Make sure the component is alive.
155         assertNotNull( serviceE );
156 
157         // Make sure the component went through all the lifecycle phases
158         assertEquals( true, serviceE.enableLogging );
159 
160         assertEquals( true, serviceE.contextualize );
161 
162         assertEquals( true, serviceE.initialize );
163 
164         assertEquals( true, serviceE.start );
165 
166         assertEquals( false, serviceE.stop );
167 
168         container.release( serviceE );
169 
170         assertEquals( true, serviceE.stop );
171     }
172 
173     /*
174      * Check that we can get references to a single component with a role
175      * hint.
176      */
177     public void testSingleComponentLookupWithRoleHint()
178         throws Exception
179     {
180         // Retrieve an instance of component c.
181         DefaultServiceC serviceC1 = (DefaultServiceC) container.lookup( ServiceC.class, "first-instance" );
182 
183         // Make sure the component is alive.
184         assertNotNull( serviceC1 );
185 
186         assertTrue( serviceC1.started );
187 
188         assertFalse( serviceC1.stopped );
189 
190         // Retrieve a second reference to the same component.
191         DefaultServiceC serviceC2 = (DefaultServiceC) container.lookup( ServiceC.class, "first-instance" );
192 
193         // Make sure component is alive.
194         assertNotNull( serviceC2 );
195 
196         assertTrue( serviceC2.started );
197 
198         assertFalse( serviceC2.stopped );
199 
200         // Let's make sure it gave us back the same component.
201         assertSame( serviceC1, serviceC2 );
202 
203         container.release( serviceC1 );
204 
205         // The component should still be alive.
206         assertTrue( serviceC2.started );
207 
208         assertTrue( serviceC2.stopped );
209 
210         container.release( serviceC2 );
211 
212         // The component should now have been stopped.
213         assertTrue( serviceC2.started );
214 
215         assertTrue( serviceC2.stopped );
216     }
217 
218     /*
219      * Check that distinct components with the same implementation are managed correctly.
220      */
221     public void testMultipleSingletonComponentInstances()
222         throws Exception
223     {
224         // Retrieve an instance of component c.
225         DefaultServiceC serviceC1 = (DefaultServiceC) container.lookup( ServiceC.class, "first-instance" );
226 
227         // Make sure the component is alive.
228         assertNotNull( serviceC1 );
229 
230         assertTrue( serviceC1.started ); 
231 
232         assertFalse( serviceC1.stopped );
233 
234         // Retrieve an instance of component c, with a different role hint.
235         // This should give us a different component instance.
236         DefaultServiceC serviceC2 = (DefaultServiceC) container.lookup( ServiceC.class, "second-instance" );
237 
238         // Make sure component is alive.
239         assertNotNull( serviceC2 );
240 
241         assertTrue( serviceC2.started );
242 
243         assertFalse( serviceC2.stopped );
244 
245         // The components should be distinct.
246         assertNotSame( serviceC1, serviceC2 );
247 
248         container.release( serviceC1 );
249 
250         // The first component should now have been stopped, the second
251         // one should still be alive.
252         assertTrue( serviceC1.started );
253 
254         assertTrue( serviceC1.stopped );
255 
256         assertTrue( serviceC2.started );
257 
258         assertFalse( serviceC2.stopped );
259 
260         container.release( serviceC2 );
261 
262         // The second component should now have been stopped.
263         assertTrue( serviceC2.started );
264 
265         assertTrue( serviceC2.stopped );
266     }
267 
268     // ----------------------------------------------------------------------
269     // Test using an arbitrary component lifecycle handler
270     // ----------------------------------------------------------------------
271 
272     public void testArbitraryLifecyclePassageUsingFourArbitraryPhases()
273         throws Exception
274     {
275         // Retrieve an manager of component H.
276         DefaultServiceH serviceH = (DefaultServiceH) container.lookup( ServiceH.class );
277 
278         // Make sure the component is alive.
279         assertNotNull( serviceH );
280 
281         // Make sure the component went through all the lifecycle phases
282         assertEquals( true, serviceH.eeny );
283 
284         assertEquals( true, serviceH.meeny );
285 
286         assertEquals( true, serviceH.miny );
287 
288         assertEquals( true, serviceH.mo );
289 
290         container.release( serviceH );
291     }
292 
293     public void testLookupAll()
294         throws Exception
295     {
296         Map<String, ServiceC> components = container.lookupMap( ServiceC.class );
297 
298         assertNotNull( components );
299 
300         assertEquals( 2, components.size() );
301 
302         ServiceC component = components.get( "first-instance" );
303 
304         assertNotNull( component );
305 
306         component = components.get( "second-instance" );
307 
308         assertNotNull( component );
309 
310         container.releaseAll( components );
311     }
312 
313     public void testAutomatedComponentConfigurationUsingXStreamPoweredComponentConfigurator()
314         throws Exception
315     {
316         Component component = container.lookup( Component.class );
317 
318         assertNotNull( component );
319 
320         assertNotNull( component.getActivity() );
321 
322         assertEquals( "localhost", component.getHost() );
323 
324         assertEquals( 10000, component.getPort() );
325     }
326 
327     public void testAutomatedComponentComposition()
328         throws Exception
329     {
330         ComponentA componentA = container.lookup( ComponentA.class );
331 
332         assertNotNull( componentA );
333 
334         assertEquals( "localhost", componentA.getHost() );
335 
336         assertEquals( 10000, componentA.getPort() );
337 
338         ComponentB componentB = componentA.getComponentB();
339 
340         assertNotNull( componentB );
341 
342         ComponentC componentC = componentA.getComponentC();
343 
344         assertNotNull( componentC );
345 
346         ComponentD componentD = componentC.getComponentD();
347 
348         assertNotNull( componentD );
349 
350         assertEquals( "jason", componentD.getName() );
351     }
352 
353     public void testComponentCompositionWhereTargetFieldIsAMap()
354         throws Exception
355     {
356         ActivityManager am = container.lookup( ActivityManager.class );
357 
358         Activity one = am.getActivity( "one" );
359 
360         assertNotNull( one );
361 
362         // repeated retrieval from map should not cause re-lookup even if instantiation strategy is per-lookup
363         assertSame( one, am.getActivity( "one" ) );
364 
365         assertFalse( one.getState() );
366 
367         am.execute( "one" );
368 
369         assertTrue( one.getState() );
370 
371         Activity two = am.getActivity( "two" );
372 
373         assertNotNull( two );
374 
375         assertFalse( two.getState() );
376 
377         am.execute( "two" );
378 
379         assertTrue( two.getState() );
380     }
381 
382     public void testComponentCompositionWhereTargetFieldIsAPartialMap()
383         throws Exception
384     {
385         ActivityManager am = container.lookup( ActivityManager.class, "slim" );
386 
387         assertEquals( 1, am.getActivityCount() );
388 
389         Activity one = am.getActivity( "one" );
390 
391         assertNotNull( one );
392 
393         assertFalse( one.getState() );
394 
395         am.execute( "one" );
396 
397         assertTrue( one.getState() );
398     }
399 
400     public void testComponentCompositionWhereTargetFieldIsAList()
401         throws Exception
402     {
403         Pipeline pipeline = container.lookup( Pipeline.class );
404 
405         List valves = pipeline.getValves();
406 
407         for (Object valve : valves) {
408             // repeated retrieval from list should not cause re-lookup even if instantiation strategy is per-lookup
409             assertSame(valve, valve);
410         }
411 
412         assertFalse( ( (Valve) valves.get( 0 ) ).getState() );
413 
414         assertFalse( ( (Valve) valves.get( 1 ) ).getState() );
415 
416         pipeline.execute();
417 
418         assertTrue( ( (Valve) valves.get( 0 ) ).getState() );
419 
420         assertTrue( ( (Valve) valves.get( 1 ) ).getState() );
421     }
422 
423     public void testComponentCompositionWhereTargetFieldIsAPartialList()
424         throws Exception
425     {
426         Pipeline pipeline = container.lookup( Pipeline.class, "slim" );
427 
428         List valves = pipeline.getValves();
429 
430         assertEquals( valves.size(), 1 );
431 
432         assertFalse( ( (Valve) valves.get( 0 ) ).getState() );
433 
434         pipeline.execute();
435 
436         assertTrue( ( (Valve) valves.get( 0 ) ).getState() );
437     }
438 
439     public void testComponentCompositionWhereTargetFieldAMapThatMustRetainTheOrderOfComponentsGivenASetOfRoleHints()
440         throws Exception
441     {
442         Pipeline pipeline = container.lookup( Pipeline.class, "chubby" );
443 
444         Map valveMap = pipeline.getValveMap();
445 
446         List valves = new ArrayList( valveMap.values() );
447 
448         assertEquals( "Expecting three valves.", 4, valves.size() );
449 
450         assertTrue( "Expecting valve one.", valves.get(0) instanceof ValveOne );
451 
452         assertTrue( "Expecting valve two.", valves.get(1) instanceof ValveTwo );
453 
454         assertTrue( "Expecting valve three.", valves.get(2) instanceof ValveThree );
455 
456         assertTrue( "Expecting valve four.", valves.get(3) instanceof ValveFour );        
457     }
458 
459     public void testLookupOfComponentThatShouldBeDiscovered()
460         throws Exception
461     {
462         DiscoveredComponent discoveredComponent = container.lookup( DiscoveredComponent.class );
463 
464         assertNotNull( discoveredComponent );
465     }
466     
467     public void testStartableComponentSnake()
468         throws Exception
469     {
470         StartableComponent ca = container.lookup( StartableComponent.class, "A-snake" );
471         
472         assertNotNull( ca );
473         
474         ca.assertStartOrderCorrect();
475         
476         container.dispose();
477         
478         ca.assertStopOrderCorrect();
479     }
480     
481     public void testStartableComponentTree()
482         throws Exception
483     {
484         StartableComponent ca = container.lookup( StartableComponent.class, "A-tree" );
485     
486         assertNotNull( ca );
487     
488         ca.assertStartOrderCorrect();
489 
490         container.dispose();
491 
492         ca.assertStopOrderCorrect();
493     }
494 
495     public void testLookupCircularity()
496         throws Exception
497     {
498         try
499         {
500             container.lookup( CircularComponent.class, "A" );
501             fail("Expected ComponentLookupException due to circularity");
502         }
503         catch ( ComponentLookupException e )
504         {
505             // todo actually test nested exception is as expected when 
506         }
507     }
508 
509     public void testAddComponent()
510         throws Exception
511     {
512         LiveComponent live = new LiveComponent();
513 
514         container.addComponent( live, LiveComponent.class.getName() );
515 
516         LiveComponent c = container.lookup( LiveComponent.class );
517 
518         assertSame( live, c );
519     }
520 
521     public void testComponentOverride() 
522         throws Exception
523     {
524         assertNotNull( container.lookup( Component.class ) );
525 
526         Component live = new Component()
527         {
528             public Activity getActivity()
529             {
530                 return null;
531             }
532             public String getHost()
533             {
534                 return null;
535             }
536             public int getPort()
537             {
538                 return 0;
539             }
540         };
541 
542         container.addComponent( live, Component.class, null );
543 
544         assertSame( live, container.lookup( Component.class ) );
545     }
546 
547     public void testUpdateOfActiveComponentCollectionUponChangeOfThreadContextClassLoader()
548         throws Exception
549     {
550         ComponentManager manager = container.lookup( ComponentManager.class );
551 
552         Map<String, ?> map = manager.getMap();
553         assertNotNull( map );
554         assertEquals( 0, map.size() );
555 
556         List<?> list = manager.getList();
557         assertNotNull( list );
558         assertEquals( 0, list.size() );
559 
560         /*
561          * Below we're creating two realms which basically contain the same components, only their bytecode/version
562          * differs. When we switch the thread's context class loader, the active component collections in the component
563          * manager must accurately reflect the components from the current realm (and not from a previous realm).
564          */
565 
566         ClassRealm realmA = container.createChildRealm( "realm-a" );
567         realmA.addURL( new File( "src/test/test-components/component-a-1.0-SNAPSHOT.jar" ).toURI().toURL() );
568         container.discoverComponents( realmA );
569 
570         ClassRealm realmB = container.createChildRealm( "realm-b" );
571         realmB.addURL( new File( "src/test/test-components/component-a-2.0-SNAPSHOT.jar" ).toURI().toURL() );
572         container.discoverComponents( realmB );
573 
574         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
575 
576         try
577         {
578             Thread.currentThread().setContextClassLoader( realmA );
579 
580             map = manager.getMap();
581             assertNotNull( map );
582             assertEquals( 1, map.size() );
583             assertSame( realmA, map.values().iterator().next().getClass().getClassLoader() );
584 
585             list = manager.getList();
586             assertNotNull( list );
587             assertEquals( 1, list.size() );
588             assertSame( realmA, list.iterator().next().getClass().getClassLoader() );
589 
590             Thread.currentThread().setContextClassLoader( realmB );
591 
592             map = manager.getMap();
593             assertNotNull( map );
594             assertEquals( 1, map.size() );
595             assertSame( realmB, map.values().iterator().next().getClass().getClassLoader() );
596 
597             list = manager.getList();
598             assertNotNull( list );
599             assertEquals( 1, list.size() );
600             assertSame( realmB, list.iterator().next().getClass().getClassLoader() );
601         }
602         finally
603         {
604             Thread.currentThread().setContextClassLoader( oldClassLoader );
605         }
606     }
607 
608     public void testUpdateOfActiveComponentCollectionUponChangeOfThreadContextClassLoaderFromParentToChildRealm()
609         throws Exception
610     {
611         ComponentManager manager = container.lookup( ComponentManager.class );
612 
613         Map<String, ?> map = manager.getMap();
614         assertNotNull( map );
615         assertEquals( 0, map.size() );
616 
617         List<?> list = manager.getList();
618         assertNotNull( list );
619         assertEquals( 0, list.size() );
620 
621         /*
622          * Below we're creating two realms which basically contain the same components, only their bytecode/version
623          * differs. The realms form a parent-child relationship where the child imports the component role from the
624          * parent. When we first load from the parent and then switch the thread's context class loader to the child,
625          * the active component collections in the component manager must accurately reflect the components from the
626          * current realm (and not from a previous realm).
627          */
628 
629         ClassRealm realmA = container.createChildRealm( "realm-a" );
630         realmA.addURL( new File( "src/test/test-components/component-a-1.0-SNAPSHOT.jar" ).toURI().toURL() );
631         container.discoverComponents( realmA );
632 
633         ClassRealm realmB = realmA.createChildRealm( "realm-b" );
634         realmB.importFrom( realmA, "org.codehaus.plexus.components.A" );
635         realmB.importFromParent( "nothing" );
636         realmB.addURL( new File( "src/test/test-components/component-a-2.0-SNAPSHOT.jar" ).toURI().toURL() );
637         container.discoverComponents( realmB );
638 
639         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
640 
641         try
642         {
643             Thread.currentThread().setContextClassLoader( realmA );
644 
645             map = manager.getMap();
646             assertNotNull( map );
647             assertEquals( 1, map.size() );
648             assertSame( realmA, map.values().iterator().next().getClass().getClassLoader() );
649 
650             list = manager.getList();
651             assertNotNull( list );
652             assertEquals( 1, list.size() );
653             assertSame( realmA, list.iterator().next().getClass().getClassLoader() );
654 
655             Thread.currentThread().setContextClassLoader( realmB );
656 
657             map = manager.getMap();
658             assertNotNull( map );
659             assertEquals( 1, map.size() );
660             assertSame( realmB, map.values().iterator().next().getClass().getClassLoader() );
661 
662             list = manager.getList();
663             assertNotNull( list );
664             assertEquals( 1, list.size() );
665             assertSame( realmB, list.iterator().next().getClass().getClassLoader() );
666         }
667         finally
668         {
669             Thread.currentThread().setContextClassLoader( oldClassLoader );
670         }
671     }
672 
673     public void testComponentLookupFromParentRealmOfImportedRealms()
674         throws Exception
675     {
676         ComponentManager manager = container.lookup( ComponentManager.class );
677 
678         Map<String, ?> map = manager.getMap();
679         assertNotNull( map );
680         assertEquals( 0, map.size() );
681 
682         List<?> list = manager.getList();
683         assertNotNull( list );
684         assertEquals( 0, list.size() );
685 
686         URL componentUrl = new File( "src/test/test-components/component-a-1.0-SNAPSHOT.jar" ).toURI().toURL();
687 
688         ClassRealm realmP = container.createChildRealm( "parent-of-imported-realm" );
689         realmP.addURL( componentUrl );
690         container.discoverComponents( realmP );
691 
692         ClassRealm realmI = realmP.createChildRealm( "imported-realm" );
693 
694         ClassRealm realmL = container.createChildRealm( "lookup-realm" );
695         realmL.importFrom( realmI, "org.something" );
696 
697         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
698 
699         try
700         {
701             Thread.currentThread().setContextClassLoader( realmL );
702 
703             map = manager.getMap();
704             assertNotNull( map );
705             assertEquals( 1, map.size() );
706             assertSame( realmP, map.values().iterator().next().getClass().getClassLoader() );
707 
708             list = manager.getList();
709             assertNotNull( list );
710             assertEquals( 1, list.size() );
711             assertSame( realmP, list.iterator().next().getClass().getClassLoader() );
712         }
713         finally
714         {
715             Thread.currentThread().setContextClassLoader( oldClassLoader );
716         }
717     }
718 
719     public void testOptionalComponentRequirement()
720         throws Exception
721     {
722         DefaultComponentWithOptionalRequirement ca =
723             (DefaultComponentWithOptionalRequirement) container.lookup( Component.class, "with-optional" );
724 
725         assertNotNull( ca );
726 
727         assertNotNull( ca.getActivity() );
728 
729         assertNull( ca.optionalComponent );
730     }
731 
732     public void testLookupOfComponentThatHasARequirementWithoutRoleHintAndTheOneAndOnlyImplHasNoDefaultHint()
733         throws Exception
734     {
735         DefaultThingUser component = (DefaultThingUser) container.lookup( ThingUser.class );
736 
737         assertNotNull( component.thing );
738     }
739 
740     public void testSingleLookupWithAndWithoutRoleHint()
741         throws Exception
742     {
743         ComponentWithRoleDefault withRoleHint = container.lookup( ComponentWithRoleDefault.class, "default" );
744 
745         ComponentWithRoleDefault withoutRoleHint = container.lookup( ComponentWithRoleDefault.class );
746 
747         assertSame( withRoleHint, withoutRoleHint );
748     }
749 
750     public void testLookupUponChangeOfThreadContextClassLoaderFromParentToChildRealm()
751         throws Exception
752     {
753         /*
754          * Below we're creating two realms which basically contain the same components, only their bytecode/version
755          * differs. The realms form a parent-child relationship where the child imports the component role from the
756          * parent. When we first lookup from the parent and then switch the thread's context class loader to the child,
757          * the second lookup must accurately reflect the components from the current realm (and not from a previous
758          * realm).
759          */
760 
761         ClassRealm realmA = container.createChildRealm( "realm-a" );
762         realmA.addURL( new File( "src/test/test-components/component-a-1.0-SNAPSHOT.jar" ).toURI().toURL() );
763         container.discoverComponents( realmA );
764 
765         ClassRealm realmB = realmA.createChildRealm( "realm-b" );
766         realmB.importFrom( realmA, "org.codehaus.plexus.components.A" );
767         realmB.importFromParent( "nothing" );
768         realmB.addURL( new File( "src/test/test-components/component-a-2.0-SNAPSHOT.jar" ).toURI().toURL() );
769         container.discoverComponents( realmB );
770 
771         Class<?> role = realmA.loadClass( "org.codehaus.plexus.components.A" );
772 
773         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
774 
775         try
776         {
777             Thread.currentThread().setContextClassLoader( realmA );
778 
779             Object comp1 = container.lookup( role, "default" );
780 
781             Thread.currentThread().setContextClassLoader( realmB );
782 
783             Object comp2 = container.lookup( role, "default" );
784 
785             assertNotNull( comp1 );
786             assertNotNull( comp2 );
787             assertNotSame( comp1, comp2 );
788             assertSame( realmA, comp1.getClass().getClassLoader() );
789             assertSame( realmB, comp2.getClass().getClassLoader() );
790         }
791         finally
792         {
793             Thread.currentThread().setContextClassLoader( oldClassLoader );
794         }
795     }
796 
797     public void testSafeConcurrentAccessToActiveComponentCollection()
798         throws Exception
799     {
800         ComponentManager manager = container.lookup( ComponentManager.class );
801 
802         final Map<String, ?> map = manager.getMap();
803         assertNotNull( map );
804         assertEquals( 0, map.size() );
805 
806         final List<?> list = manager.getList();
807         assertNotNull( list );
808         assertEquals( 0, list.size() );
809 
810         final AtomicBoolean go = new AtomicBoolean( false );
811 
812         final List<Exception> exceptions = new CopyOnWriteArrayList<Exception>();
813         Thread[] threads = new Thread[64];
814         final CountDownLatch latch = new CountDownLatch( threads.length );
815         for ( int i = 0; i < threads.length; i++ )
816         {
817             threads[i] = new Thread()
818             {
819                 @Override
820                 public void run()
821                 {
822                     try
823                     {
824                         ClassRealm realm = container.createChildRealm( "realm-" + UUID.randomUUID().toString() );
825                         realm.addURL( new File( "src/test/test-components/component-a-1.0-SNAPSHOT.jar" ).toURI().toURL() );
826                         container.discoverComponents( realm );
827                         Thread.currentThread().setContextClassLoader( realm );
828 
829                         while ( !go.get() )
830                         {
831                             // just wait
832                         }
833 
834                         for ( int j = 0; j < 1000; j++ )
835                         {
836                             // this just must not die with some exception
837                             for ( Object value : map.values() )
838                             {
839                                 value.toString();
840                             }
841                             for ( Object value : list )
842                             {
843                                 value.toString();
844                             }
845                         }
846                     }
847                     catch ( Exception e )
848                     {
849                         e.printStackTrace();
850                         exceptions.add( e );
851                     }
852                     finally
853                     {
854                         latch.countDown();
855                     }
856                 }
857             };
858             threads[i].start();
859         }
860         go.set( true );
861         latch.await();
862 
863         assertTrue( exceptions.toString(), exceptions.isEmpty() );
864     }
865 
866 }