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