1 2 3 4 5 6 Previous Next 77 Replies Latest reply on Oct 21, 2010 6:45 AM by Ales Justin Go to original post
      • 60. Re: Implementing a non-flat deployment for Weld Integration
        Flavia Rainone Master

        Ales Justin wrote:

         

        - we need also a mechanism to scan for libs referenced from manifest files, creating BDAs for any lib that contains META-INF/beans.xml

        How is this different from what we're already doing?

        Or, I think we're already covering this use case. Or not?

        We are not. I need to enable scanning of libs referenced by the manifest of deployed jars. The same goes for libs referenced by the manifest of lib jars (if any).

         

        Ales Justin wrote:

         

        Let me know when you're done, as I'm mostly done, but I have a few changes to your code,

        to make this integration easier / nicer.

         

        You can feel free to commit when you're done. I don't think that the stuff that you are doing, even if you refactor some of the BDA impl code, which you probably did, will affect too much the work I mentioned above.

         

        BTW, this is all that is left. The other two itens below are committed to trunk:

        - a FIXME that I had previously added to DeploymentImpl (regarding the undeployment of loaded BDAs)

        - replace ClasspathImpl by NoDuplicatesClasspath

        • 61. Re: Implementing a non-flat deployment for Weld Integration
          Flavia Rainone Master

          Flavia Rainone wrote:


          We are not. I need to enable scanning of libs referenced by the manifest of deployed jars. The same goes for libs referenced by the manifest of lib jars (if any).

           

          With the help of Ales, I learned that ArchiveFilesDeployer should already receive the manifest referenced classpath of deployed jars in the line flagged below:

           

              public void deploy(VFSDeploymentUnit unit, JBossWeldMetaData deployment) throws DeploymentException
               {
          >>>>>    Iterable<VirtualFile> classpaths = getClassPaths(unit);
                   for (VirtualFile cp : classpaths)
                   {
                      VirtualFile wbXml = cp.getChild("META-INF/beans.xml");
                      if (wbXml.exists())
                      {
                         // add url
                         wbFiles.add(wbXml);
                         // add classes
                         cpFiles.add(cp);
                      }
                   }
          

           

          That means that we shouldn't have to do any work on the weld-int side to make it work. Despite that, I didn't manage to make a 100% working example.

           

          I removed SentenceParser class from weld-translator.jar (the same used by testsuite deployers/weld) and added that class to a weld-translator-lib.jar. Then, I tried the following alternatives:

           

          - I first put weld-translator-lib.jar in /home/fla and referenced that jar from weld-translator.jar manifest file, with a series of ../:

          Class-Path: ../../../weld-translator-lib.jar

          VFSUtils.addManifestLocations correctly recognizes the jar, but WeldFilesDeployer receives a classpath like $JBOSS_HOME/server/all/deploy/weld-translator.jar/home/fla/weld-translator-lib.jar, which does not exist

           

          - I decided to get rid of the .. in the classpath and added weld-translator-lib.jar to server/all/deploy. The weld-translator.jar manifest classpath refers now to weld-translator-lib.jar, as in the attached file

            That one works (i.e., no deployment errors). However, it does not work 100% correctly, because the

          if (wbXml.exists())

          statement above (when checking for weld-translator-lib.jar/META-INF/beans.xml) returns false, when it should return true

           

          - finally, I tested the attached weld-translator.ear file, that contains weld-translator-lib.jar, and whose weld-translator.jar archive references that lib jar from its manifest. It doesn't work either. This time, VFSUtils.addManifestLocations recognizes the referenced jar, but the WeldFilesDeployer piece of code I pasted above does not get the extra classpath entry $JBOSS_HOME/server/all/deploy/weld-translator.ear/weld-translator-lib.jar. The outcome is the following deployment exception:

           

          15:50:42,482 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to
          Start: name=vfs:///home/fla/Development/projects/jbossas-trunkLATEST/build/target/jboss-6.0.0-SNAPSHOT/
          server/all/deploy/weld-translator.ear_WeldBootstrapBean state=Create: org.jboss.weld.exceptions.DeploymentException:
          WELD-001408 Unsatisfied dependencies for type [SentenceParser] with qualifiers [@Default] at injection point [[parameter 1] of [constructor] @Inject org.jboss.test.deployers.weld.translator.ejb.TextTranslator(SentenceParser)]
              at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:294)
          
          • 62. Re: Implementing a non-flat deployment for Weld Integration
            Flavia Rainone Master

            Flavia Rainone wrote:

             

             

            I removed SentenceParser class from weld-translator.jar (the same used by testsuite deployers/weld) and added that class to a weld-translator-lib.jar. Then, I tried the following alternatives:

             

            - I first put weld-translator-lib.jar in /home/fla and referenced that jar from weld-translator.jar manifest file, with a series of ../:

            Class-Path: ../../../weld-translator-lib.jar

            VFSUtils.addManifestLocations correctly recognizes the jar, but WeldFilesDeployer receives a classpath like $JBOSS_HOME/server/all/deploy/weld-translator.jar/home/fla/weld-translator-lib.jar, which does not exist

             

            - I decided to get rid of the .. in the classpath and added weld-translator-lib.jar to server/all/deploy. The weld-translator.jar manifest classpath refers now to weld-translator-lib.jar, as in the attached file

              That one works (i.e., no deployment errors). However, it does not work 100% correctly, because the

            if (wbXml.exists())
            

            statement above (when checking for weld-translator-lib.jar/META-INF/beans.xml) returns false, when it should return true

             

            I found the cause of that if statement failure and opened a new thread discussion for that.

            With the fix I wrote, the scenarios above work ok, with one exception: if weld-translator-lib.jar is in the deploy dir as well, I'm afraid a double deployment takes place (notice I'm not sure if this is the cause) and I get this deployment exception:

             

            00:45:26,056 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to Start: name=vfs:///home/fla/Development/projects/jbossas-trunkLATEST/build/target/jboss-6.0.0-SNAPSHOT/server/all/deploy/weld-translator.jar_WeldBootstrapBean state=Create: org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [SentenceParser] with qualifiers [@Default] at injection point [[parameter 1] of [constructor] @Inject org.jboss.test.deployers.weld.translator.ejb.TextTranslator(SentenceParser)]. Possible dependencies [[Managed Bean [class org.jboss.test.deployers.weld.translator.ejb.SentenceParser] with qualifiers [@Any @Default], Managed Bean [class org.jboss.test.deployers.weld.translator.ejb.SentenceParser] with qualifiers [@Any @Default]]]
                at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:298) [:2010-08-30 15:40]
                at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:132) [:2010-08-30 15:40]
                at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:151) [:2010-08-30 15:40]
                at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:366) [:2010-08-30 15:40]
                at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:352) [:2010-08-30 15:40]
                at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:436) [:2010-08-30 15:40]
            

             

            Is it correct to assume that this scenario is not feasible and move on? I'm not sure if the test I'm performing is correct in this case.

             

            Flavia Rainone wrote:


            - finally, I tested the attached weld-translator.ear file, that contains weld-translator-lib.jar, and whose weld-translator.jar archive references that lib jar from its manifest. It doesn't work either. This time, VFSUtils.addManifestLocations recognizes the referenced jar, but the WeldFilesDeployer piece of code I pasted above does not get the extra classpath entry $JBOSS_HOME/server/all/deploy/weld-translator.ear/weld-translator-lib.jar. The outcome is the following deployment exception:

             

            15:50:42,482 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to
            Start: name=vfs:///home/fla/Development/projects/jbossas-trunkLATEST/build/target/jboss-6.0.0-SNAPSHOT/
            server/all/deploy/weld-translator.ear_WeldBootstrapBean state=Create: org.jboss.weld.exceptions.DeploymentException:
            WELD-001408 Unsatisfied dependencies for type [SentenceParser] with qualifiers [@Default] at injection point [[parameter 1] of [constructor] @Inject org.jboss.test.deployers.weld.translator.ejb.TextTranslator(SentenceParser)]
                at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:294)
            

             

            The problem here is that WeldFilesDeployer.getClasspaths filters out the manifest referenced classpath, just because it is not contained inside the weld-translator.ear/weld-translator.jar archive. I commented out the filtering and no tests were broken.

             

            That "fix" is committed along with a new testsuite test that reproduces the scenario above. Ales, do you remember for what reason WeldFilesDeployer was filtering the classpath entries? I need to know if I can delete that method or if it is needed for some specific scenario.

            • 63. Re: Implementing a non-flat deployment for Weld Integration
              Ales Justin Master
              The problem here is that WeldFilesDeployer.getClasspaths filters out the manifest referenced classpath, just because it is not contained inside the weld-translator.ear/weld-translator.jar archive. I commented out the filtering and no tests were broken.

               

              That "fix" is committed along with a new testsuite test that reproduces the scenario above. Ales, do you remember for what reason WeldFilesDeployer was filtering the classpath entries? I need to know if I can delete that method or if it is needed for some specific scenario.

              I think you're right -- the full classpath should be considered.

              Filtering was more of a brain dump from some old code, which actually needed this filtering.

              e.g. only valid classpath were the deployments paths, which is not the case here as your example shows it

               

              I'll remove the unneeded code.

              • 64. Re: Implementing a non-flat deployment for Weld Integration
                Ales Justin Master
                OK, I still need to think about this one a bit.

                If you enable libArchivesProvider in weld-deployers-jboss-beans.xml,
                you'll get the loop below:

                 

                What's the right solution for this?

                 

                ---------------------

                 

                       at org.jboss.weld.integration.deployer.env.bda.ClasspathFactory.getClasspath(ClasspathFactory.java:142) [:6.0.0-SNAPSHOT]
                       at org.jboss.weld.integration.deployer.env.bda.ClasspathFactory.create(ClasspathFactory.java:120) [:6.0.0-SNAPSHOT]
                       at org.jboss.weld.integration.deployer.env.bda.ArchiveInfo.<init>(ArchiveInfo.java:85) [:6.0.0-SNAPSHOT]
                       at org.jboss.weld.integration.deployer.env.bda.LibraryDiscoveryService.getLibraries(LibraryDiscoveryService.java:108) [:6.0.0-SNAPSHOT]
                       at org.jboss.weld.integration.deployer.env.bda.ClasspathFactory.getClasspath(ClasspathFactory.java:137) [:6.0.0-SNAPSHOT]
                       at org.jboss.weld.integration.deployer.env.bda.ClasspathFactory.create(ClasspathFactory.java:120) [:6.0.0-SNAPSHOT]
                       at org.jboss.weld.integration.deployer.env.bda.ArchiveInfo.<init>(ArchiveInfo.java:85) [:6.0.0-SNAPSHOT]
                       at org.jboss.weld.integration.deployer.env.bda.LibraryDiscoveryService.getLibraries(LibraryDiscoveryService.java:108) [:6.0.0-SNAPSHOT]
                       at org.jboss.weld.integration.deployer.env.bda.ClasspathFactory.getClasspath(ClasspathFactory.java:137) [:6.0.0-SNAPSHOT]
                       at org.jboss.weld.integration.deployer.env.bda.ClasspathFactory.create(ClasspathFactory.java:120) [:6.0.0-SNAPSHOT]
                       at org.jboss.weld.integration.deployer.env.bda.ArchiveInfo.<init>(ArchiveInfo.java:85) [:6.0.0-SNAPSHOT]

                • 65. Re: Implementing a non-flat deployment for Weld Integration
                  Ales Justin Master

                  Flavia Rainone wrote:

                   

                  IMO, I would move the initialization of default domain to a static block. In this block, I would also add the lib Archives after the default domain is created:
                  - we know that ClasspathFactory will be loaded only when it is needed. At the time ClasspathFactory is loaded, hence, it is because we are on a deploy process and it means that we will need default domain, so no gain in initializing DefaultClasspath inside of getClasspath
                  - if the libraries are loaded after ClasspathFactory, we won't enter the loop
                  - if the libraries are loaded in a static block, we know that nobody is using ClasspathFactory, so we know nobody will get his hands on a DefaultClasspath that lacks the lib Archives
                  - you get rid of the synchronized (DefaultDomain) block. No need to synchronize just to return something that is already initialized. As almost every request to create a classpath will recursively enter this block, this is a nice thing

                  Regardless of whether you decide to move it to a static block, which is personal choice, if you load the DefaultClasspath prior to creating the lib archives, you will get rid of the infinite loop. The reason for this is that ArchiveInfo transparently creates a Classpath to represent the associated ClassLoader domain.
                  • 66. Re: Implementing a non-flat deployment for Weld Integration
                    Ales Justin Master
                    IMO, I would move the initialization of default domain to a static block. In this block, I would also add the lib Archives after the default domain is created:

                    The initialization cannot be in a static block, since the libs provider is dynamic -- injected via MC beans.

                     

                    - if the libraries are loaded after ClasspathFactory, we won't enter the loop

                    OK, while this might save us from this curent loop,

                    having Classpath that refs itself seems like asking for another loop trouble.

                     

                    Isn't there a better/safer aka proper way of doing this?

                    • 67. Re: Implementing a non-flat deployment for Weld Integration
                      Ales Justin Master
                      - finally, I tested the attached weld-translator.ear file, that contains weld-translator-lib.jar, and whose weld-translator.jar archive references that lib jar from its manifest. It doesn't work either. This time, VFSUtils.addManifestLocations recognizes the referenced jar, but the WeldFilesDeployer piece of code I pasted above does not get the extra classpath entry $JBOSS_HOME/server/all/deploy/weld-translator.ear/weld-translator-lib.jar. The outcome is the following deployment exception:

                      This test is actually semi-broken, as it doesn't exactly/propery test what you had in mind.

                      The catch is in the way we handle sub-deployments in .ear.

                      Even though they are not referenced in application.xml, they are still considered to be real ear contents; see EARStructure.

                       

                      So, in your case, the SentenceParser bean could come or be refed (in Weld) from just another sub-deployment,

                      hence not actually thru manifest reference.

                      • 68. Re: Implementing a non-flat deployment for Weld Integration
                        Flavia Rainone Master

                        Ales Justin wrote:

                         

                        IMO, I would move the initialization of default domain to a static block. In this block, I would also add the lib Archives after the default domain is created:

                        The initialization cannot be in a static block, since the libs provider is dynamic -- injected via MC beans.

                         

                        Indeed.

                        In that case, an alternative is adding the libs at the exact moment setLibArchivesProvider is invoked. We could initialize the DefaultClasspath inside that method, that would need another name now, or we could initialize it staticaly again. Either way, this matter of initializing it statically or inside create is personal. I just think that it would be nice to get rid of the synchronized block and to get rid of the "if defaultClasspath is null", given that everytime ClasspathFactory is invoked, we will end up needing DefaultClasspath anyway.

                        Ales Justin wrote:

                         

                        - if the libraries are loaded after ClasspathFactory, we won't enter the loop

                        OK, while this might save us from this curent loop,

                        having Classpath that refs itself seems like asking for another loop trouble.

                         

                        Isn't there a better/safer aka proper way of doing this?

                        I think that the proper way is to initialize the parent container , i.e, DefaultClasspath, prior to initializing all the rest, including its contents, i.e., Archive/ArchiveInfo structure. Isn't it done this way with default domain initialization vs class loader initializations?

                         

                        The Archive/ArchiveInfo structure is written in a way that assumes that the container (Classpath) to which an Archive will be added is already created or, if not, will be created transparently, mirroring the ClassLoader structure. This saves whoever is the Archive client the trouble of having to worry about Classpaths. Transparently as well, the ArchiveInfo/Archive/Classpath structure reaccomodates itself to mirror BDAs created and BDAs not created.I wrote it this way because I was following the natural order of deployment, and I wanted to keep the deployers as simple as possible.

                         

                        So, in order to create BDAs for the libs, the best way IMO is to initialize DefaultClasspath without any contents,  and rename LibraryDiscoveryService.getLibraries method to discoverServices, loadServices, or something like that. You won't need any return value for that method because, at the moment it creates ArchiveInfo, the corresponding Classpath structure is initialized, and the structure is updated when you create an Archive out of it and extract the BDAs. Meaning that DefaultClasspath will automaticaly add the created Archives to itself.

                         

                        BTW DefaultClasspath does not ref itself, as the classpaths mirror the domain structure.

                        • 69. Re: Implementing a non-flat deployment for Weld Integration
                          Flavia Rainone Master

                          As the pseudocode below shows, we need to know which services should be added to the lib BDAs:

                           

                          Flavia Rainone wrote:

                          Roughly speaking, this is how we would fill in the gaps of the TODO mark you added in your getLibraries method:

                           

                          ... 
                          // finally create the Archive
                          Archive archive = ArchiveFactory.createArchive(archiveInfo, new ArrayList<EjbDescriptor<?>>());
                          // ... and the corresponding BDA
                          ServiceRegistry serviceRegistry = new SimpleServiceRegistry();
                          // TODO: fill in serviceRegistry? With which services?
                          libs.add(archive.createBeanDeploymentArchive(serviceRegistry));

                           

                          Right now, Ales is getting the following error because of the missing services:

                           

                          IllegalStateException: WELD-000117 Required service org.jboss.weld.injection.spi.ResourceInjectionServices
                                                 has not been specified
                          

                           

                           

                          Pete or Marius, do you know which services we need to add to these BDAs?

                          This is one of the final missing pieces to close this issue :-)

                          • 70. Re: Implementing a non-flat deployment for Weld Integration
                            Ales Justin Master
                            Right now, Ales is getting the following error because of the missing services:

                             

                            IllegalStateException: WELD-000117 Required service org.jboss.weld.injection.spi.ResourceInjectionServices
                                                   has not been specified
                            

                             

                             

                            Pete or Marius, do you know which services we need to add to these BDAs?

                            This is one of the final missing pieces to close this issue :-)

                             

                            Let me try no-op ServiceRegistry first ...

                            • 71. Re: Implementing a non-flat deployment for Weld Integration
                              Ales Justin Master
                              Let me try no-op ServiceRegistry first ...

                              This looks like it might work.

                               

                              But then I hit another issue: BeanDeploymentArchiveImpl::getBeansXml

                               

                              public BeansXml getBeansXml()
                                 {
                                    Collection<URL> urls = archive.getXmlURLs();
                                    if (urls.isEmpty())
                                    {
                                       return BeansXml.EMPTY_BEANS_XML;
                                    }
                                    return bootstrap.parse(urls);
                                 }

                               

                              The problem is that lib BDAs don't have bootstrap.

                              And bootstrap impl is only available in weld-core, which is dynamically added to deployments != libs.

                               

                              I could duplicate all beans xml parsing logic from weld-core,

                              but I don't see a reason why this couldn't be put into spi?

                               

                              Pete?

                              • 72. Re: Implementing a non-flat deployment for Weld Integration
                                Ales Justin Master

                                OK, got past the "parse urls" issue.

                                 

                                App got deployed, but failed when looking for matching beans:

                                 

                                18:19:46,737 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to Start: name=vfs:///Users/alesj/projects/jboss6/trunk/testsuite/output/lib/weld-translator3rdpartylib.ear_WeldBootstrapBean state=Create: org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [SentenceParser] with qualifiers [@Default] at injection point [[parameter 1] of [constructor] @Inject org.jboss.test.deployers.weld.translator.ejb.TextTranslator(SentenceParser)]
                                    at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:294) [:6.0.0-SNAPSHOT]
                                    at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:132) [:6.0.0-SNAPSHOT]
                                    at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:151) [:6.0.0-SNAPSHOT]
                                    at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:366) [:6.0.0-SNAPSHOT]
                                    at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:352) [:6.0.0-SNAPSHOT]
                                    at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:436) [:6.0.0-SNAPSHOT]
                                    at org.jboss.weld.integration.deployer.env.helpers.BootstrapBean.boot(BootstrapBean.java:124) [:6.0.0-SNAPSHOT]

                                 

                                The "lib" is where it should be:

                                 

                                Skywalker:~ alesj$ cd jboss/build/target/jboss-6.0.0-SNAPSHOT/common/lib
                                Skywalker:lib alesj$ ls | grep weld
                                weld-api.jar
                                weld-translator-lib.jar

                                 

                                Skywalker:lib alesj$ jar -tf weld-translator-lib.jar
                                META-INF/
                                META-INF/MANIFEST.MF
                                org/
                                org/jboss/
                                org/jboss/test/
                                org/jboss/test/deployers/
                                org/jboss/test/deployers/weld/
                                org/jboss/test/deployers/weld/translator/
                                org/jboss/test/deployers/weld/translator/ejb/
                                org/jboss/test/deployers/weld/translator/ejb/SentenceParser.class
                                META-INF/beans.xml

                                 

                                The AS6 test is WeldTranslator3rdPartyLibExampleUnitTestCase.

                                You have to manually copy the weld-translator-lib.jar to common/lib/.

                                 

                                Any ideas?

                                • 73. Re: Implementing a non-flat deployment for Weld Integration
                                  Flavia Rainone Master

                                  Ales Justin wrote:

                                   

                                  Any ideas?

                                  Thanks for your help with this, Ales!

                                  I'll take a look to see what's wrong.

                                  • 74. Re: Implementing a non-flat deployment for Weld Integration
                                    Flavia Rainone Master

                                    Ales, your lib scanning code works like a charm :-)

                                     

                                    The only piece that was missing is to uncomment the injection of libArchiveProvider into ClasspathFactory:

                                    <bean name="WeldClasspathFactory" class="org.jboss.weld.integration.deployer.env.bda.ClasspathFactory">
                                          <constructor factoryMethod="getInstance" />
                                          <property name="system"><inject bean="ClassLoaderSystem"/></property>
                                          <!-- Disable until we fix the loop -->
                                          <!-- property name="libArchivesProvider"><inject bean="LibsDiscoveryService"/></property -->
                                       </bean>
                                    

                                     

                                    The fix is committed to JBoss AS trunk.