1 package org.nanocontainer.script.jruby; 2 3 import java.io.File ; 4 import java.io.IOException ; 5 import java.io.Reader ; 6 import java.io.StringReader ; 7 import java.io.StringWriter ; 8 import java.net.URL ; 9 import java.net.URLClassLoader ; 10 11 import org.jmock.Mock; 12 import org.jruby.exceptions.RaiseException; 13 import org.nanocontainer.NanoPicoContainer; 14 import org.nanocontainer.TestHelper; 15 import org.nanocontainer.integrationkit.PicoCompositionException; 16 import org.nanocontainer.reflection.DefaultNanoPicoContainer; 17 import org.nanocontainer.script.AbstractScriptedContainerBuilderTestCase; 18 import org.nanocontainer.script.NanoContainerMarkupException; 19 import org.nanocontainer.testmodel.A; 20 import org.nanocontainer.testmodel.B; 21 import org.nanocontainer.testmodel.HasParams; 22 import org.nanocontainer.testmodel.ParentAssemblyScope; 23 import org.nanocontainer.testmodel.SomeAssemblyScope; 24 import org.nanocontainer.testmodel.X; 25 import org.picocontainer.ComponentAdapter; 26 import org.picocontainer.MutablePicoContainer; 27 import org.picocontainer.PicoContainer; 28 import org.picocontainer.defaults.ComponentAdapterFactory; 29 import org.picocontainer.defaults.DefaultPicoContainer; 30 import org.picocontainer.defaults.InstanceComponentAdapter; 31 import org.picocontainer.defaults.SetterInjectionComponentAdapter; 32 import org.picocontainer.defaults.SetterInjectionComponentAdapterFactory; 33 import org.picocontainer.defaults.UnsatisfiableDependenciesException; 34 35 41 public class JRubyContainerBuilderTestCase extends AbstractScriptedContainerBuilderTestCase { 42 private static final String ASSEMBLY_SCOPE = "SOME_SCOPE"; 43 44 45 public void testContainerCanBeBuiltWithParentGlobal() { 46 Reader script = new StringReader ( 47 "StringBuffer = java.lang.StringBuffer\n" + 48 "container(:parent => $parent) { \n" + 49 " component(StringBuffer)\n" + 50 "}"); 51 PicoContainer parent = new DefaultPicoContainer(); 52 PicoContainer pico = buildContainer(script, parent, ASSEMBLY_SCOPE); 53 assertNotNull(pico.getParent()); 55 assertNotSame(parent, pico.getParent()); 56 assertEquals(StringBuffer .class, pico.getComponentInstance(StringBuffer .class).getClass()); 57 } 58 59 public void testContainerCanBeBuiltWithComponentImplementation() { 60 X.reset(); 61 Reader script = new StringReader ( 62 "A = org.nanocontainer.testmodel.A\n" + 63 "container {\n" + 64 " component(A)\n" + 65 "}"); 66 67 PicoContainer pico = buildContainer(script, null, ASSEMBLY_SCOPE); 68 pico.dispose(); 70 71 assertEquals("Should match the expression", "<A!A", X.componentRecorder); 72 } 73 74 public void testContainerCanBeBuiltWithComponentInstance() { 75 Reader script = new StringReader ( 76 "container { \n" + 77 " component(:key => 'string', :instance => 'foo')\n" + 78 "}"); 79 80 PicoContainer pico = buildContainer(script, null, "SOME_SCOPE"); 81 82 assertEquals("foo", pico.getComponentInstance("string")); 83 } 84 85 public void testBuildingWithPicoSyntax() { 86 Reader script = new StringReader ( 87 "$parent.registerComponentImplementation('foo', Java::JavaClass.for_name('java.lang.String'))\n" 88 + 89 "DefaultPicoContainer = org.picocontainer.defaults.DefaultPicoContainer\n" + 90 "pico = DefaultPicoContainer.new($parent)\n" + 91 "pico.registerComponentImplementation(Java::JavaClass.for_name('org.nanocontainer.testmodel.A'))\n" 92 + 93 "pico"); 94 95 PicoContainer parent = new DefaultPicoContainer(); 96 PicoContainer pico = buildContainer(script, parent, "SOME_SCOPE"); 97 98 assertNotSame(parent, pico.getParent()); 99 assertNotNull(pico.getComponentInstance(A.class)); 100 assertNotNull(pico.getComponentInstance("foo")); 101 } 102 103 public void testContainerBuiltWithMultipleComponentInstances() { 104 Reader script = new StringReader ( 105 "container {\n" + 106 " component(:key => 'a', :instance => 'apple')\n" + 107 " component(:key => 'b', :instance => 'banana')\n" + 108 " component(:instance => 'noKeySpecified')\n" + 109 "}"); 110 111 PicoContainer pico = buildContainer(script, null, ASSEMBLY_SCOPE); 112 assertEquals("apple", pico.getComponentInstance("a")); 113 assertEquals("banana", pico.getComponentInstance("b")); 114 assertEquals("noKeySpecified", pico.getComponentInstance(String .class)); 115 } 116 117 public void testShouldFailWhenNeitherClassNorInstanceIsSpecifiedForComponent() { 118 Reader script = new StringReader ( 119 "container {\n" + 120 " component(:key => 'a')\n" + 121 "}"); 122 123 try { 124 buildContainer(script, null, ASSEMBLY_SCOPE); 125 fail("NanoContainerMarkupException should have been raised"); 126 } catch(NanoContainerMarkupException e) { 127 } 129 } 130 131 public void testAcceptsConstantParametersForComponent() { 132 Reader script = new StringReader ( 133 "HasParams = org.nanocontainer.testmodel.HasParams\n" + 134 "container {\n" + 135 " component(:key => 'byClass', :class => HasParams, :parameters => [ 'a', 'b', constant('c')])\n" 136 + 137 "}"); 138 139 PicoContainer pico = buildContainer(script, null, ASSEMBLY_SCOPE); 140 HasParams byClass = (HasParams) pico.getComponentInstance("byClass"); 141 assertEquals("abc", byClass.getParams()); 142 } 143 144 public void testAcceptsComponentClassNameAsString() { 145 Reader script = new StringReader ( 146 "container {\n" + 147 " component(:key => 'byClassString', :class => 'org.nanocontainer.testmodel.HasParams', :parameters => [ 'c', 'a', 't' ])\n" 148 + 149 "}"); 150 151 PicoContainer pico = buildContainer(script, null, ASSEMBLY_SCOPE); 152 HasParams byClassString = (HasParams) pico.getComponentInstance("byClassString"); 153 assertEquals("cat", byClassString.getParams()); 154 } 155 156 public void testAcceptsComponentParametersForComponent() { 157 Reader script = new StringReader ( 158 "A = org.nanocontainer.testmodel.A\n" + 159 "B = org.nanocontainer.testmodel.B\n" + 160 "container {\n" + 161 " component(:key => 'a1', :class => A)\n" + 162 " component(:key => 'a2', :class => A)\n" + 163 " component(:key => 'b1', :class => B, :parameters => [ key('a1') ])\n" + 164 " component(:key => 'b2', :class => B, :parameters => key('a2'))\n" + 165 "}"); 166 167 PicoContainer pico = buildContainer(script, null, ASSEMBLY_SCOPE); 168 A a1 = (A) pico.getComponentInstance("a1"); 169 A a2 = (A) pico.getComponentInstance("a2"); 170 B b1 = (B) pico.getComponentInstance("b1"); 171 B b2 = (B) pico.getComponentInstance("b2"); 172 173 assertNotNull(a1); 174 assertNotNull(a2); 175 assertNotNull(b1); 176 assertNotNull(b2); 177 178 assertSame(a1, b1.getA()); 179 assertSame(a2, b2.getA()); 180 assertNotSame(a1, a2); 181 assertNotSame(b1, b2); 182 } 183 184 public void testAcceptsComponentParameterWithClassNameKey() { 185 Reader script = new StringReader ( 186 "A = org.nanocontainer.testmodel.A\n" + 187 "B = org.nanocontainer.testmodel.B\n" + 188 "container {\n" + 189 " component(:class => A)\n" + 190 " component(:key => B, :class => B, :parameters => key(A))\n" + 191 "}"); 192 193 PicoContainer pico = buildContainer(script, null, ASSEMBLY_SCOPE); 194 A a = (A) pico.getComponentInstance(A.class); 195 B b = (B) pico.getComponentInstance(B.class); 196 197 assertNotNull(a); 198 assertNotNull(b); 199 assertSame(a, b.getA()); 200 } 201 202 public void testInstantiateBasicComponentInDeeperTree() { 203 X.reset(); 204 Reader script = new StringReader ( 205 "A = org.nanocontainer.testmodel.A\n" + 206 "container {\n" + 207 " container {\n" + 208 " component(A)\n" + 209 " }\n" + 210 "}"); 211 212 PicoContainer pico = buildContainer(script, null, ASSEMBLY_SCOPE); 213 pico.dispose(); 214 assertEquals("Should match the expression", "<A!A", X.componentRecorder); 215 } 216 217 public void testCustomComponentAdapterFactoryCanBeSpecified() { 218 Reader script = new StringReader ( 219 "A = org.nanocontainer.testmodel.A\n" + 220 "container(:component_adapter_factory => $assembly_scope) {\n" + 221 " component(A)\n" + 222 "}"); 223 224 A a = new A(); 225 Mock cafMock = mock(ComponentAdapterFactory.class); 226 cafMock.expects(once()).method("createComponentAdapter").with(same(A.class), same(A.class), eq(null)) 227 .will(returnValue(new InstanceComponentAdapter(A.class, a))); 228 PicoContainer pico = buildContainer(script, null, cafMock.proxy()); 229 assertSame(a, pico.getComponentInstanceOfType(A.class)); 230 } 231 232 public void testCustomComponentMonitorCanBeSpecified() { 233 Reader script = new StringReader ( 234 "A = org.nanocontainer.testmodel.A\n" + 235 "StringWriter = java.io.StringWriter\n" + 236 "WriterComponentMonitor = org.picocontainer.monitors.WriterComponentMonitor\n" + 237 "writer = StringWriter.new\n" + 238 "monitor = WriterComponentMonitor.new(writer) \n" + 239 "container(:component_monitor => monitor) {\n" + 240 " component(A)\n" + 241 " component(:key => StringWriter, :instance => writer)\n" + 242 "}"); 243 244 PicoContainer pico = buildContainer(script, null, ASSEMBLY_SCOPE); 245 StringWriter writer = (StringWriter ) pico.getComponentInstanceOfType(StringWriter .class); 246 assertTrue(writer.toString().length() > 0); 247 } 248 249 public void testCustomComponentMonitorCanBeSpecifiedWhenCAFIsSpecified() { 250 Reader script = new StringReader ( 251 "A = org.nanocontainer.testmodel.A\n" + 252 "StringWriter = java.io.StringWriter\n" + 253 "WriterComponentMonitor = org.picocontainer.monitors.WriterComponentMonitor\n" + 254 "DefaultComponentAdapterFactory = org.picocontainer.defaults.DefaultComponentAdapterFactory\n" + 255 "writer = StringWriter.new\n" + 256 "monitor = WriterComponentMonitor.new(writer) \n" + 257 "container(:component_adapter_factory => DefaultComponentAdapterFactory.new, :component_monitor => monitor) {\n" 258 + 259 " component(A)\n" + 260 " component(:key => StringWriter, :instance => writer)\n" + 261 "}"); 262 263 PicoContainer pico = buildContainer(script, null, ASSEMBLY_SCOPE); 264 StringWriter writer = (StringWriter ) pico.getComponentInstanceOfType(StringWriter .class); 265 assertTrue(writer.toString().length() > 0); 266 } 267 268 public void testCustomComponentMonitorCanBeSpecifiedWhenParentIsSpecified() { 269 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(); 270 Reader script = new StringReader ( 271 "A = org.nanocontainer.testmodel.A\n" + 272 "StringWriter = java.io.StringWriter\n" + 273 "WriterComponentMonitor = org.picocontainer.monitors.WriterComponentMonitor\n" + 274 "writer = StringWriter.new\n" + 275 "monitor = WriterComponentMonitor.new(writer) \n" + 276 "container(:parent => $parent, :component_monitor => monitor) {\n" + 277 " component(A)\n" + 278 " component(:key => StringWriter, :instance => writer)\n" + 279 "}"); 280 281 PicoContainer pico = buildContainer(script, parent, ASSEMBLY_SCOPE); 282 StringWriter writer = (StringWriter ) pico.getComponentInstanceOfType(StringWriter .class); 283 assertTrue(writer.toString().length() > 0); 284 } 285 286 public void testCustomComponentMonitorCanBeSpecifiedWhenParentAndCAFAreSpecified() { 287 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(); 288 Reader script = new StringReader ( 289 "A = org.nanocontainer.testmodel.A\n" + 290 "StringWriter = java.io.StringWriter\n" + 291 "WriterComponentMonitor = org.picocontainer.monitors.WriterComponentMonitor\n" + 292 "DefaultComponentAdapterFactory = org.picocontainer.defaults.DefaultComponentAdapterFactory\n" + 293 "writer = StringWriter.new\n" + 294 "monitor = WriterComponentMonitor.new(writer) \n" + 295 "container(:parent => $parent, :component_adapter_factory => DefaultComponentAdapterFactory.new, :component_monitor => monitor) {\n" 296 + 297 " component(A)\n" + 298 " component(:key => StringWriter, :instance => writer)\n" + 299 "}"); 300 301 PicoContainer pico = buildContainer(script, parent, ASSEMBLY_SCOPE); 302 StringWriter writer = (StringWriter ) pico.getComponentInstanceOfType(StringWriter .class); 303 assertTrue(writer.toString().length() > 0); 304 } 305 306 public void testInstantiateWithImpossibleComponentDependenciesConsideringTheHierarchy() { 307 X.reset(); 308 Reader script = new StringReader ( 309 "A = org.nanocontainer.testmodel.A\n" + 310 "B = org.nanocontainer.testmodel.B\n" + 311 "C = org.nanocontainer.testmodel.C\n" + 312 "container {\n" + 313 " component(B)\n" + 314 " container() {\n" + 315 " component(A)\n" + 316 " }\n" + 317 " component(C)\n" + 318 "}"); 319 320 try { 321 buildContainer(script, null, ASSEMBLY_SCOPE); 322 fail("Should not have been able to instansiate component tree due to visibility/parent reasons."); 323 } catch(UnsatisfiableDependenciesException expected) { 324 } 325 } 326 327 public void testInstantiateWithChildContainerAndStartStopAndDisposeOrderIsCorrect() { 328 X.reset(); 329 Reader script = new StringReader ( 330 "A = org.nanocontainer.testmodel.A\n" + 331 "B = org.nanocontainer.testmodel.B\n" + 332 "C = org.nanocontainer.testmodel.C\n" + 333 "container {\n" + 334 " component(A)\n" + 335 " container() {\n" + 336 " component(B)\n" + 337 " }\n" + 338 " component(C)\n" + 339 "}\n"); 340 341 PicoContainer pico = buildContainer(script, null, ASSEMBLY_SCOPE); 343 pico.stop(); 344 pico.dispose(); 345 346 assertEquals("Should match the expression", "<A<C<BB>C>A>!B!C!A", X.componentRecorder); 347 } 348 349 public void testBuildContainerWithParentAttribute() { 350 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(); 351 parent.registerComponentInstance("hello", "world"); 352 353 Reader script = new StringReader ( 354 "A = org.nanocontainer.testmodel.A\n" + 355 "container(:parent => $parent) {\n" + 356 " component(A)\n" + 357 "}\n"); 358 359 PicoContainer pico = buildContainer(script, parent, ASSEMBLY_SCOPE); 360 assertEquals("world", pico.getComponentInstance("hello")); 362 } 363 364 public void testBuildContainerWithParentDependencyAndAssemblyScope() throws Exception { 365 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(); 366 parent.registerComponentImplementation("a", A.class); 367 368 String source = 369 "B = org.nanocontainer.testmodel.B\n" + 370 "SomeAssemblyScope = org.nanocontainer.testmodel.SomeAssemblyScope\n" + 371 "container(:parent => $parent) {\n" + 372 " if $assembly_scope.kind_of?(SomeAssemblyScope)\n " + 373 " component(B)\n" + 374 " end\n " + 375 "}\n"; 376 377 Reader script = new StringReader (source); 378 379 PicoContainer pico = buildContainer(script, parent, new SomeAssemblyScope()); 380 assertNotNull(pico.getComponentInstanceOfType(B.class)); 381 382 script = new StringReader (source); 383 pico = buildContainer(script, parent, ASSEMBLY_SCOPE); 384 assertNull(pico.getComponentInstanceOfType(B.class)); 385 } 386 387 public void testBuildContainerWithParentAndChildAssemblyScopes() throws IOException { 388 String scriptValue = 389 "A = org.nanocontainer.testmodel.A\n" + 390 "B = org.nanocontainer.testmodel.B\n" + 391 "ParentAssemblyScope = org.nanocontainer.testmodel.ParentAssemblyScope\n" + 392 "SomeAssemblyScope = org.nanocontainer.testmodel.SomeAssemblyScope\n" + 393 "container(:parent => $parent) {\n" + 394 " puts 'assembly_scope:'+$assembly_scope.inspect\n " + 395 " case $assembly_scope\n" + 396 " when ParentAssemblyScope\n " + 397 " puts 'parent scope'\n " + 398 " component(A)\n" + 399 " when SomeAssemblyScope\n " + 400 " puts 'child scope'\n " + 401 " component(B)\n" + 402 " else \n" + 403 " raise 'Invalid Scope: ' + $assembly_scope.inspect\n" + 404 " end\n " + 405 "}\n"; 406 407 Reader script = new StringReader (scriptValue); 408 NanoPicoContainer parent = new DefaultNanoPicoContainer( 409 buildContainer(script, null, new ParentAssemblyScope())); 410 assertNotNull(parent.getComponentAdapterOfType(A.class)); 411 412 script = new StringReader (scriptValue); 413 PicoContainer pico = buildContainer(script, parent, new SomeAssemblyScope()); 414 assertNotNull(pico.getComponentInstance(B.class)); 415 } 416 417 public void FAILING_testBuildContainerWithParentAttributesPropagatesComponentAdapterFactory() { 418 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(new SetterInjectionComponentAdapterFactory()); 419 Reader script = new StringReader ("container(:parent => $parent)\n"); 420 421 MutablePicoContainer pico = (MutablePicoContainer) buildContainer(script, parent, ASSEMBLY_SCOPE); 422 ComponentAdapter componentAdapter = pico.registerComponentImplementation(String .class); 424 assertTrue("ComponentAdapter should be originally defined by parent", 425 componentAdapter instanceof SetterInjectionComponentAdapter); 426 } 427 428 public void testExceptionThrownWhenParentAttributeDefinedWithinChild() { 429 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(new SetterInjectionComponentAdapterFactory()); 430 Reader script = new StringReader ( 431 "A = org.nanocontainer.testmodel.A\n" + 432 "B = org.nanocontainer.testmodel.B\n" + 433 "container() {\n" + 434 " component(A)\n" + 435 " container(:parent => $parent) {\n" + 436 " component(B)\n" + 437 " }\n" + 438 "}\n"); 439 440 try { 441 buildContainer(script, parent, ASSEMBLY_SCOPE); 442 fail("NanoContainerMarkupException should have been thrown."); 443 } catch(NanoContainerMarkupException ignore) { 444 } 446 } 447 448 public void testSpuriousAttributes() { 450 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(); 451 452 Reader script = new StringReader ( 453 "container(:jim => 'Jam', :foo => 'bar')"); 454 try { 455 buildContainer(script, parent, ASSEMBLY_SCOPE); 456 } catch(NanoContainerMarkupException ex) { 458 } 460 } 461 462 public void testWithDynamicClassPathThatDoesNotExist() { 463 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(); 464 try { 465 Reader script = new StringReader ( 466 "container {\n" + 467 " classPathElement(:path => 'this/path/does/not/exist.jar')\n" + 468 " component(:class => \"FooBar\")\n" + 469 "}"); 470 471 buildContainer(script, parent, ASSEMBLY_SCOPE); 472 fail("should have barfed with bad path exception"); 473 } catch(NanoContainerMarkupException e) { 474 } 476 477 } 478 479 public void testWithDynamicClassPath() { 480 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(); 481 Reader script = new StringReader ( 482 "TestHelper = org.nanocontainer.TestHelper\n" 483 + "testCompJar = TestHelper.getTestCompJarFile()\n" 484 + "compJarPath = testCompJar.getCanonicalPath()\n" 485 + "container {\n" 486 + " classPathElement(:path => compJarPath)\n" 487 + " component(:class => \"TestComp\")\n" 488 + "}" ); 489 490 MutablePicoContainer pico = (MutablePicoContainer) buildContainer(script, parent, ASSEMBLY_SCOPE); 491 492 assertEquals(1, pico.getComponentInstances().size()); 493 assertEquals("TestComp", pico.getComponentInstances().get(0).getClass() 494 .getName()); 495 } 496 497 public void testWithDynamicClassPathWithPermissions() { 498 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(); 499 Reader script = new StringReader ( 500 "TestHelper = org.nanocontainer.TestHelper\n" + 501 "SocketPermission = java.net.SocketPermission\n" 502 + "testCompJar = TestHelper.getTestCompJarFile()\n" 503 + "compJarPath = testCompJar.getCanonicalPath()\n" 504 + "container {\n" 505 + " classPathElement(:path => compJarPath) {\n" 506 + " grant(:perm => SocketPermission.new('google.com','connect'))\n" 507 + " }\n" 508 + " component(:class => \"TestComp\")\n" 509 + "}" ); 510 511 MutablePicoContainer pico = (MutablePicoContainer) buildContainer(script, parent, ASSEMBLY_SCOPE); 512 513 assertEquals(1, pico.getComponentInstances().size()); 514 } 517 518 public void testGrantPermissionInWrongPlace() { 519 DefaultNanoPicoContainer parent = new DefaultNanoPicoContainer(); 520 try { 521 Reader script = new StringReader ( 522 "TestHelper = org.nanocontainer.TestHelper\n" + 523 "SocketPermission = java.net.SocketPermission\n" + 524 "testCompJar = TestHelper.getTestCompJarFile()\n" + 525 "container {\n" + 526 " grant(:perm => SocketPermission.new('google.com','connect'))\n" + 527 "}"); 528 529 buildContainer(script, parent, ASSEMBLY_SCOPE); 530 fail("should barf with RaiseException"); 531 } catch(PicoCompositionException e) { 532 assertNotNull(e.getCause()); 533 assertTrue(e.getCause() instanceof RaiseException); 534 } 535 } 536 537 538 public void testWithParentClassPathPropagatesWithNoParentContainer() throws IOException { 539 File testCompJar = TestHelper.getTestCompJarFile(); 540 541 URLClassLoader classLoader = new URLClassLoader (new URL []{testCompJar.toURL()}, 542 this.getClass().getClassLoader()); 543 Class testComp = null; 544 545 try { 546 testComp = classLoader.loadClass("TestComp"); 547 } catch(ClassNotFoundException ex) { 548 fail("Unable to load test component from the jar using a url classloader"); 549 } 550 Reader script = new StringReader ( 551 "container(:parent => $parent) {\n" 552 + " component(:class => \"TestComp\")\n" 553 + "}"); 554 555 PicoContainer pico = buildContainer(new JRubyContainerBuilder(script, classLoader), null, null); 556 assertNotNull(pico); 557 Object testCompInstance = pico.getComponentInstance(testComp.getName()); 558 assertSame(testCompInstance.getClass(), testComp); 559 560 } 561 562 581 private PicoContainer buildContainer(Reader script, PicoContainer parent, Object scope) { 582 return buildContainer(new JRubyContainerBuilder(script, getClass().getClassLoader()), parent, scope); 583 } 584 } 585 | Popular Tags |