10 Replies Latest reply on Apr 8, 2010 1:33 PM by jaikiran pai

    Using a deployer to add jars to a webapp classpath.

    Stan Silvert Master

      In AS5 this was fairly straightforward.  But in AS6 the same code doesn't work.

       

      I want to add the JSF impl jars on the fly using a JSFDeployer.  The reason is that I want to allow different JSF impls or no impl at all.

       

      I did the following:

      • Removed jsf-libs directory from the classpath in jbossweb.sar/META-INF/jboss-structure.xml
      • extend AbstractSimpleVFSRealDeployer<JBossWebMetaData>
      • In constructor, setStage(DeploymentStages.POST_PARSE)
      • In deploy(VFSDeploymentUnit unit, JBossWebMetaData metaData), do this:

       

      {code}private void addClasspath(VFSDeploymentUnit unit, URL url) throws MalformedURLException
         {
             // note: url points to the directory where the JSF impl jars live
            try
            {                 
               // add jar files if url is a directory
               if (vFile.isDirectory())
               {
                  for (VirtualFile jarFile : vFile.getChildrenRecursively(JAR_FILTER))
                  {              
                     unit.addClassPath(jarFile);
                     System.out.println("$2 Added " + jarFile + " to classpath for " + unit.getName());
                  }
               }
            }
            catch (IOException e)
            {
               log.warn("Unable to add URL to classpath: " + url.toString());
            }
            catch (URISyntaxException e)
            {
               log.warn("Unable to add URL to classpath: " + url.toString());
            }
         }{code}

       

      The System.out shows me that the code found all the correct jars and called unit.AddClassPath().

      {quote}

      14:13:35,261 INFO  [STDOUT] $2 Added "/C:/projects/astrunk/build/target/jboss-6.0.0-SNAPSHOT/server/default/deployers/jsf.deployer/Mojarra-2.0/jsf-api.jar" to classpath for vfs:///C:/projects/astrunk/build/target/jboss-6.0.0-SNAPSHOT/server/default/deploy/jboss-jsf-20test-jsfunit.war


      14:13:35,267 INFO  [STDOUT] $2 Added "/C:/projects/astrunk/build/target/jboss-6.0.0-SNAPSHOT/server/default/deployers/jsf.deployer/Mojarra-2.0/jsf-impl.jar" to classpath for vfs:///C:/projects/astrunk/build/target/jboss-6.0.0-SNAPSHOT/server/default/deploy/jboss-jsf-20test-jsfunit.war

      {quote}

       

      But in AS6, Tomcat is no longer able to load the JSF impl classes.  The only reason it finds JBossJSFConfigureListener is because I unjarred the class and put it in the root of deployers/jsf.deployer:

       

      {quote}14:13:54,446 INFO  [TomcatDeployment] deploy, ctxPath=/jboss-jsf-20test-jsfunit
      14:13:54,507 ERROR [[/jboss-jsf-20test-jsfunit]] Error configuring application listener of class org.jboss.jsf.integration.config.JBossJSFConfigureListener: java.lang.NoClassDefFoundError: com/sun/faces/config/ConfigureListener
              at java.lang.ClassLoader.defineClass1(Native Method)
              at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
              at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
              at org.jboss.classloader.spi.base.BaseClassLoader.access$200(BaseClassLo
      ader.java:70)
              at org.jboss.classloader.spi.base.BaseClassLoader$2.run(BaseClassLoader.
      java:668)
              at org.jboss.classloader.spi.base.BaseClassLoader$2.run(BaseClassLoader.
      java:627)
              at java.security.AccessController.doPrivileged(Native Method)
              at org.jboss.classloader.spi.base.BaseClassLoader.loadClassLocally(BaseC
      lassLoader.java:626)
              at org.jboss.classloader.spi.base.BaseClassLoader.loadClassLocally(BaseC
      lassLoader.java:603){quote}

       

        • 1. Re: Using a deployer to add jars to a webapp classpath.
          Ales Justin Master

          My guess is that these new jars are not mounted soon enough.

                 for (VirtualFile jarFile : vFile.getChildrenRecursively(JAR_FILTER))            

           

          Does this really need to be recursive?

          If any jar inside that directory is already mounted, this is very consuming, as it will go very deep. :-)

          • 2. Re: Using a deployer to add jars to a webapp classpath.
            Stan Silvert Master

            Actually it probably doesn't need to be recursive.  I'll change that part.

             

            So how do I make sure the jars are mounted?

             

            Also, I started looking at your AS6 changes for the Seam deployer.  Should I extend from UrlIntegrationDeployer instead of AbstractSimpleVFSRealDeployer?

             

            Stan

            • 3. Re: Using a deployer to add jars to a webapp classpath.
              Ales Justin Master
              So how do I make sure the jars are mounted?

              By mounting them yourself in your deployer. :-)

              I think they will not be double mounted, and also make sure you unmount them as well.

              Also, I started looking at your AS6 changes for the Seam deployer.  Should I extend from UrlIntegrationDeployer instead of AbstractSimpleVFSRealDeployer?

              No, as that one doesn't do much else than what you're already doing.

              I probably need to think if I should also already do the mounting.

              I'll probably make it optional, so a user can choose, dependening on when he needs these new resources.

               

              btw: when do you need -- at which deployment stage / state -- these new resources?

              • 4. Re: Using a deployer to add jars to a webapp classpath.
                Stan Silvert Master

                They just need to be there when the TomcatDeployer needs them.  I think it's the Real stage.

                 

                Stan

                • 5. Re: Using a deployer to add jars to a webapp classpath.
                  Ales Justin Master
                  They just need to be there when the TomcatDeployer needs them.  I think it's the Real stage.

                  Hmmm, this is then strange, as VFSClassLoaderClassPathDeployer already mounts this in Describe.

                   

                  You will need to debug further / deeper. :-(

                  • 6. Re: Using a deployer to add jars to a webapp classpath.
                    Stan Silvert Master

                    Ales Justin wrote:

                     

                    They just need to be there when the TomcatDeployer needs them.  I think it's the Real stage.

                    Hmmm, this is then strange, as VFSClassLoaderClassPathDeployer already mounts this in Describe.

                     

                    You will need to debug further / deeper. :-(

                    Yea.  I tried mounting before adding to the classpath:

                     

                    {code}Automounter.mount(this, jarFile);{code}

                     

                    It didn't help.

                     

                    Stan

                    • 8. Re: Using a deployer to add jars to a webapp classpath.
                      Stan Silvert Master

                      Ales Justin wrote:

                       

                      Could it be some JBWeb change?

                      I don't know.  Maybe you can shed some light on this.  If I unjar the JSF classes into the root of my deployer it works:

                       

                      deployer/jsf.deployer/com/sun/faces .... Foo.class

                      deployer/jsf.deployer/javax/faces .... Bar.class

                       

                      Someone is classpathing the jsf.deployer directory for me.  In AS5 I had to do that myself.  So why would Tomcat see classes in my jsf.deployer directory but not in the jars that I explicitly added to the classpath?  And why does your Seam deployer work with Tomcat?  What is it doing differently?

                       

                      Stan

                      • 9. Re: Using a deployer to add jars to a webapp classpath.
                        Ales Justin Master
                        So why would Tomcat see classes in my jsf.deployer directory but not in the jars that I explicitly added to the classpath?

                        Since those are part of default CL domain aka big-ball-o-mud, shared by everyone.

                         

                        And why does your Seam deployer work with Tomcat?  What is it doing differently?

                        Dunno.

                         

                        Could be that it adds that jar to non-web (sub)deployment,

                        as I think the attachment is optional, since it only cares about matching file (some Seam known file).

                        (it might add that multiple times, but the first one would win anyway, and not much is in seam-int.jar)

                        • 10. Re: Using a deployer to add jars to a webapp classpath.
                          jaikiran pai Master

                          Stan Silvert wrote:

                           

                          But in AS6, Tomcat is no longer able to load the JSF impl classes.  The only reason it finds JBossJSFConfigureListener is because I unjarred the class and put it in the root of deployers/jsf.deployer:

                           

                          14:13:54,446 INFO  http://community.jboss.org/message/536136#536136/TomcatDeployment deploy, ctxPath=/jboss-jsf-20test-jsfunit

                          14:13:54,507 ERROR [[/jboss-jsf-20test-jsfunit]] Error configuring application listener of class org.jboss.jsf.integration.config.JBossJSFConfigureListener: java.lang.NoClassDefFoundError: com/sun/faces/config/ConfigureListener

                                  at java.lang.ClassLoader.defineClass1(Native Method)

                                  at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)

                                  at java.lang.ClassLoader.defineClass(ClassLoader.java:616)

                                  at org.jboss.classloader.spi.base.BaseClassLoader.access$200(BaseClassLo

                          ader.java:70)

                                  at org.jboss.classloader.spi.base.BaseClassLoader$2.run(BaseClassLoader.

                          java:668)

                                  at org.jboss.classloader.spi.base.BaseClassLoader$2.run(BaseClassLoader.

                          java:627)

                                  at java.security.AccessController.doPrivileged(Native Method)

                                  at org.jboss.classloader.spi.base.BaseClassLoader.loadClassLocally(BaseC

                          lassLoader.java:626)

                                  at org.jboss.classloader.spi.base.BaseClassLoader.loadClassLocally(BaseC

                          lassLoader.java:603)

                           

                           

                          A really wild guess (since I haven't really looked at this deployer in detail) - The TomcatDeployer (or the entity which is trying to configure the listener class) perhaps isn't using the deployment unit's classloader and instead is using the server level classloader (which doesn't contain those jsf jars in the classpath).