glassfish
  1. glassfish
  2. GLASSFISH-16872

ServletContainerInitializer API contract broken

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.1
    • Fix Version/s: 3.1.1
    • Component/s: web_container
    • Labels:
      None
    • Environment:

      Linux 2.6.35-28-generic #50-Ubuntu SMP x86_64 GNU/Linux
      GlassFish Server Open Source Edition 3.1 (build 43)

      Description

      ServletContainerInitializer.onStartup method is invoked with incomplete list of classes
      The behavior is non-deterministic and hard to debug.

      This issue is the root cause for http://java.net/jira/browse/GLASSFISH-16635
      and http://java.net/jira/browse/GLASSFISH-16118

      JerseyServletContainerInitializer, which is annotated
      with @HandlesTypes(

      {Path.class, Provider.class, javax.ws.rs.core.Application.class}

      )
      is sometimes invoked (via it's onStartup method) without application
      classes extending javax.ws.rs.core.Application class. This breaks the ServletContainerInitializer API contract.

      To reproduce, please see http://java.net/jira/browse/GLASSFISH-16118, which has
      a SimpleServlet.war application attached. I have deployed the application onto a fresh
      GFv3.1 container, undeployed, then deployed again and restarted the container.
      After the last restart, the issue reproduced. Attaching my server.log file
      to this report. To see what happens, i have added the following lines to domain conf/logging.properties
      file:

      org.apache.catalina.core.StandardContext.level=FINEST
      com.sun.jersey.spi.service.ServiceFinder.level=FINEST
      com.sun.jersey.server.impl.container.servlet.JerseyServletContainerInitializer.level=FINEST

      Here is what i see in the server.log file for the two latest re-start of the application:

      [#|2011-06-16T13:33:21.256+0200|FINE|glassfish3.1|org.apache.catalina.core.StandardContext|_ThreadID=21;_ThreadName=Threa
      d-1;ClassName=org.apache.catalina.core.StandardContext;MethodName=callServletContainerInitializers;|Calling ServletContai
      nerInitializer [class com.sun.jersey.server.impl.container.servlet.JerseyServletContainerInitializer] onStartup with clas
      ses [class com.sun.jersey.samples.servlet.resources.ResourceBean1, class com.sun.jersey.api.core.ScanningResourceConfig,
      class com.sun.jersey.samples.servlet.resources.ResourceBean2, class com.sun.jersey.api.core.ClasspathResourceConfig, clas
      s com.sun.jersey.api.core.ApplicationAdapter, class com.sun.jersey.api.core.ResourceConfig, class com.sun.jersey.samples.
      servlet.resources.MasterResourceBean, class com.sun.jersey.api.core.DefaultResourceConfig, class com.sun.jersey.samples.s
      ervlet.resources.ResourceBean4, class com.sun.jersey.api.core.WebAppResourceConfig, class com.sun.jersey.api.core.Package
      sResourceConfig, class com.sun.jersey.samples.servlet.resources.ResourceBean3, class com.sun.jersey.api.core.ClassNamesRe
      sourceConfig, class com.sun.jersey.server.impl.application.DeferredResourceConfig, class com.sun.jersey.samples.servlet.r
      esources.MyApplication]|#]

      [#|2011-06-16T13:33:54.485+0200|FINE|glassfish3.1|org.apache.catalina.core.StandardContext|_ThreadID=10;_ThreadName=Threa
      d-1;ClassName=org.apache.catalina.core.StandardContext;MethodName=callServletContainerInitializers;|Calling ServletContai
      nerInitializer [class com.sun.jersey.server.impl.container.servlet.JerseyServletContainerInitializer] onStartup with clas
      ses [class com.sun.jersey.samples.servlet.resources.ResourceBean4, class com.sun.jersey.samples.servlet.resources.MasterR
      esourceBean, class com.sun.jersey.samples.servlet.resources.ResourceBean1, class com.sun.jersey.samples.servlet.resources
      .ResourceBean2, class com.sun.jersey.samples.servlet.resources.ResourceBean3]|#]

      The key class, com.sun.jersey.samples.servlet.resources.MyApplication, is missing in the later call,
      which is causing the JAX-RS application servlet not to be registered.

      I think, the problematic code is in the org.glassfish.web.loader.ServletContainerInitializerUtil class,
      where two methods are utilized for interest list construction, both called checkAgainstInterestList.
      When the first one of them is utilized, the problem reproduces.

      1. server.log
        68 kB
        Jakub Podlesak

        Issue Links

          Activity

          Hide
          Jakub Podlesak added a comment -

          When added the following JVM property, it seems i can not reproduce the issue any more:

          asadmin create-jvm-options -Dorg.glassfish.web.parsing=true

          but then also the application context path changes to SimpleServlet,
          so that the main application URI changes to:

          http://localhost:8080/SimpleServlet/resources/start

          The above property controls, which checkAgainstInterestList method gets called
          in the above mentioned ServletContainerInitializerUtil class
          to put together the ServletContainerInitializer interest list:

          if (types==null || Boolean.getBoolean("org.glassfish.web.parsing")) {
          ClassDependencyBuilder classInfo = new ClassDependencyBuilder();
          for(URL u : ((URLClassLoader)cl).getURLs()) {
          String path = u.getPath();
          try {
          if(path.endsWith(".jar")) {
          JarFile jf = new JarFile(path);
          try {
          Enumeration<JarEntry> entries = jf.entries();
          while(entries.hasMoreElements()) {
          JarEntry anEntry = entries.nextElement();
          if(anEntry.isDirectory())
          continue;
          if(!anEntry.getName().endsWith(".class"))
          continue;
          InputStream jarInputStream = null;
          try {
          jarInputStream = jf.getInputStream(anEntry);
          int size = (int) anEntry.getSize();
          byte[] classData = new byte[size];
          for(int bytesRead = 0; bytesRead < size

          { int r2 = jarInputStream.read(classData, bytesRead, size - bytesRead); bytesRead += r2; }

          classInfo.loadClassData(classData);
          } catch (Throwable t) {
          if (log.isLoggable(Level.FINE)) {
          log.log(Level.FINE,
          "servletContainerInitializerUtil.classLoadingError",
          new Object[]

          { anEntry.getName(), t.toString()}

          );
          }
          continue;
          } finally {
          if(jarInputStream != null)

          { jarInputStream.close(); }

          }
          }
          } finally

          { jf.close(); }

          } else {
          File file = new File(path);
          if (file.exists()) {
          if (file.isDirectory())

          { scanDirectory(file, classInfo); }

          else

          { log.log(Level.WARNING, "servletContainerInitializerUtil.invalidUrlClassLoaderPath", path); }

          }
          }
          } catch(IOException ioex) {
          String msg = rb.getString(
          "servletContainerInitializerUtil.ioError");
          msg = MessageFormat.format(msg,
          new Object[]

          { path }

          );
          log.log(Level.SEVERE, msg, ioex);
          return null;
          }
          }

          initializerList = checkAgainstInterestList(classInfo, interestList, initializerList, cl);
          } else

          { initializerList = checkAgainstInterestList(types, interestList, initializerList, cl); }

          }

          Show
          Jakub Podlesak added a comment - When added the following JVM property, it seems i can not reproduce the issue any more: asadmin create-jvm-options -Dorg.glassfish.web.parsing=true but then also the application context path changes to SimpleServlet, so that the main application URI changes to: http://localhost:8080/SimpleServlet/resources/start The above property controls, which checkAgainstInterestList method gets called in the above mentioned ServletContainerInitializerUtil class to put together the ServletContainerInitializer interest list: if (types==null || Boolean.getBoolean("org.glassfish.web.parsing")) { ClassDependencyBuilder classInfo = new ClassDependencyBuilder(); for(URL u : ((URLClassLoader)cl).getURLs()) { String path = u.getPath(); try { if(path.endsWith(".jar")) { JarFile jf = new JarFile(path); try { Enumeration<JarEntry> entries = jf.entries(); while(entries.hasMoreElements()) { JarEntry anEntry = entries.nextElement(); if(anEntry.isDirectory()) continue; if(!anEntry.getName().endsWith(".class")) continue; InputStream jarInputStream = null; try { jarInputStream = jf.getInputStream(anEntry); int size = (int) anEntry.getSize(); byte[] classData = new byte [size] ; for(int bytesRead = 0; bytesRead < size { int r2 = jarInputStream.read(classData, bytesRead, size - bytesRead); bytesRead += r2; } classInfo.loadClassData(classData); } catch (Throwable t) { if (log.isLoggable(Level.FINE)) { log.log(Level.FINE, "servletContainerInitializerUtil.classLoadingError", new Object[] { anEntry.getName(), t.toString()} ); } continue; } finally { if(jarInputStream != null) { jarInputStream.close(); } } } } finally { jf.close(); } } else { File file = new File(path); if (file.exists()) { if (file.isDirectory()) { scanDirectory(file, classInfo); } else { log.log(Level.WARNING, "servletContainerInitializerUtil.invalidUrlClassLoaderPath", path); } } } } catch(IOException ioex) { String msg = rb.getString( "servletContainerInitializerUtil.ioError"); msg = MessageFormat.format(msg, new Object[] { path } ); log.log(Level.SEVERE, msg, ioex); return null; } } initializerList = checkAgainstInterestList(classInfo, interestList, initializerList, cl); } else { initializerList = checkAgainstInterestList(types, interestList, initializerList, cl); } }
          Hide
          kchung added a comment -

          I've traced the cause of the problem to the method com.sun.enterprise.v3.server.ApplicationLifecycle.getDeployableTypes(). This method is supposed to collect all Types related to the application at deployment and store them in the deployment context. However, on some calls (described below), at the end of this method no such Type exist for the class "javax.ws.rs.core.Application". Therefore the web container cannot provide any info about the classes that extend javax.ws.rs.core.Application.

          To force the failure, use the following steps:

          1. Start with a fresh Glassfish.
          asadmin start-domain
          2. asadmin deploy simple_servlet.war
          3. asadmin stop-domain
          4. asadmin deploy --force=true simple_servlet.war

          I suspect there are issues with Types cache with the deployment context.

          Show
          kchung added a comment - I've traced the cause of the problem to the method com.sun.enterprise.v3.server.ApplicationLifecycle.getDeployableTypes(). This method is supposed to collect all Types related to the application at deployment and store them in the deployment context. However, on some calls (described below), at the end of this method no such Type exist for the class "javax.ws.rs.core.Application". Therefore the web container cannot provide any info about the classes that extend javax.ws.rs.core.Application. To force the failure, use the following steps: 1. Start with a fresh Glassfish. asadmin start-domain 2. asadmin deploy simple_servlet.war 3. asadmin stop-domain 4. asadmin deploy --force=true simple_servlet.war I suspect there are issues with Types cache with the deployment context.
          Hide
          dochez added a comment -

          Resolved by integrating Hk2 1.1.3

          The issue was that we were creating ProxyTypes of type Interface when visiting fields, this was creating duplicate entries in particular javax.rs.core.Application one which was creating wrong results.

          Show
          dochez added a comment - Resolved by integrating Hk2 1.1.3 The issue was that we were creating ProxyTypes of type Interface when visiting fields, this was creating duplicate entries in particular javax.rs.core.Application one which was creating wrong results.

            People

            • Assignee:
              dochez
              Reporter:
              Jakub Podlesak
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: