6 Replies Latest reply on Feb 5, 2009 3:08 AM by alesj

    LinkageError with gwt-user.jar

    alaiseca

      Hi, I'm getting this error when deploying my application under AS5:

      javax.servlet.ServletException: java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/jasper/servlet/JasperLoader) previously initiated loading for a different type with name "javax/servlet/http/HttpServletRequest"
      org.apache.jasper.servlet.JspServlet.service(JspServlet.java:257)
      javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
      org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)

      Looks to me that under this version there is some kind of conflict with the javax.servlet package which happens to be included in gwt-user.jar, too. I cannot undeploy this jar because my app depends on com.google.gwt.user.server.rpc.RemoteServiceServlet, which is also part of gwt-user.jar. In previous versions of JBoss (4.0.2 and 4.2.3) I never experienced such a problem. I could try removing the javax.* packages from gwt-user.jar and see if it works, but first I would like to know if there is cleaner way to deal with this problem.

      Thanks

        • 1. Re: LinkageError with gwt-user.jar
          jaikiran

           

          gwt-user.jar


          That reminds me of a weird issue some other user had run into in JBossAS-5.0 GA http://www.jboss.com/index.html?module=bb&op=viewtopic&t=149044

          Looks to me that under this version there is some kind of conflict with the javax.servlet package which happens to be included in gwt-user.jar, too. I cannot undeploy this jar because my app depends on com.google.gwt.user.server.rpc.RemoteServiceServlet, which is also part of gwt-user.jar.

          Are you sure its the gwt-user.jar which is having that package and not the gwt-servlet.jar? If it's the gwt-servlet.jar, then i guess you can remove it from your application - you may not need it.

          Having said that, i remember there was a way (atleast in JBossAS4.x) where you specified, ignore xxx.yyy.* package from my application and use the one from the server. Let me see if i can find that configuration for AS5.


          • 2. Re: LinkageError with gwt-user.jar
            jaikiran

             

            "jaikiran" wrote:


            Having said that, i remember there was a way (atleast in JBossAS4.x) where you specified, ignore xxx.yyy.* package from my application and use the one from the server. Let me see if i can find that configuration for AS5.


            In AS-4.x, there was this:

            <attribute name="FilteredPackages">javax.servlet</attribute>


            in %JBOSS_HOME%/server/< serverName>/deploy/jboss-web.deployer/META-INF/jboss-service.xml for the jboss.web:service=WebServer MBean.

            The MBeans have been refactored to MC Beans in JBossAS5 and the corresponding property for the bean can be found in %JBOSS_HOME%/server/< serverName>/deployers/jboss-web.deployer/META-INF/war-deployers-jboss-beans.xml:

            <!-- The list of package prefixes that should not be loaded without
             delegating to the parent class loader before trying the web app
             class loader. The packages listed here are those tha are used by
             the web container implementation and cannot be overriden. The format
             is a comma separated list of the package names. There cannot be any
             whitespace between the package prefixes.
             This setting only applies when UseJBossWebLoader=false.
             -->
             <property name="filteredPackages">javax.servlet,org.apache.commons.logging</property>


            So assuming you haven't changed any of these changes, i guess having the javax.servlet classes in your application packaging should not have caused issues.


            • 3. Re: LinkageError with gwt-user.jar
              alaiseca

              Thanks, jaikiran. Yes, I can confirm that the source of the problem was gwt-user.jar. I manually created another jar without javax.servlet and the error is gone. I reviewed the file you mentioned and indeed, I have exactly the same configuration (I never touched it). From the last paragraph in the comment, I see this setting takes place only when UseJBossWebLoader=false. Where can I find this parameter? What is the default value? Again, I have not touched it, so if the default is true, maybe that's the reason why the setting is not working.

              Thanks

              • 4. Re: LinkageError with gwt-user.jar
                jaikiran

                I just reproduced this and looks like the package filtering by the deployer is broken. Here's what i tried:

                1) Create a simple war containing a simple servlet which just prints out a hello message
                2) In the WEB-INF/lib of the war, placed a jar file which contains javax.servlet.* package (just copied the jboss-javaee.jar from the %JBOSS_HOME%/common/lib).
                3) No other changes to the server configurations (a clean JBossAS5 GA).
                4) Started the server and accessed the URL to invoke the servlet.
                5) Got this exception:

                19:35:54,802 ERROR [[MyTestServlet]] Servlet.service() for servlet MyTestServlet threw exception
                javax.servlet.ServletException: non-HTTP request or response
                 at javax.servlet.http.HttpServlet.service(HttpServlet.java:801)
                 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
                 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                 at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
                 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
                 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
                 at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
                 at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
                 at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
                 at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
                 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
                 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
                 at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
                 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
                 at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
                 at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:828)
                 at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:601)
                 at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
                 at java.lang.Thread.run(Thread.java:595)
                


                -verbose:class JVM parameter shows me this:

                ....//deleted some lines
                [Loaded org.apache.tomcat.util.net.JIoEndpoint$WorkerStack from jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/jbossweb.sar/jbossweb.jar!/]
                [Loaded javax.servlet.ServletRequest from jar:file:/opt/jpai/jboss-5.0.0.GA/common/lib/servlet-api.jar!/]
                [Loaded javax.servlet.http.HttpServletRequest from jar:file:/opt/jpai/jboss-5.0.0.GA/common/lib/servlet-api.jar!/]
                [Loaded org.apache.catalina.connector.Request from jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/jbossweb.sar/jbossweb.jar!/]
                [Loaded javax.servlet.ServletResponse from jar:file:/opt/jpai/jboss-5.0.0.GA/common/lib/servlet-api.jar!/]
                [Loaded javax.servlet.http.HttpServletResponse from jar:file:/opt/jpai/jboss-5.0.0.GA/common/lib/servlet-api.jar!/]
                
                ...// again deleted some more lines
                
                [Loaded org.apache.catalina.connector.RequestFacade from jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/jbossweb.sar/jbossweb.jar!/]
                [Loaded org.jboss.security.SecurityRolesAssociation from jar:file:/opt/jpai/jboss-5.0.0.GA/common/lib/jbosssx.jar!/]
                [Loaded javax.servlet.ServletRequestEvent from jar:file:/opt/jpai/jboss-5.0.0.GA/common/lib/servlet-api.jar!/]
                [Loaded javax.servlet.http.HttpServletResponse from jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/test.war/WEB-INF/lib/jboss-javaee.jar!/]
                [Loaded org.jboss.servlet.http.HttpEventServlet from jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/jbossweb.sar/jbossweb.jar!/]
                [Loaded org.apache.catalina.core.ApplicationFilterFactory from jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/jbossweb.sar/jbossweb.jar!/]
                [Loaded javax.servlet.FilterChain from jar:file:/opt/jpai/jboss-5.0.0.GA/common/lib/servlet-api.jar!/]
                [Loaded org.jboss.servlet.http.HttpEventFilterChain from jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/jbossweb.sar/jbossweb.jar!/]
                [Loaded org.apache.catalina.core.ApplicationFilterChain from jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/jbossweb.sar/jbossweb.jar!/]
                [Loaded org.apache.catalina.connector.ResponseFacade from jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/jbossweb.sar/jbossweb.jar!/]
                [Loaded javax.servlet.http.HttpServletRequest from jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/test.war/WEB-INF/lib/jboss-javaee.jar!/]
                19:35:54,802 ERROR [[MyTestServlet]] Servlet.service() for servlet MyTestServlet threw exception
                javax.servlet.ServletException: non-HTTP request or response
                 at javax.servlet.http.HttpServlet.service(HttpServlet.java:801)


                Based on this default configuration of the deployer:

                <!-- Allow for war local class loaders: in testing -->
                 <bean name="WarClassLoaderDeployer" class="org.jboss.web.tomcat.service.deployers.WarClassLoaderDeployer">
                 <property name="relativeOrder">-1</property>
                
                 <property name="includeWebInfInClasspath">true</property>
                 <property name="filteredPackages">javax.servlet,org.apache.commons.logging</property>
                
                 </bean>
                
                
                <!-- The WebMetaData to service mbean deployer -->
                 <bean name="WarDeployer" class="org.jboss.web.tomcat.service.deployers.TomcatDeployer">
                 ...
                
                 <!-- Get the flag indicating if the normal Java2 parent first class
                 loading model should be used over the servlet 2.3 web container first
                 model.
                 -->
                 <property name="java2ClassLoadingCompliance">false</property>
                 <!-- A flag indicating if the JBoss Loader should be used. This loader
                 uses a unified class loader as the class loader rather than the tomcat
                 specific class loader.
                 The default is false to ensure that wars have isolated class loading
                 for duplicate jars and jsp files.
                 -->
                 <property name="useJBossWebLoader">false</property>
                 <!-- The list of package prefixes that should not be loaded without
                 delegating to the parent class loader before trying the web app
                 class loader. The packages listed here are those tha are used by
                 the web container implementation and cannot be overriden. The format
                 is a comma separated list of the package names. There cannot be any
                 whitespace between the package prefixes.
                 This setting only applies when UseJBossWebLoader=false.
                 -->
                 <property name="filteredPackages">javax.servlet,org.apache.commons.logging</property>
                
                ...


                the javax.servlet.* classes from the jars in .war/WEB-INF/lib should have been ignored. But that's not happening.


                • 5. Re: LinkageError with gwt-user.jar
                  jaikiran

                   

                  "jaikiran" wrote:
                  I just reproduced this and looks like the package filtering by the deployer is broken.


                  Got it! It turns out to be an issue in org.jboss.classloader.spi.filter.PackageClassFilter in jboss-cl project. This class is responsible for matching the package names of classes being loaded against a set of filtered packages. However, this seems to be having an issue in the regex pattern that is being used for doing this match. This class currently successfully matches only those classes which are directly under the filtered package. For example, if your filteredPackage is "javax.servlet", then this is going to match (and ultimately filter) classes which are directly under javax.servlet (ex: javax.servlet.ServletException) but not any classes under the sub-packages (ex: javax.servlet.http.HttpServletRequest will not be filtered by this class). So effectively, some of the classes get loaded from the jar present in the web application even after i have added the filteredPackage setting.

                  The org.jboss.classloading TRACE level logs proved to be very informative in helping debug this issue. So here's the relevant part from the logs:


                  2009-02-05 11:20:06,473 TRACE [org.jboss.classloading.spi.vfs.policy.VFSClassLoaderPolicy] getProtectionDomain:className=javax.servlet.ServletRequestEvent path=javax/servlet/ServletRequestEvent.class codeSourceURL=jar:file:/opt/jpai/jboss-5.0.0.GA/common/lib/servlet-api.jar!/
                  2009-02-05 11:20:06,475 TRACE [org.jboss.classloading.spi.vfs.policy.VFSClassLoaderPolicy] getProtectionDomain:className=javax.servlet.http.HttpServletResponse path=javax/servlet/http/HttpServletResponse.class codeSourceURL=jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/test.war/WEB-INF/lib/jboss-javaee.jar!/
                  2009-02-05 11:20:06,475 TRACE [org.jboss.classloading.spi.vfs.policy.VFSClassLoaderPolicy] VFSClassLoaderPolicy@1c66162{vfsfile:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/test.war/} getResource path=javax/servlet/ServletException.class matches exclude filter: [javax.servlet, org.apache.commons.logging]
                   2009-02-05 11:20:06,479 TRACE [org.jboss.classloading.spi.vfs.policy.VFSClassLoaderPolicy] getProtectionDomain:className=org.jboss.servlet.http.HttpEventServlet path=org/jboss/servlet/http/HttpEventServlet.class codeSourceURL=jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/jbossweb.sar/jbossweb.jar!/
                  ...
                  ....
                  2009-02-05 11:20:06,487 TRACE [org.jboss.classloading.spi.vfs.policy.VFSClassLoaderPolicy] getProtectionDomain:className=javax.servlet.http.HttpServletRequest path=javax/servlet/http/HttpServletRequest.class codeSourceURL=jar:file:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/test.war/WEB-INF/lib/jboss-javaee.jar!/
                   2009-02-05 11:20:06,489 TRACE [org.jboss.classloading.spi.vfs.policy.VFSClassLoaderPolicy]
                  
                  


                  As can be seen, the log says there's a match for javax/servlet/ServletException.class against the filter but not for javax/servlet/http/HttpServletRequest.class

                  Coming to the piece of code which creates this regex pattern:

                  private static String[] convertPackageNamesToClassPatterns(String[] packageNames)
                   {
                   if (packageNames == null)
                   throw new IllegalArgumentException("Null package names");
                  
                   String[] patterns = new String[packageNames.length];
                   for (int i = 0; i < packageNames.length; ++i)
                   {
                   if (packageNames[ i ] == null)
                   throw new IllegalArgumentException("Null package name in " + Arrays.asList(packageNames));
                  
                   if (packageNames[ i ].length() == 0)
                   // Base package - it is a match if there is no . in the class name
                   patterns[ i ] = "[^.]*";
                   else
                   // Escape the dots in the package and match anything that has a single dot followed by non-dots
                   patterns[ i ] = packageNames[ i ].replace(".", "\\.") + "\\.[^.]+";
                  
                   }
                   return patterns;
                   }
                  


                   /**
                   * Convert package names to resource patterns
                   *
                   * @param packageNames the package names
                   * @return the patterns
                   */
                   private static String[] convertPackageNamesToResourcePatterns(String[] packageNames)
                   {
                   if (packageNames == null)
                   throw new IllegalArgumentException("Null package names");
                  
                   String[] patterns = new String[packageNames.length];
                   for (int i = 0; i < packageNames.length; ++i)
                   {
                   if (packageNames[ i ] == null)
                   throw new IllegalArgumentException("Null package name in " + Arrays.asList(packageNames));
                  
                   if (packageNames[ i ].length() == 0)
                   // Base package - it is a match if there is no / in the path
                   patterns[ i ] = "[^/]*";
                   else
                   // Replace the dots with slashs and match non slashes after that
                   patterns[ i ] = packageNames[ i ].replace(".", "/") + "/[^/]+";
                  
                   }
                   return patterns;
                   }
                  
                  


                  As can be seen, the regex is being created to not match the child packages. The comments above those statements also show that this is intentional. But any specific reason why this is the case? I would have expected that setting a filter on javax.servlet would effectively mean, setting the filter on the (classes under) sub-packages too. Similar to the JBossAS-4.x behaviour. Has this changed intentionally?

                  To fix this, i changed the regex as follows:

                  Index: src/main/java/org/jboss/classloader/spi/filter/PackageClassFilter.java
                  ===================================================================
                  --- src/main/java/org/jboss/classloader/spi/filter/PackageClassFilter.java (revision 83874)
                  +++ src/main/java/org/jboss/classloader/spi/filter/PackageClassFilter.java (working copy)
                  @@ -60,8 +60,11 @@
                   // Base package - it is a match if there is no . in the class name
                   patterns[ i ] = "[^.]*";
                   else
                  - // Escape the dots in the package and match anything that has a single dot followed by non-dots
                  - patterns[ i ] = packageNames[ i ].replace(".", "\\.") + "\\.[^.]+";
                  + // Escape the dots in the package and match those packages which start with the
                  + // filtered package name and any sub-packages under this package
                  + // Ex: If filtered package is javax.servlet then this successfully matches
                  + // javax.servlet.ServletException as well as javax.servlet.http.HttpServletRequest
                  + patterns[ i ] = packageNames[ i ].replace(".", "\\.") + "[\\.]?.*";
                   }
                   return patterns;
                   }
                  @@ -87,8 +90,11 @@
                   // Base package - it is a match if there is no / in the path
                   patterns[ i ] = "[^/]*";
                   else
                  - // Replace the dots with slashs and match non slashes after that
                  - patterns[ i ] = packageNames[ i ].replace(".", "/") + "/[^/]+";
                  + // Replace the dots with slashes and match those packages which start with the
                  + // filtered package name and any sub-packages under this package
                  + // Ex: If filtered package is javax.servlet then this successfully matches
                  + // javax/servlet/ServletException as well as javax/servlet/http/HttpServletRequest
                  + patterns[ i ] = packageNames[ i ].replace(".", "/") + "[/]?.*";
                   }
                   return patterns;
                   }
                  
                  
                  
                  I then patched this into the AS5.0 GA and tried my sample application again. And this time it worked without any issues. Here's the classloading TRACE log which shows javax/servlet/http/HttpServlet.class was now considered a match:


                  2009-02-05 11:24:34,957 TRACE [org.jboss.classloading.spi.vfs.policy.VFSClassLoaderPolicy] VFSClassLoaderPolicy@151a1a1{vfsfile:/opt/jpai/jboss-5.0.0.GA/server/default/deploy/test.war/} getResource path=javax/servlet/http/HttpServlet.class matches exclude filter: [javax.servlet, org.apache.commons.logging]
                  


                  I haven't yet filed a JIRA for this since i wanted to make sure that this is not the intended behaviour - which i guess shouldn't be or else it's going to difficult to keep adding filters to child packages.


                  • 6. Re: LinkageError with gwt-user.jar
                    alesj

                     

                    "jaikiran" wrote:

                    I haven't yet filed a JIRA for this since i wanted to make sure that this is not the intended behaviour - which i guess shouldn't be or else it's going to difficult to keep adding filters to child packages.

                    There was already an attempt to clear this out:
                    - http://www.jboss.com/index.html?module=bb&op=viewtopic&t=142788
                    Perhaps just add this use case there and we'll see if there's any progress. ;-)