4.3.6. 调试和解决 Seam 2.2 Booking 例程的部署错误和异常

在上面的步骤 第 4.3.5 节 “构建和部署 Seam 2.2 Booking 例程的 JBoss EAP 5.1 版本。” 里,你构建了 JBoss EAP 5.1 的 Seam 2.2 Booking 例程且将其部署到了 JBoss EAP 6 的部署目录里。在这个步骤,你可以调试和解决遇到的每个部署错误。

重要

直接使用 Hibernate 的 Seam 2.2 应用程序可以使用包裹在应用程序里的一个 Hibernate 3 版本。而通过 JBoss EAP 6 的 org.hibernate 模块提供的 Hibernate 4,不被 Seam 2.2 支持。这个例子将帮助你在 JBoss EAp 6 运行应用程序。请注意,将 Hibernate 3 包裹在 Seam 2.2 应用程序不是被支持的配置。

过程 4.16. 调试和解决部署错误和异常

  1. 问题 - java.lang.ClassNotFoundException: javax.faces.FacesException
    当你部署应用程序时,日志会包含下列错误:
    ERROR \[org.jboss.msc.service.fail\] (MSC service thread 1-1) MSC00001: Failed to start service jboss.deployment.subunit."jboss-seam-booking.ear"."jboss-seam-booking.war".POST_MODULE:
    org.jboss.msc.service.StartException in service jboss.deployment.subunit."jboss-seam-booking.ear"."jboss-seam-booking.war".POST_MODULE:
    Failed to process phase POST_MODULE of subdeployment "jboss-seam-booking.war" of deployment "jboss-seam-booking.ear"
        (.. additional logs removed ...)
    Caused by: java.lang.ClassNotFoundException: javax.faces.FacesException from \[Module "deployment.jboss-seam-booking.ear:main" from Service Module Loader\]
        at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:191)
    
    它表示:

    ClassNotFoundException 表示缺失的依赖关系。在这个例子里是无法找到 javax.faces.FacesException,你需要显性地添加这个依赖关系。

    如何解决这个问题:

    EAP6_HOME/modules/system/layers/base/ 目录里通过查找匹配缺失的类的路径找到这个类的模块名。在这个例子里,你会找到两个匹配的模块:

    javax/faces/api/main
    javax/faces/api/1.2
    
    这两个模块都有相同的模块名:javax.faces.api,但位于 main 目录里的是用于 JSF 2.0 的,而位于 1.2 目录里的另外一个是用于 JSF 1.2 的。如果只有一个可用的模块,你可以简单地创建一个 MANIFEST.MF 并添加模块依赖关系。在这个例子里,你像使用 JSF 1.2 版本而不是 main 里的 JSF 2.0,所以你需要指定一个并排斥另外一个。为此,你可以在 EAR 的 META-INF/ 目录里创建一个包含下列数据的 jboss-deployment-structure.xml
    <jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
      <deployment>
          <dependencies>
            <module name="javax.faces.api" slot="1.2" export="true"/>
          </dependencies>
      </deployment>
      <sub-deployment name="jboss-seam-booking.war">
        <exclusions>
            <module name="javax.faces.api" slot="main"/>
          </exclusions>
          <dependencies>
            <module name="javax.faces.api" slot="1.2"/>
          </dependencies>
      </sub-deployment>
    </jboss-deployment-structure>
    
    
    deployment 部分,你可以添加用于 JSF 1.2 模块的 javax.faces.api 的依赖关系。你也可以在 WAR 的 subdeployment 部分添加用于 JSF 1.2 模块的依赖关系并排除用于 JSF 2.0 的模块。

    通过删除 EAP6_HOME/standalone/deployments/jboss-seam-booking.ear.failed 文件并在相同目录里创建一个空白的 jboss-seam-booking.ear.dodeploy 文件来重新部署应用程序。
  2. 问题 - java.lang.ClassNotFoundException: org.apache.commons.logging.Log
    当你部署应用程序时,日志会包含下列错误:
    ERROR [org.jboss.msc.service.fail] (MSC service thread 1-8) MSC00001: Failed to start service jboss.deployment.unit."jboss-seam-booking.ear".INSTALL:
    org.jboss.msc.service.StartException in service jboss.deployment.unit."jboss-seam-booking.ear".INSTALL:
    Failed to process phase INSTALL of deployment "jboss-seam-booking.ear"
        (.. additional logs removed ...)
    Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.Log from [Module "deployment.jboss-seam-booking.ear.jboss-seam-booking.war:main" from Service Module Loader]
    
    它表示:

    ClassNotFoundException 指示了一个缺失的依赖关系。在这个例子里是无法找到 org.apache.commons.logging.Log 且你需要显性地添加依赖关系。

    如何解决这个问题:

    通过查找匹配缺失类的路径在 EAP6_HOME/modules/system/layers/base/ 里找到这个类的模块名。在这个例子里,你要找到匹配路径 org/apache/commons/logging/ 的模块。这个模块名是 “org.apache.commons.logging”。

    修改 jboss-deployment-structure.xml 文件,添加模块依赖关系至部署部分。
    <module name="org.apache.commons.logging" export="true"/>
    
    
    jboss-deployment-structure.xml 应该类似于:
    <jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
      <deployment>
          <dependencies>
            <module name="javax.faces.api" slot="1.2" export="true"/>
            <module name="org.apache.commons.logging" export="true"/>
          </dependencies>
      </deployment>
      <sub-deployment name="jboss-seam-booking.war">
        <exclusions>
            <module name="javax.faces.api" slot="main"/>
          </exclusions>
          <dependencies>
            <module name="javax.faces.api" slot="1.2"/>
          </dependencies>
      </sub-deployment>
    </jboss-deployment-structure>
    
    
    通过删除 EAP6_HOME/standalone/deployments/jboss-seam-booking.ear.failed 文件并在相同目录里创建一个空白的 jboss-seam-booking.ear.dodeploy 文件来重新部署应用程序。
  3. 问题 - java.lang.ClassNotFoundException: org.dom4j.DocumentException
    当你部署应用程序时,日志会包含下列错误:
    ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/seam-booking]] (MSC service thread 1-3) Exception sending context initialized event to listener instance of class org.jboss.seam.servlet.SeamListener: java.lang.NoClassDefFoundError: org/dom4j/DocumentException
        (... additional logs removed ...)
    Caused by: java.lang.ClassNotFoundException: org.dom4j.DocumentException from [Module "deployment.jboss-seam-booking.ear.jboss-seam.jar:main" from Service Module Loader]
    
    它表示:

    ClassNotFoundException 表示缺失的依赖关系。在这个例子里是无法找到 org.dom4j.DocumentException 类。

    如何解决这个问题:

    EAP6_HOME/modules/system/layers/base/ 目录里通过查找 org/dom4j/DocumentException 来查找模块名。这个模块名是 “org.dom4j”。修改 jboss-deployment-structure.xml 文件,添加模块依赖关系至文件的部署部分。

    <module name="org.dom4j" export="true"/>
    
    
    jboss-deployment-structure.xml 文件应该类似于:
    <jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
      <deployment>
          <dependencies>
            <module name="javax.faces.api" slot="1.2" export="true"/>
            <module name="org.apache.commons.logging" export="true"/>
                <module name="org.dom4j" export="true"/>
              </dependencies>
      </deployment>
      <sub-deployment name="jboss-seam-booking.war">
        <exclusions>
            <module name="javax.faces.api" slot="main"/>
          </exclusions>
          <dependencies>
            <module name="javax.faces.api" slot="1.2"/>
          </dependencies>
      </sub-deployment>
    </jboss-deployment-structure>
    
    

    通过删除 EAP6_HOME/standalone/deployments/jboss-seam-booking.ear.failed 文件并在相同目录里创建一个空白的 jboss-seam-booking.ear.dodeploy 文件来重新部署应用程序。
  4. 问题 - java.lang.ClassNotFoundException: org.hibernate.validator.InvalidValue
    当你部署应用程序时,日志会包含下列错误:
    ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/seam-booking]] (MSC service thread 1-6) Exception sending context initialized event to listener instance of class org.jboss.seam.servlet.SeamListener: java.lang.RuntimeException: Could not create Component: org.jboss.seam.international.statusMessages
        (... additional logs removed ...)
    Caused by: java.lang.ClassNotFoundException: org.hibernate.validator.InvalidValue from [Module "deployment.jboss-seam-booking.ear.jboss-seam.jar:main" from Service Module Loader]
    
    它表示:

    ClassNotFoundException 表示缺失的依赖关系。在这个例子里是无法找到 org.hibernate.validator.InvalidValue 类。

    如何解决这个问题:

    存在名为 “org.hibernate.validator” 的模块,但 JAR 不包含 org.hibernate.validator.InvalidValue 类,所以添加模块依赖关系不会解决这个问题。在这个例子里,JAR 包含这个类,将其作为 JBoss EAP 5.1 部署的一部分。在 EAP5_HOME/seam/lib/ 目录里查找包含缺失类的 JAR。为此,打开控制台并输入:

    $ cd EAP5_HOME/seam/lib
    $ grep 'org.hibernate.validator.InvalidValue' `find . -name '*.jar'
    
    其结果显示:
    $ Binary file ./hibernate-validator.jar matches
    $ Binary file ./test/hibernate-all.jar matches
    
    在这个例子里,复制 hibernate-validator.jarjboss-seam-booking.ear/lib/ 目录:
    $ cp EAP5_HOME/seam/lib/hibernate-validator.jar jboss-seam-booking.ear/lib
    

    通过删除 EAP6_HOME/standalone/deployments/jboss-seam-booking.ear.failed 文件并在相同目录里创建一个空白的 jboss-seam-booking.ear.dodeploy 文件来重新部署应用程序。
  5. 问题 - java.lang.InstantiationException: org.jboss.seam.jsf.SeamApplicationFactory
    当你部署应用程序时,日志会包含下列错误:
    INFO  [javax.enterprise.resource.webcontainer.jsf.config] (MSC service thread 1-7) Unsanitized stacktrace from failed start...: com.sun.faces.config.ConfigurationException: Factory 'javax.faces.application.ApplicationFactory' was not configured properly.
      at com.sun.faces.config.processor.FactoryConfigProcessor.verifyFactoriesExist(FactoryConfigProcessor.java:296) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4]
      (... additional logs removed ...)
    Caused by: javax.faces.FacesException: org.jboss.seam.jsf.SeamApplicationFactory
      at javax.faces.FactoryFinder.getImplGivenPreviousImpl(FactoryFinder.java:606) [jsf-api-1.2_13.jar:1.2_13-b01-FCS]
      (... additional logs removed ...)
      at com.sun.faces.config.processor.FactoryConfigProcessor.verifyFactoriesExist(FactoryConfigProcessor.java:294) [jsf-impl-2.0.4-b09-jbossorg-4.jar:2.0.4-b09-jbossorg-4]
      ... 11 more
    Caused by: java.lang.InstantiationException: org.jboss.seam.jsf.SeamApplicationFactory
      at java.lang.Class.newInstance0(Class.java:340) [:1.6.0_25]
      at java.lang.Class.newInstance(Class.java:308) [:1.6.0_25]
      at javax.faces.FactoryFinder.getImplGivenPreviousImpl(FactoryFinder.java:604) [jsf-api-1.2_13.jar:1.2_13-b01-FCS]
      ... 16 more
    
    它表示:

    com.sun.faces.config.ConfigurationExceptionjava.lang.InstantiationException 表示存在依赖关系的问题。在这个例子里,原因并不明显。

    如何解决这个问题:

    你需要找到包含 com.sun.faces 类的模块。虽然这里没有 com.sun.faces 模块,但却有两个 com.sun.jsf-impl 模块。在 1.2 目录里快速检查 jsf-impl-1.2_13.jar,你会发现它包含 com.sun.faces 类。如你对 javax.faces.FacesExceptionClassNotFoundException 所做的一样,你希望在 main 里使用 JSF 1.2 版本而不是 JSF 2.0,所以你需要指定一个且排除另外一个。你需要修改 jboss-deployment-structure.xml 以添加模块依赖关系到这个文件的 deployment 部分。你也需要添加它到 WAR 子部署并排除 JSF 2.0 模块。这个文件现在应该类似于:

    <jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
      <deployment>
          <dependencies>
            <module name="javax.faces.api" slot="1.2" export="true"/>
                  <module name="com.sun.jsf-impl" slot="1.2" export="true"/>
            <module name="org.apache.commons.logging" export="true"/>
            <module name="org.dom4j" export="true"/>
          </dependencies>
      </deployment>
      <sub-deployment name="jboss-seam-booking.war">
        <exclusions>
            <module name="javax.faces.api" slot="main"/>
            <module name="com.sun.jsf-impl" slot="main"/>
          </exclusions>
          <dependencies>
            <module name="javax.faces.api" slot="1.2"/>
                  <module name="com.sun.jsf-impl" slot="1.2"/>
          </dependencies>
      </sub-deployment>
    </jboss-deployment-structure>
    

    通过删除 EAP6_HOME/standalone/deployments/jboss-seam-booking.ear.failed 文件并在相同目录里创建一个空白的 jboss-seam-booking.ear.dodeploy 文件来重新部署应用程序。
  6. 问题 - java.lang.ClassNotFoundException: org.apache.commons.collections.ArrayStack
    当你部署应用程序时,日志会包含下列错误:
    ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/seam-booking]] (MSC service thread 1-1) Exception sending context initialized event to listener instance of class com.sun.faces.config.ConfigureListener: java.lang.RuntimeException: com.sun.faces.config.ConfigurationException: CONFIGURATION FAILED! org.apache.commons.collections.ArrayStack from [Module "deployment.jboss-seam-booking.ear:main" from Service Module Loader]
        (... additional logs removed ...)
    Caused by: java.lang.ClassNotFoundException: org.apache.commons.collections.ArrayStack from [Module "deployment.jboss-seam-booking.ear:main" from Service Module Loader]
    
    它表示:

    ClassNotFoundException 表示缺失的依赖关系。在这个例子里是无法找到 org.apache.commons.collections.ArrayStack

    如何解决这个问题:

    EAP6_HOME/modules/system/layers/base/ 目录里通过查找 org/apache/commons/collections 路径来查找模块名。这个模块名是 “org.apache.commons.collections”。修改 jboss-deployment-structure.xml 文件,添加模块依赖关系至文件的部署部分。

    <module name="org.apache.commons.collections" export="true"/>
    
    jboss-deployment-structure.xml 文件应该类似于:
    <jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">
      <deployment>
          <dependencies>
            <module name="javax.faces.api" slot="1.2" export="true"/>
                  <module name="com.sun.jsf-impl" slot="1.2" export="true"/>
            <module name="org.apache.commons.logging" export="true"/>
            <module name="org.dom4j" export="true"/>
            <module name="org.apache.commons.collections" export="true"/>
        </dependencies>
      </deployment>
      <sub-deployment name="jboss-seam-booking.war">
        <exclusions>
            <module name="javax.faces.api" slot="main"/>
            <module name="com.sun.jsf-impl" slot="main"/>
          </exclusions>
          <dependencies>
            <module name="javax.faces.api" slot="1.2"/>
                  <module name="com.sun.jsf-impl" slot="1.2"/>
          </dependencies>
      </sub-deployment>
    </jboss-deployment-structure>
    

    通过删除 EAP6_HOME/standalone/deployments/jboss-seam-booking.ear.failed 文件并在相同目录里创建一个空白的 jboss-seam-booking.ear.dodeploy 文件来重新部署应用程序。
  7. 问题 - Services with missing/unavailable dependencies
    当你部署应用程序时,日志会包含下列错误:
    ERROR [org.jboss.as.deployment] (DeploymentScanner-threads - 2) {"Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"Services with missing/unavailable dependencies" => ["jboss.deployment.subunit.\"jboss-seam-booking.ear\".\"jboss-seam-booking.jar\".component.AuthenticatorAction.START missing [ jboss.naming.context.java.comp.jboss-seam-booking.\"jboss-seam-booking.jar\".AuthenticatorAction.\"env/org.jboss.seam.example.booking.AuthenticatorAction/em\" ]","jboss.deployment.subunit.\"jboss-seam-booking.ear\".\"jboss-seam-booking.jar\".component.HotelSearchingAction.START missing [ jboss.naming.context.java.comp.jboss-seam-booking.\"jboss-seam-booking.jar\".HotelSearchingAction.\"env/org.jboss.seam.example.booking.HotelSearchingAction/em\" ]","
      (... additional logs removed ...)
    "jboss.deployment.subunit.\"jboss-seam-booking.ear\".\"jboss-seam-booking.jar\".component.BookingListAction.START missing [ jboss.naming.context.java.comp.jboss-seam-booking.\"jboss-seam-booking.jar\".BookingListAction.\"env/org.jboss.seam.example.booking.BookingListAction/em\" ]","jboss.persistenceunit.\"jboss-seam-booking.ear/jboss-seam-booking.jar#bookingDatabase\" missing [ jboss.naming.context.java.bookingDatasource ]"]}}}
    
    它表示:

    当你遇到 “Services with missing/unavailable dependencies” 错误,请查看 “missing” 后面括号里的文本。在这里例子里是:

    missing [ jboss.naming.context.java.comp.jboss-seam-booking.\"jboss-seam-booking.jar\".AuthenticatorAction.\"env/org.jboss.seam.example.booking.AuthenticatorAction/em\" ]
    
    “/em” 表示这是一个 Entity Manager 和数据源的问题。

    如何解决这个问题:

    在 JBoss EAP 6 里,数据源配置已经进行了修改,它需要在 EAP6_HOME/standalone/configuration/standalone.xml 文件里进行定义。既然 JBoss EAP 6 附带的示例数据库已经在 standalone.xml 文件里进行了定义,请修改 persistence.xml 文件来使用这个示例数据库。请看 standalone.xml 文件,你可以看到示例数据库的 jndi-namejava:jboss/datasources/ExampleDS。修改 jboss-seam-booking.jar/META-INF/persistence.xml 文件,注释现有的 jta-data-source 元素并用下列内容来替代:

    <!-- <jta-data-source>java:/bookingDatasource</jta-data-source> -->
    <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
    

    通过删除 EAP6_HOME/standalone/deployments/jboss-seam-booking.ear.failed 文件并在相同目录里创建一个空白的 jboss-seam-booking.ear.dodeploy 文件来重新部署应用程序。
  8. 问题 - java.lang.ClassNotFoundException: org.hibernate.cache.HashtableCacheProvider
    当你部署应用程序时,日志会包含下列错误:
    ERROR [org.jboss.msc.service.fail] (MSC service thread 1-4) MSC00001: Failed to start service jboss.persistenceunit."jboss-seam-booking.ear/jboss-seam-booking.jar#bookingDatabase": org.jboss.msc.service.StartException in service jboss.persistenceunit."jboss-seam-booking.ear/jboss-seam-booking.jar#bookingDatabase": Failed to start service
      at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1786)
      (... log messages removed ...)
    Caused by: java.lang.ClassNotFoundException: org.hibernate.cache.HashtableCacheProvider from [Module "org.hibernate:main" from local module loader @12a3793 (roots: /home/sgilda/tools/jboss7/modules)]
      at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:191)
      (... log messages removed ...)
    
    它表示:

    ClassNotFoundException 表示一个缺失的依赖关系。在这里例子里,它无法找到 org.hibernate.cache.HashtableCacheProvider

    如何解决这个问题:

    没有模块 “org.hibernate.cache”。在这个例子里,包含这个类的 JAR 是 JBoss EAP 5.1 部署的一部分。请在 EAP5_HOME/jboss-eap-5.1/seam/lib/ 目录里查找包含缺失类的 JAR。为此,请打开控制台并输入:

    $ cd EAP5_HOME/seam/lib
    $ grep 'org.hibernate.validator.InvalidValue' `find . -name '*.jar'`
    
    其结果显示:
    Binary file ./hibernate-core.jar matches
    Binary file ./test/hibernate-all.jar matches
    
    在这个例子里,复制 hibernate-core.jarjboss-seam-booking.ear/lib/ 目录:
    cp EAP5_HOME/seam/lib/hibernate-core.jar jboss-seam-booking.ear/lib
    

    通过删除 EAP6_HOME/standalone/deployments/jboss-seam-booking.ear.failed 文件并在相同目录里创建一个空白的 jboss-seam-booking.ear.dodeploy 文件来重新部署应用程序。
  9. 问题 - java.lang.ClassCastException: org.hibernate.cache.HashtableCacheProvider
    当你部署应用程序时,日志会包含下列错误:
    ERROR [org.jboss.msc.service.fail] (MSC service thread 1-2) MSC00001: Failed to start service jboss.persistenceunit."jboss-seam-booking.ear/jboss-seam-booking.jar#bookingDatabase": org.jboss.msc.service.StartException in service jboss.persistenceunit."jboss-seam-booking.ear/jboss-seam-booking.jar#bookingDatabase": Failed to start service
      at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1786)
      (... log messages removed ...)
    Caused by: java.lang.ClassCastException: org.hibernate.cache.HashtableCacheProvider cannot be cast to org.hibernate.cache.spi.CacheProvider
      at org.hibernate.cache.internal.bridge.RegionFactoryCacheProviderBridge.init(RegionFactoryCacheProviderBridge.java:65)
      ... 20 more
    
    它表示:

    很多情况下都会遇到 ClassCastException。如果你在日志里看到了这个异常,就表示 org.hibernate.cache.HashtableCacheProvider 扩展了 org.hibernate.cache.spi.CacheProvider 且正由和它扩展的类不同的类加载器加载。org.hibernate.cache.HashtableCacheProvider 类位于 hibernate-core.jar 且由应用程序类加载器加载。它扩展的类, org.hibernate.cache.spi.CacheProvider,位于 org/hibernate/main/hibernate-core-4.0.0.Beta1.jar 且由该模块隐性地加载。这并不明显,但是由于 Hibernate 4 里的改动,由于移动 HashtableCacheProvider 类到其他软件包会导致向后的兼容性问题。这个类将从 org.hibernate.cache 软件包移动到 org.hibernate.cache.internal 软件包。如果你没有从 persistence.xml 删除 hibernate.cache.provider_class 属性,它将强制 Seam 应用程序捆绑旧的 Hibernate 库,导致 ClassCastExceptions。在 JBoss EAP 6 里,你应该使用 Infinispan 而避免使用 HashtableCacheProvider。

    如何解决这个问题:

    在 JBoss EAP 6 里,注释 jboss-seam-booking.jar/META-INF/persistence.xml 文件里的 hibernate.cache.provider_class 属性:

    <!-- <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/> -->
    

    通过删除 EAP6_HOME/standalone/deployments/jboss-seam-booking.ear.failed 文件并在相同目录里创建一个空白的 jboss-seam-booking.ear.dodeploy 文件来重新部署应用程序。
  10. 此时,应用程序应该已部署无误了,但当你访问 http://localhost:8080/seam-booking/ 并尝试 "Account Login" 时,你会遇到一个运行时错误 “The page isn't redirecting properly”。在下一步里,你会学习如何调试和解决运行时错误。
    要学习如何调试和解决运行时的问题,点击这里:第 4.3.7 节 “调试和解决 Seam 2.2 Booking 例程的运行时错误和异常”