8 Replies Latest reply on Nov 24, 2010 4:49 AM by David Bosschaert

    Running AS7 embedded in Arquillian

    Thomas Diesler Master

      This post describes what I have done and seen when running AS7 embedded in Arquillian. There is a large overlap with what Kabir has done with embedded AS7 so lets try to converge.

       

      The JBossASEmbeddedContainer the StandaloneServerFactory and waits for the Arquillian MBean to become available

       

               Properties sysprops = new Properties();
               sysprops.putAll(System.getProperties());
               sysprops.setProperty("jboss.home.dir", jbossHomeDir.getAbsolutePath());
               sysprops.setProperty("java.util.logging.manager", "org.jboss.logmanager.LogManager");
               sysprops.setProperty("logging.configuration", "file:" + jbossHomeDir + "/standalone/configuration/logging.properties");
               sysprops.setProperty("org.jboss.boot.log.file", jbossHomeDir + "/standalone/log/boot.log");

       

               server = StandaloneServerFactory.create(jbossHomeDir, sysprops);
               server.start();

       

      The StandaloneServerFactory uses the InitialModuleLoaderFactory to bootstrap modules with a controlled set of packages from the app classpath. I agree with Jason, it is impossible to put stuff on the appclasspath and somehow hope the test deployemnts will behave like they would in a running server.

       

      For this to work in ARQ it is necessary that nothing initializes jdk logging before we have a chance to load the LoggingManager from the "org.jboss.logmanager" module. Therefore, I added a looging abstraction to ARQ that allows you do disable or redirect ARQ logging to System.out

       

               <plugin>
                  <artifactId>maven-surefire-plugin</artifactId>
                  <configuration>
                    <systemProperties>
                      <property>
                        <name>java.util.logging.manager</name>
                        <value>org.jboss.logmanager.LogManager</value>
                      </property>
                      <property>
                        <name>arquillian.logging</name>
                        <value>system</value>
                      </property>
                    </systemProperties>
                  </configuration>
                </plugin> 
      

       

      The StandaloneServerFactory loads the server module and uses reflection and a proxy to bootstrap the server.

       

      Currently, the server comes up and deployment fails with

       

      12:46:07,295 ERROR [org.jboss.as.protocol.connection] (pool-1-thread-2) Failed to read a message: java.util.ServiceConfigurationError: org.jboss.marshalling.ProviderDescriptor: Provider org.jboss.marshalling.river.RiverProviderDescriptor could not be instantiated: java.lang.ClassCastException
          at java.util.ServiceLoader.fail(ServiceLoader.java:207) [:1.6.0_21]
          at java.util.ServiceLoader.access$100(ServiceLoader.java:164) [:1.6.0_21]
          at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:353) [:1.6.0_21]
          at java.util.ServiceLoader$1.next(ServiceLoader.java:421) [:1.6.0_21]
          at org.jboss.marshalling.Marshalling.loadMarshallerFactory(Marshalling.java:78) [jboss-marshalling-1.3.0.CR8.jar:1.3.0.CR8]
          at org.jboss.marshalling.Marshalling.getMarshallerFactory(Marshalling.java:74) [jboss-marshalling-1.3.0.CR8.jar:1.3.0.CR8]
          at org.jboss.as.protocol.ProtocolUtils.<clinit>(ProtocolUtils.java:50) [jboss-as-protocol-7.0.0.Alpha1.jar:7.0.0.Alpha1]
          at org.jboss.as.protocol.mgmt.ManagementProtocolHeader.read(ManagementProtocolHeader.java:75) [jboss-as-protocol-7.0.0.Alpha1.jar:7.0.0.Alpha1]
          at org.jboss.as.protocol.mgmt.ManagementResponseHeader.read(ManagementResponseHeader.java:60) [jboss-as-protocol-7.0.0.Alpha1.jar:7.0.0.Alpha1]
          at org.jboss.as.protocol.mgmt.ManagementProtocolHeader.<init>(ManagementProtocolHeader.java:55) [jboss-as-protocol-7.0.0.Alpha1.jar:7.0.0.Alpha1]
          at org.jboss.as.protocol.mgmt.ManagementResponseHeader.<init>(ManagementResponseHeader.java:45) [jboss-as-protocol-7.0.0.Alpha1.jar:7.0.0.Alpha1]
          at org.jboss.as.protocol.mgmt.ManagementRequest$1.handle(ManagementRequest.java:124) [jboss-as-protocol-7.0.0.Alpha1.jar:7.0.0.Alpha1]
      
      

       

      StandaloneServer is now an interface that also supports StandaloneServer.stop(). The idea is that the factory installs a service that can be used to bring down the server.

       

      An AS7 Arquinllian test would look like this

       

      @RunWith(Arquillian.class)
      public class JBossASEmbeddedIntegrationTestCase
      {
         @Inject
         public ServiceContainer container;
      
         @Deployment
         public static JavaArchive createDeployment() throws Exception
         {
            JavaArchive archive = ShrinkWrap.create(JavaArchive.class, "test.jar");
            archive.addClasses(SimpleServiceActivator.class);
            String path = "META-INF/services/" + ServiceActivator.class.getName();
            URL resourceURL = JBossASEmbeddedIntegrationTestCase.class.getResource("/module/" + path);
            archive.addResource(new File(resourceURL.getFile()), path);
            return archive;
         }
      
         @Test
         public void testDeployedService() throws Exception
         {
            assertNotNull("ServiceContainer not null", container);
            ServiceController<?> controller = container.getRequiredService(SimpleService.SERVICE_NAME);
            SimpleService service = (SimpleService)controller.getValue();
            service.add(2, 3);
         }
      }
      
      

       

      The ServiceContainer is injected by the ServiceContainerEnricher. The test is deployed using the ServerDeploymentManager, which is part of the domain protocol.

       

       

      To try this out you need to checkout these branches

       

      https://github.com/jbosgi/arquillian/tree/jbas7

      https://github.com/jbosgi/jboss-as/tree/arquillian

       

      Build AS7 and in arquillian run

       

      mvn -Djboss.home=/home/tdiesler/git/jboss-as/build/target/jboss-7.0.0.Alpha2 -pl container/jbossas-embedded-7 -am install
      

       

      I'll talk this through with Kabir. So hopefully the demos and other smoke/integration tests can be embedded ARQ tests soon.

       

      cheers

      -thomas

        • 1. Re: Running AS7 embedded in Arquillian
          Thomas Diesler Master

          Following a call with Kabir, Aslak, David, and myself we agreed

           

          #1 Kabir gets the embedded AS7 to work in JBossASEmbeddedContainer. This is merges his work and my work and generally provides an API that allows AS7 embedded bootstrap with a minimal set of packages (i.e. idealy only org.jboss.modules) on the app classpath

           

          #2 David extends the ARQ JMX protocol to support the notion of events between test case and test client. The use case is that at runtime a test case can fetch additional archives from the test client. Aslak has done some design work around this. Later we port the JMX extension to the new ARQ Event API [JBOSGI-418]

           

          #3 Kabir ports the AS7 demos to ARQ when #1 is done. This should allow the demos to run at build time

           

          #4 I unify the code paths for deployed/installed bundles. Currently, 3rd party OSGi provisioners like the EOSGi JMX API shortcut the DeploymentChain. Generally, BundleContext.installBundle(...) must go through the DeploymentUnitProcessors like for any other deployment. This would allow to get rid of arquillian-osgi-bundle in AS7. The ARQ subsystem would see all deployments. [JBOSGI-427]

           

          #5 Unrelated to ARQ, but here for the record. I provide a ConfigAdmin subsytem that that can be used to maintain the configuration aspects of arbitrary deployments. It would also be compatible with the standard OSGi ConfigAdmin such that 3rd party bundles can get their configuration data from it. The data is maintained as part of the domain model and as such visible/editable by the AS7 management agent. [JBOSGI-425]

          • 2. Re: Running AS7 embedded in Arquillian
            Kabir Khan Master

            I have got AS started up in arquillian using the embedded stuff I've been working on, the test class currently needs these annotations:

             

            @RunWith(Arquillian.class)

            @Run(AS_CLIENT)

            @ModuleTestSetup(

                    testModule=@ModuleDef(

                            name="test.module",

                            packages={@PackageResource(directory="target/classes", packages={"org.jboss.arquillian.container.jboss.embedded_7"}),

                                    @PackageResource(directory="target/test-classes", packages={"org.jboss.arquillian.container.test.jboss.embedded_7"})},

                            dependencies= {@Dependency("javax.servlet.api")}),

                    tcclModule=@ModuleDef (

                            name="test.demos.tccl",

                            dependencies= {@Dependency("org.jboss.logging"), @Dependency("org.jboss.logmanager")})

            )

            @ClassFactory(JBossEmbeddedClassFactoryProvider.class)

            public class JBossEmbeddedContainerTestCase

             

             

            The @ClassFactory annotation is a signal to the Arquillian which now does this

             

               public Arquillian(Class<?> klass) throws InitializationError

               {

                  super(getTestClass(klass));

                  try

                  {

                     // first time we're being initialized

                     if(deployableTest.get() == null)

                     ....

               }

             

            The default behaviour of getTestClass() is to just return the original class. If @ClassFactory is there, it uses JBossEmbeddedClassFactoryProvider to set up the modules from @ModuleTestSetup, and then loads up the test class loaded from modules returns that. I need this hook, but how it is set up now was just a quick hack, so Aslak if you have any preferences on how to configure this please let me know.

             

            I got around the java.util.logging.Logging issues by setting the tcclModule's classloader as the thread context classloader in JBossEmbeddedClassFactoryProvider.getTestClass() so it gets initialized properly.

             

            I have not deployed anything yet but will look at that tomorrow along with tidying up the module setup, which I think when running in this framework is a bit too verbose at the moment. I am hoping that we can just define the dependencies for the test deployments and then to be able to generate each deployment's manifest.mf from the annotations.

             

             

            • 3. Re: Running AS7 embedded in Arquillian
              Thomas Diesler Master

              Ok, lets talk about this in more detail when you have something that runs and are generally happy with.

               

              I generally think that this

              @Dependency("org.jboss.logging"), @Dependency("org.jboss.logmanager")

               

              is evil because results in jboss proprietary manifest headers that also has an equivalent standard, which is Require-Bundle

              So instead of putting

              Dependencies: org.jboss.logging, org.jboss.logmanager

              we could also add

               

              Require-Bundle: org.jboss.logging, org.jboss.logmanager

               

              On the topic on why Require-Bundle is also bad see JBoss AS7 OSGi Integration half way down the page section

              3.12.3 Issues With Requiring Bundles

               

              Our demos should show the recommended set of AS7 best practises, so perhaps we need to reach a conclusion on 'Dependencies' vs. 'Require-Bundle' vs. 'Package-Import'

               

              For now I would say that 'Dependencies' does exist and gets processed by the DUP, but we should not promote its usage by introducing an annotation for it. How about requiring the user to explicitly put it in the @Deployment artifact manifest like I do in ModuleAccessesBundleServiceTestCase

               

                 private JavaArchive getClientModuleArchive() throws Exception
                 {
                    final JavaArchive archive = ShrinkWrap.create(JavaArchive.class, "example-xservice-client-module");
                    archive.addClasses(EchoInvokerService.class, ClientModuleActivator.class);
                    String activatorPath = "META-INF/services/" + ServiceActivator.class.getName();
                    archive.addResource(getResourceFile("xservice/client-module/" + activatorPath), activatorPath);
                    archive.setManifest(getResourceFile("xservice/client-module/" + JarFile.MANIFEST_NAME));
                    return archive;
                 }

               

              • 4. Re: Running AS7 embedded in Arquillian
                Kabir Khan Master

                I've taken a better look at your solution now, and we are taking two opposite approaches.

                 

                Most of my work was done before Brian pointed out to me that the -Djava.class.path system property has influence on what is visible to the module system. In my case I am making sure everything runs in modules, both the test itself and the server. This might be overkill and forces a lot of definition of modules etc. which although made simple to set up will still probably be confusing to users new to module classloading.

                 

                In your case the server is started up using modules with the classpath and with the test itself and its dependencies using the app classpath, the -Djava.class.path system property controls that the app classpath is not visible to the server. I will look more into your solution now, but what you have is a lot simpler to set for the user so I think we should go with something based on that. I would still like a hook in Arquillian to be able to set tccl before starting it so that your logging abstraction is not necessary.

                 

                For now I would say that 'Dependencies' does exist and gets processed by the DUP, but we should not promote its usage by introducing an annotation for it. How about requiring the user to explicitly put it in the @Deployment artifact manifest like I do in ModuleAccessesBundleServiceTestCase

                 

                   private JavaArchive getClientModuleArchive() throws Exception
                   {
                      final JavaArchive archive = ShrinkWrap.create(JavaArchive.class, "example-xservice-client-module");
                      archive.addClasses(EchoInvokerService.class, ClientModuleActivator.class);
                      String activatorPath = "META-INF/services/" + ServiceActivator.class.getName();
                      archive.addResource(getResourceFile("xservice/client-module/" + activatorPath), activatorPath);
                      archive.setManifest(getResourceFile("xservice/client-module/" + JarFile.MANIFEST_NAME));
                      return archive;
                   }

                 

                This is something I was already doing for the demos. I don't really like it though, I think it would be nicer to be able to specify this somehow from within the test itself rather than having loads of manifest files in the resources but we can talk about that later.

                • 5. Re: Running AS7 embedded in Arquillian
                  Jason Greene Master

                  Thomas Diesler wrote:

                   

                  Ok, lets talk about this in more detail when you have something that runs and are generally happy with.

                   

                  I generally think that this

                  @Dependency("org.jboss.logging"), @Dependency("org.jboss.logmanager")

                   

                  is evil because results in jboss proprietary manifest headers that also has an equivalent standard, which is Require-Bundle


                  But they are jboss modules, not osgi bundles. We should only use osgi manifest entries if the thing we are producing is an actual osgi bundle, that actually uses osgi. Also, I don't think we should mandate usage of OSGi across the board with AS.

                   

                  On the topic on why Require-Bundle is also bad see JBoss AS7 OSGi Integration half way down the page section

                  3.12.3 Issues With Requiring Bundles

                  As you know, I never really bought into the reasons behind packaged deps. I think OSGi is the only modularity spec that advocates them, and even they are moving away from them with their capabilities and requirements notion.

                  • 6. Re: Running AS7 embedded in Arquillian
                    Thomas Diesler Master
                    I would still like a hook in Arquillian to be able to set tccl before  starting it so that your logging abstraction is not necessary

                     

                    This won't help. If you look at the jdk LoggingManager you'll find that it ignores the TCCL when it finds the configured LoggingManager on the app classpath.

                     

                    Setting

                     

                    -Darquillian.logging=system|off

                     

                    should get you around that logging initilization issue. It works in Eclipse and mvn

                    • 7. Re: Running AS7 embedded in Arquillian
                      Thomas Diesler Master

                      That is fair enough as long as we have a clear understanding of what can be a module and what should be a bundle instead. With DavidL we had a continued discussion on validating the module wiring.

                       

                      My current idea is to move the XResolver down one layer and make it the "gate keeper" to the modules wiring API. Deployments that contain 'Dependencies' that would result in inconsistent wiring would not resolve and be rejected at deploy time. They can still be modules though. The static wiring in all modules.xml should be verified at build time.

                       

                      OSGi pretty much still consideres the package as the key for consistent class space wiring. Caps/Reqs extend and generalizes this notion. In 4.3 PackageCap/Req will probably show up in the API.

                      • 8. Re: Running AS7 embedded in Arquillian
                        David Bosschaert Expert

                        Jason Greene wrote:

                         

                        As you know, I never really bought into the reasons behind packaged deps. I think OSGi is the only modularity spec that advocates them, and even they are moving away from them with their capabilities and requirements notion.

                        No - OSGi is not moving away from the package dependency model, that is an incorrect observation. The generic capabilities and requirements provide an additional level of declaring dependencies in cases where you don't have this information available as packages. Examples are the existence of an IoC (beans that are being injected typically don't have a package dependency on the IoC container) or some other type of extender.

                         

                        OSGi is the most mature modularity system around today and although it supports other types of dependency declaration the package dependency model has been found the best dependency model by all OSGi experts that I know of.