从 Apache Tomcat Version 6.0.x 迁移到 WebSphere Application Server Community Edition V2.1

本文逐步地指导您将一个应用程序部署到 Tomcat 6.0,然后迁移代码并将其部署到 WebSphere® Application Server Community Edition V2.1。该示例应用程序突出说明了这两种实现之间的一些显著差异。

Ashish Jain, 软件工程师, IBM

Ashish Jain 是 IBM WebSphere Application Server Community Edition 的 Level 3 Technical Support 的一位软件工程师。他获得了 NITK Surathkal 的计算机科学工程学士学位,并于 2005 年作为 ELTP 加入 IBM。



2008 年 9 月 24 日

引言

现在就下载 Community Edition V2.1!
IBM WebSphere Application Server Community Edition V2.1 可供免费使用和部署。现在就下载它,以开始后面的工作。

IBM WebSphere Application Server Community Edition(以下称为 Community Edition)是一个 Java™ Enterprise Edition 5 (Java EE5) 认证应用程序服务器,其中包含用于数据 (Apache Derby)、消息服务 (Active MQ)、Web 服务 (Apache Axis) 等的集成组件。

Community Edition 是使用 Geronimo Beans (GBean) 体系结构来构建的,并将 Apache Geronimo 作为其核心。Community Edition 的很小内存占用空间、易用性、免费可用性和 IBM 世界级的可选支持,使其对于中小型组织的来说非常理想。

Apache Tomcat 是由 Apache Software Foundation 开发的 Web 容器。它实现了 Java Servlet 和 Java Server Pages API。Tomcat Version 6.0.x 实现了 Java Servlet 2.5 和 Java Server Pages 2.1 API。

虽然本文将指导您把一个示例应用程序从 Tomcat 6.0.x 迁移到 Community Edition 2.1,但是从 Tomcat 5.x 进行迁移也是非常相似的。Tomcat Version 5.x 实现了 Java Servlet 2.4 和 Java Server Pages 2.0 API,并且 Community Edition 2.1 与这些版本向后兼容。然而,在如何定义配置方面可能存在一些差异。

本文指导您将一个在 Apache Tomcat 上开发的应用程序迁移到 Community Edition。我们在 Tomcat 和 Community Edition 上使用了 Eclipse IDE 来进行应用程序开发。本文将按以下部分进行组织:


体系结构分析——相似性和区别

图 1. Geronimo (Community Edition) 体系结构
Community Edition 体系结构关系图

如图 1 所示,Community Edition 遵循组件体系结构。它包含来自各个开放源代码社区的最佳品种的开放源代码产品。Apache Tomcat 是 Community Edition 的缺省 Web 容器,因此您可以容易地将 Tomcat 上开发的应用程序迁移到 Community Edition。

在使用 Community Edition 时,您将使用与 Tomcat 的独立版本相同的 Tomcat 服务器。因此,您不需要针对 Community Edition 重新对应用程序打包。然而,在将应用程序从 Tomcat 迁移到 Community Edition 时,您需要解决它们之间存在的一些差异。出现这些差异的原因在于,Tomcat 是作为 Community Edition 中的一个服务来部署的,以提供可用于 Java EE5 认证应用程序服务器的功能;而不只是一个 Servlet 容器。Community Edition 中的 Tomcat 与其他已部署的容器服务集成在一起,例如:

  • JMS (Apache ActiveMQ)
  • 数据库 (Apache Derby)
  • EJB (Apache OpenEJB)
  • Web 服务 (Apache Axis)
  • 持久性 (Apache OpenJPA)
  • 日志记录
  • 安全性

为了克服大多数迁移问题,您需要弄清 Tomcat 中的每个服务如何映射并应用到 Community Edition。Tomcat 的基本体系结构是相同的,但是在 Community Edition 中将其定义为一个 gbean。这种实现使得更新版本的 Tomcat 能够容易地集成到将来的 Community Edition 版本中。

下表说明了独立 Tomcat 与运行在 Community Edition 中的 Tomcat 之间的主要区别和相似之处:

表 1. Tomcat V6.0.x 和 Community Edition V2.1 功能比较
功能TomcatCommunity Edition
Java Servlet实现 Servlet 2.5 API实现 Servlet 2.5 API
Java Server Pages实现 JSP 2.1 API实现 JSP 2.1 API
JNDI一般通过 server.xml 进行手动配置JNDI 能够访问由 Geronimo 内核管理的对象引用
JMScontext.xml 中进行手动配置可以使用基于 Web 的 GUI 来创建 JMS 资源
JDBC 数据源context.xml 中进行手动配置可以使用基于 Web 的 GUI 来创建 JDBC 资源
Web 服务 (Apache Axis)Axis.war 的部署引入 WebServices 功能Axis 已预先集成到 Community Edition 中。
安全领域使用 server.xmlcontext.xml 文件进行配置支持容器管理的领域,这些领域可用于所有组件的授权。还可以定义单独的组件领域。
多个连接器多个协议处理程序访问同一个引擎。HTTP 连接器可以与同一个引擎上的 SSL 连接器一起工作可以使用管理控制台来配置各个连接器,包括 HTTP、SSL 以及用于负载平衡和集群的 Apache JServ 协议 (AJP13)
虚拟主机支持在同一个 IP 地址上承载不同的网站。可以使用 server.xml 来对此进行配置可以通过配置config.xml 实现相同的功能
部署描述符web.xml 是 J2EE Web 应用程序 (WAR) 的缺省部署描述符web.xml 是 J2EE Web 应用程序 (WAR) 的缺省部署描述符
部署计划没有特定于供应商的部署描述符Community Edition 具有特定于 Geronimo 的部署描述符,用于配置特定于 Geronimo 的服务。对于 Web 应用程序,geronimo-web.xml 是部署计划。

在 Community Edition 中,大多数配置可以使用以下部署计划之一来完成:geronimo-web.xmlconfig.xmlconfig-substitution.properties。您还可以使用基于 Web 的管理控制台添加资源,例如 JMS 队列、连接工厂和 JDBC 数据源。该控制台简化了配置管理,而在 Tomcat 中则是使用 server.xmlcontext.xml 进行手动配置。


关于示例应用程序

我们从 Tomcat V6.0.x 迁移到 Community Edition V2.1 的示例应用程序是使用了以下组件的通用商店应用程序:

  • JSP
  • Servlet
  • JSP 标准标记库(JSP Standard Tag Library,JSTL)
  • Apache Derby JDBC 数据源
  • 基于 Apache ActiveMQ 的 JMS
  • 基于 Apache Axis 的 Web 服务

该应用程序还使用缺省的 Tomcat UserRealm 对用户进行身份验证,而 Community Edition 则使用缺省的 geronimo-admin 领域。

本文包括的示例应用程序由单个 WAR 模块组成,其中包含以下内容:

  • generalstore.jsp——向用户呈现购物目录。通过外部 Web 服务显示当前 IBM 股票价格。
  • checkoutcart.jsp——向用户呈现购物车。通过 Derby 数据源使用 RDBMS 显示促销消息。通过外部 Web 服务显示 IBM 股票价格。
  • generalstore.css——样式表,用于格式化两个 JSP 页面所使用的 HTML 元素。
  • StockService.wsdl——描述 Web 服务的位置以及服务中可用的方法。您将使用此 WSDL 文件来生成所需的 Java 类,并使用 Eclipse 工具来生成这些类文件。
  • StoreController.java——主控制器,用于将请求分派到 JSP。还可以获得目录和产品信息,并将这些信息作为 JSP 的属性附加以进行显示。
  • GeneralStore.java——包含返回应用程序所需数据的方法。还包含实现自定义标记库的功能(请参见 generalstore-taglib.tld)。
  • Category.java、Product.java、LineItem.java——当数据在应用程序的模型和视图之间传输时用于保存值的 JavaBean。
  • CheckOut.java——完成订单并将订单发送给库存管理器。

设置 Tomcat 以进行应用程序部署

Tomcat 连接器配置

缺省情况下,Tomcat 服务器在端口 8080 上侦听请求。要更改此缺省端口,您可以修改 <Tomcat_Home>/conf/server.xml。清单 1 显示了更改缺省端口配置所需要的修改。

清单 1. server.xml 中的 Tomcat 连接器配置
<Service name="Catalina">
     ...
     ...
<Connector port="8080" 
 protocol="HTTP/1.1" 
 connectionTimeout="20000"
 redirectPort="8443" />

将端口值更改为您喜欢的任何端口。请记住在对 server.xml 做出任何配置更改之前停止服务器。重新启动服务器以使设置生效。

Tomcat 身份验证领域配置

在 Tomcat 中,领域维护用户、组和密码信息。缺省情况下,您在 Tomcat 中配置一个 UserDatabaseRealm,从而使您能够在允许用户访问商店之前对他们进行身份验证。server.xml 文件也设置了此领域。清单 2 中的 server.xml 代码段中粗体显示的行表示该身份验证领域的配置。

清单 2. server.xml 中的 Tomcat UserDatabaseRealm 配置
<Server port="8005" shutdown="SHUTDOWN">
     ...
    <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  ... 
  <Service name="Catalina">
  
    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />

      ...

      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>

上面的配置将 UserDatabaseRealm 设置为使用 conf/tomcat-users.xml 下面的一个文件来维护用户、密码和角色信息。由于该领域是在 <Engine> 级别配置的,因此它对运行在 Tomcat <Engine> 组件实例上的所有主机可用。

要运行我们的应用程序,您不必对 conf/server.xml 文件进行任何修改,因为原样的缺省配置就适合我们的需要。但是,您确实需要对 conf/tomcat-users.xml 文件做出某些更改,其中 UserDatabaseRealm 保存了所有的用户信息。对 tomcat-users.xml 文件进行清单 3 中以粗体表示的更改。

清单 3. 在 tomcat-users.xml 中为 Tomcat 用户添加管理员和管理器角色
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
  <role rolename="tomcat"/>
  <role rolename="role1"/>
  <user username="tomcat" password="tomcat" roles="tomcat,manager,admin"/>
  <user username="role1" password="tomcat" roles="role1"/>
  <user username="both" password="tomcat" roles="tomcat,role1"/>
</tomcat-users>

此代码将 tomcat 用户(密码为“tomcat”角色分配为 manageradmin 组的成员。

在该应用程序的 web.xml 文件中,商店的控制器受到保护,并且它只对具有“admin”角色的用户授予访问权限。清单 4 中的粗体行显示了保护应用程序的 web.xml 代码(在代码分发包的 dd 目录中)。

清单 4. 对应用程序进行身份验证访问保护的 web.xml 部署描述符
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns="http://java.sun.com/xml/ns/javaee" 
  xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
  id="WebApp_ID" version="2.5">
  <display-name>ShoppingStore</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>GeneralStore</servlet-name>
    <servlet-class>com.ibm.wasce.store.StoreController</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>GeneralStore</servlet-name>
    <url-pattern>/store.cgi</url-pattern>
  </servlet-mapping>
  <resource-ref>
    <description>Derby DB connection</description>
    <res-ref-name>jdbc/storeDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
  <security-constraint>
    <display-name>General Store Security Constraint</display-name>
    <web-resource-collection>
      <web-resource-name>Entire store</web-resource-name>
      <url-pattern>*.cgi</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>admin</role-name>
    </auth-constraint>
  </security-constraint>
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Shopping Realm</realm-name>
  </login-config>
  <security-role>
    <role-name>admin</role-name>
  </security-role>
  <servlet>
    <description></description>
    <display-name>CheckOut</display-name>
    <servlet-name>CheckOut</servlet-name>
    <servlet-class>com.ibm.wasce.store.CheckOut</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>CheckOut</servlet-name>
    <url-pattern>/CheckOut</url-pattern>
  </servlet-mapping>
</web-app>

上面的代码中的 <security-constraint><security-role> 元素是标准 J2EE 安全配置元素,并且在容器之间是可移植的。因此,未改变的 web.xml 稍后可以在 Community Edition 环境中工作。

设置 Derby 网络服务器

首先,请确保安装了 Apache Derby 10.3.1。然后按照以下步骤操作:

  1. 将 DERBY_INSTALL 环境变量设置为您的 Derby 安装目录。在 CLASSPATH 环境变量中包括以下元素:
    • lib/derby.jar
    • lib/derbytools.jar
    • lib/derbynet.jar
    • lib/derbyclient.jar
  2. 使用以下命令启动 Derby 服务器:
    	java org.apache.derby.drda.NetworkServerControl start

    Derby 服务器启动并在缺省端口 1527 进行侦听。

  3. 创建名为 generalstore 的数据库,其中只有一个名为 promotions 的表。createdb1.sql 脚本将创建并填充该数据库。

    使用 ij 命令执行该 SQL 脚本:
    java org.apache.derby.tools.ij createdb1.sql

createdb1.sql 脚本包含清单 5 所示的 SQL 命令。

清单 5. createdb1.sql 脚本:创建数据库表并填充数据
connect 'jdbc:derby://localhost/generalstore;create=true';
drop table promotion;
create table promotion
  (id char (5) not null,
   message char(40) not null,
   primary key(id));
insert into promotion values ('1', 'Thank your for your order.');
insert into promotion values ('2', 'Have a nice day!');
exit;

如果您看到消息 ERROR 08001: No suitable driver,则所需的 lib/derbyclient.jar 库不在 CLASSPATH 环境变量中。

设置 Apache ActiveMQ JMS 代理

确保安装了 apache-activemq-4.1.1,然后执行以下步骤:

  1. 在 CLASSPATH 环境变量中包括以下元素。
    • lib/activeio-core-3.0.0-incubator.jar
    • lib/commons-logging-1.1.jar
    • <ActiveMQ_HOME>/apache-activemq-4.1.1.jar
  2. 通过运行 activemq.bat 脚本启动 ActiveMQ 代理。您可以在 <ActiveMQ_HOME>/bin 中找到此脚本。

设置 Apache Axis

在 CLASSPATH 环境变量中包括以下元素。您可以从 Eclipse 中自动下载下面提到的 JAR。有关更多信息,请参阅“从 Community Edition WAR 文件中删除不需要的服务”。

  • wsdl4j-1.5.1.jar
  • saaj.jar
  • jaxrpc.jar
  • axis.jar

Tomcat JNDI 资源引用和 JDBC 连接器

checkoutcart.jsp 页面使用 JSTL 的 SQL 支持标记访问促销数据库并输出促销消息。清单 6 显示了访问 RDBMS 的代码摘录。

清单 6. 访问数据库服务器的 checkoutcart.jsp 中的 JSP 代码
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="storetags" uri="/GeneralStoreTagLibrary" %>
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql"  %>
 ...
<sql:query var="rs" dataSource="jdbc/storeDB">
   select * from promotion
</sql:query>
 ...
<tr>
<td colspan="5">
<c:forEach var="row" items="${rs.rows}">
   ${row.message}<br/>
</c:forEach>
</td>
</tr>

JSTL <sql:query> 标记将通过 JNDI查找名为 jdbc/storeDB 的数据源。该名称引用是以 J2EE 标准的方式在应用程序的 web.xml 部署描述符中定义的。该标准配置同时适用于 Tomcat 和 Community Edition。清单 7 显示了该配置。

清单 7. web.xml 中指定 JNDI 数据源引用的元素
<resource-ref>
      <description>Derby DB connection</description>
      <res-ref-name>jdbc/storeDB</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
</resource-ref>

您现在需要配置此引用,以便以特定于容器的方式(对于 Tomcat 和 Community Edition 来说是不同的)匹配实际的 JDBC 驱动程序和 RDBMS 连接。对于 Tomcat,您将在 conf/context.xml 文件(可以在 Tomcat 安装目录中找到)中进行配置。请参见清单 8:

清单 8. 将 JNDI 资源与 Derby JDBC 连接器相关联的特定于 Tomcat 的 context.xml 描述符
<Context>
     ...
     ...
<Resource name="jdbc/storeDB" auth="Container" type="javax.sql.DataSource"
  maxActive="100" maxIdle="30" maxWait="10000"
  driverClassName="org.apache.derby.jdbc.ClientDriver"
  user="APP" password="APP" 
  url="jdbc:derby://localhost/generalstore"/>
     ...
     ...
</Context>

为 ActiveMQ 代理配置 Tomcat

CheckOut.java Servlet 在下订单成功时显示一条消息。清单 9 显示了该 Servlet 中查找连接工厂和队列的代码摘录:

清单 9. Servlet 代码摘录
Context initContext = new InitialContext();
Context jndiContext=(Context) initContext.lookup("java:comp/env");
connectionFactory = (ConnectionFactory)  jndiContext.lookup("jms/ConnectionFactory");
queue = (Queue) jndiContext.lookup("jms/aQueue");

您将在 web.xml 中定义对连接工厂和队列的名称引用,如清单 10 所示。

清单 10. web.xml 中指定 JMS 连接工厂和队列的元素
<resource-ref>
        <description>jms broker</description>
        <res-ref-name>jms/ConnectionFactory</res-ref-name>
        <res-type>javax.jms.ConnectionFactory</res-type>
        <res-auth>Container</res-auth>
  </resource-ref>
	<message-destination-ref>
		<message-destination-ref-name>jms/aQueue</message-destination-ref-name>
		<message-destination-type>javax.jms.Queue</message-destination-type>
		<message-destination-usage>ConsumesProduces</message-destination-usage>
		<message-destination-link>aQueue</message-destination-link>
	</message-destination-ref>
	<message-destination>
		<message-destination-name>aQueue</message-destination-name>
	</message-destination>

您现在需要为 ActiveMQ 连接工厂和目标队列配置 Tomcat,也是以特定于容器的方式进行配置。对于 Tomcat,您可以在 conf/context.xml 文件(可以在 Tomcat 安装目录中找到)中进行配置。清单 11 显示了连接工厂和目标队列参数。

清单 11. 用于 ActiveMQ 配置的特定于 Tomcat 的 context.xml 描述符
<Context>
     ...
     ...
<Resource
        name="jms/ConnectionFactory"
        auth="Container"
        type="org.apache.activemq.ActiveMQConnectionFactory"
        description="JMS Connection Factory"
        factory="org.apache.activemq.jndi.JNDIReferenceFactory"
        brokerURL="tcp://localhost:61616"
        brokerName="localhost"
        persistent="false"
        useEmbeddedBroker="false"/>

     <Resource name="jms/aQueue"
        auth="Container"
        type="org.apache.activemq.command.ActiveMQQueue"
        factory="org.apache.activemq.jndi.JNDIReferenceFactory"
        physicalName="MY.TEST.QUEUE"/>
     ...
     ...
</Context>

使用 StockService.wsdl 生成 Web 服务类

在本部分中,我们将生成 Web 服务类:

  1. 清单 12 显示了生成 Web 服务构件所需要的 WSDL 文件。

    清单 12. 用于生成 Web 服务构件的 StockService.wsdl

    <wsdl:definitions xmlns:http=http://schemas.xmlsoap.org/wsdl/http/
       xmlns:soap=http://schemas.xmlsoap.org/wsdl/soap/
       xmlns:s=http://www.w3.org/2001/XMLSchema
       xmlns:soapenc=http://schemas.xmlsoap.org/soap/encoding/
       xmlns:tns=http://www.webserviceX.NET/
       xmlns:tm=http://microsoft.com/wsdl/mime/textMatching/
       xmlns:mime=http://schemas.xmlsoap.org/wsdl/mime/
       targetNamespace=http://www.webserviceX.NET/
       xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    
      <wsdl:types>
       <s:schema elementFormDefault="qualified" 
              targetNamespace="http://www.webserviceX.NET/">
       <s:element name="GetQuote">
         <s:complexType>
          <s:sequence>
           <s:element minOccurs="0" maxOccurs="1" name="symbol"
            type="s:string"/>
          </s:sequence>
         </s:complexType>
        </s:element>
        <s:element name="GetQuoteResponse">
         <s:complexType>
          <s:sequence>
           <s:element minOccurs="0" maxOccurs="1" name="GetQuoteResult" type="s:string"/>
          </s:sequence>
         </s:complexType>
        </s:element>
        <s:element name="string" nillable="true" type="s:string"/>
       </s:schema>
      </wsdl:types>
      <wsdl:message name="GetQuoteSoapIn">
       <wsdl:part name="parameters" element="tns:GetQuote"/>
      </wsdl:message>
      <wsdl:message name="GetQuoteSoapOut">
       <wsdl:part name="parameters" element="tns:GetQuoteResponse"/>
      </wsdl:message>
      <wsdl:message name="GetQuoteHttpGetIn">
       <wsdl:part name="symbol" type="s:string"/>
      </wsdl:message>
      <wsdl:message name="GetQuoteHttpGetOut">
       <wsdl:part name="Body" element="tns:string"/>
      </wsdl:message>
      <wsdl:message name="GetQuoteHttpPostIn">
       <wsdl:part name="symbol" type="s:string"/>
      </wsdl:message>
      <wsdl:message name="GetQuoteHttpPostOut">
       <wsdl:part name="Body" element="tns:string"/>
     </wsdl:message>
    
     <wsdl:portType name="StockQuoteSoap">
      <wsdl:operation name="GetQuote">
       <wsdl:input message="tns:GetQuoteSoapIn"/>
       <wsdl:output message="tns:GetQuoteSoapOut"/>
      </wsdl:operation>
     </wsdl:portType>
    
     <wsdl:portType name="StockQuoteHttpGet">
      <wsdl:operation name="GetQuote">
       <wsdl:input message="tns:GetQuoteHttpGetIn"/>
       <wsdl:output message="tns:GetQuoteHttpGetOut"/>
      </wsdl:operation>
     </wsdl:portType>
    
     <wsdl:portType name="StockQuoteHttpPost">
      <wsdl:operation name="GetQuote">
      <wsdl:input message="tns:GetQuoteHttpPostIn"/>
       <wsdl:output message="tns:GetQuoteHttpPostOut"/>
      </wsdl:operation>
     </wsdl:portType>
    
     <wsdl:binding name="StockQuoteSoap" type="tns:StockQuoteSoap">
      <soap:binding transport=http://schemas.xmlsoap.org/soap/http
       style="document"/>
      <wsdl:operation name="GetQuote">
       <soap:operation soapAction=http://www.webserviceX.NET/GetQuote
         style="document"/>
       <wsdl:input>
        <soap:body use="literal"/>
       </wsdl:input>
       <wsdl:output>
        <soap:body use="literal"/>
       </wsdl:output>
      </wsdl:operation>
     </wsdl:binding>
    
     <wsdl:binding name="StockQuoteHttpGet" type="tns:StockQuoteHttpGet">
      <http:binding verb="GET"/>
      <wsdl:operation name="GetQuote">
       <http:operation location="/GetQuote"/>
       <wsdl:input>
        <http:urlEncoded/>
       </wsdl:input>
       <wsdl:output>
        <mime:mimeXml part="Body"/>
       </wsdl:output>
      </wsdl:operation>
     </wsdl:binding>
    
     <wsdl:binding name="StockQuoteHttpPost" type="tns:StockQuoteHttpPost">
      <http:binding verb="POST"/>
      <wsdl:operation name="GetQuote">
       <http:operation location="/GetQuote"/>
       <wsdl:input>
        <mime:content part="NMTOKEN" type="application/x-www-form-urlencoded"/>
       </wsdl:input>
       <wsdl:output>
        <mime:mimeXml part="Body"/>
       </wsdl:output>
      </wsdl:operation>
     </wsdl:binding>
     <wsdl:service name="StockQuote">
      <wsdl:port name="StockQuoteSoap" binding="tns:StockQuoteSoap">
       <soap:address location="http://www.webservicex.net/stockquote.asmx"/>
      </wsdl:port>
      <wsdl:port name="StockQuoteHttpGet" binding="tns:StockQuoteHttpGet">
       <http:address location="http://www.webservicex.net/stockquote.asmx"/>
      </wsdl:port>
      <wsdl:port name="StockQuoteHttpPost" binding="tns:StockQuoteHttpPost">
       <http:address location="http://www.webservicex.net/stockquote.asmx"/>
      </wsdl:port>
     </wsdl:service>
    </wsdl:definitions>
  2. 右键单击 Stock Service.wsdl 文件(如图 2 所示),并选择 Web Services -Generate Client
    图 2. 使用 StockService.wsdl 生成 Web 服务构件
    显示如何选择“Web Services - Generate Client”的屏幕快照
  3. 此步骤自动生成 Web 服务的所有必需构件。将生成下列类,如图 3 所示:
    • StockQuote.java
    • StockQuoteLocator.java
    • StockQuoteSoap.java
    • StockQuoteSoapProxy.java
    • StockQuoteSoapStub.java

    此步骤还将下载在“设置 Apache Axis”部分中提到的 JAR,并将 jar 移动到应用程序的 WEB-INF/lib 文件。

    图 3. 生成的 Web 服务类
    显示 Project Explorer 中的类清单的屏幕快照
  4. 为了在我们的应用程序中访问 Web 服务,我们将清单 13 中的代码添加到 checkoutcart.jspgeneralstore.jsp 文件。

    清单 13. 访问 IBM 股票报价的代码片段

    <%
    StockQuoteLocator sql = new StockQuoteLocator(); 
    StockQuoteSoap sqs = sql.getStockQuoteSoap();
    PrintWriter out1 =response.getWriter(); 
    String s1=sqs.getQuote("IBM");
     s1=s1.substring(46,51);
    %>

    在我们的例子中,我们将 IBM 作为变量进行传递,该变量将从 Stock Web 服务检索 IBM 股票报价。


在 Tomcat 中部署应用程序

在本部分中,我们将在 Tomcat 中部署应用程序,并使用以下步骤:

  1. 从 Eclipse 中将应用程序导出为 WAR 文件。
  2. 启动 Tomcat 并使用以下命令运行 Web 控制台:
    http://localhost:8080/manager/html
  3. 系统将提示您登录;请使用我们在前面设置的 UserDatabaseRealm。由于需要管理器角色,请输入 tomcat 作为 user namepassword
  4. 管理器应用程序将显示所有已部署的模块。滚动到底部,此处有一个框 Deploy directory or WAR file located on server。对于 Context path,请输入 /Shopping,对于 WAR or Directory URL,请输入到 generalstore.war 文件的绝对路径。
  5. 单击 Deploy 按钮。现在您应该看到运行于 /Shopping 上下文的 General Store 应用程序。图 4 显示了成功部署后的管理器应用程序。
    图 4. Tomcat 中的成功应用程序部署
    Tomcat Web 应用程序管理器的屏幕快照
  6. 要访问该应用程序,可以输入以下 URL:http://localhost:8080/Shopping/store.cgi

将应用程序迁移到 Community Edition

一般情况下,要将 General Store 应用程序迁移到 Community Edition 1.0,您需要执行以下操作:

  1. 对 Tomcat UserDatabaseRealm 进行配置,并将它替换为某个由 Community Edition 容器管理的身份验证领域。
  2. 启动并使用 Community Edition 中包括的 Derby RDBMS,而不是使用独立版本的 Derby。
  3. 创建由 Community Edition 管理的新数据源。
  4. 创建所需的数据库表并为其填充数据。
  5. 配置一个 JNDI 引用以使其指向 Community Edition 中的 Derby 数据源。
  6. 在 Community Edition 中配置 ActiveMQ JMS 代理连接工厂和队列。

迁移过程中不需要更改的元素有:

  • web.xml 中对 JNDI 数据源的引用。
  • web.xml 中保护应用程序的安全性配置。

对于这些元素,要小心进行编码,以使其在 J2EE 容器之间可以移植。

在 Community Edition 中更改 Tomcat 连接器使用的端口

如果您需要在 Community Edition 中更改 Tomcat 连接器使用的端口,不要查找 server.xml 文件;Community Edition 中没有这个文件。取而代之,要在 Community Edition 安装目录下的 var/config 目录中查找 config-substitutions.properties 文件。清单 14 显示了 Community Edition 中的端口配置:

清单 14. Community Edition 中的 Tomcat 端口配置
AJPPort=8009
clusterNodeName=NODE
ORBPort=6882
MaxThreadPoolSize=500
ResourceBindingsNamePattern=
SMTPHost=localhost
ResourceBindingsQuery=?\#org.apache.geronimo.naming.ResourceSource
COSNamingPort=1050
webcontainer=TomcatWebContainer
OpenEJBPort=4201
ORBSSLPort=2001
PortOffset=0
ActiveMQStompPort=61613
JMXPort=9999
ORBHost=localhost
EndPointURI=http\://localhost\:8080
NamingPort=1099
DefaultWadiSweepInterval=36000
WebConnectorConTimeout=20000
HTTPSPort=8443
COSNamingHost=localhost
MinThreadPoolSize=200
ReplicaCount=2
ServerHostname=0.0.0.0
ActiveMQPort=61616
ORBSSLHost=localhost
SMTPPort=25
webcontainerName=tomcat6
ResourceBindingsNameInNamespace=jca\:
DefaultWadiNumPartitions=24
HTTPPort=8080
clusterName=CLUSTER_NAME
ClusterName=DEFAULT_CLUSTER
ResourceBindingsFormat={groupId}/{artifactId}/{j2eeType}/{name}
RemoteDeployHostname=localhost
TmId=71,84,77,73,68

您可以在 Community Edition 中修改清单 14 中的代码,以更改缺省端口配置。您还可以取消注释 PortOffset 变量,并输入自己选择的值。此更改将通过所定义的 PortOffset 值修改 Community Edition 中的所有服务的端口设置。例如,如果您定义了 PortOffset=10,则 HTTP 端口将为 8090,管理控制台的 URL 将为 http://localhost:8090/console

记住使用以下命令关闭 Tomcat 应用程序使用的独立 Derby 数据库:
java org.apache.derby.drda.NetworkServerControl stop

另外,您也可以使用 Web 控制台添加 Tomcat 连接器,或者编辑连接器使用的端口号。只需在 Web 控制台菜单中选择 Server - Web Server 。在编辑并保存端口号更改之后,重新启动以使端口更改立即生效。记住,如果您在使用该端口号显示管理控制台,请更改浏览器 URL 中的端口号以重新显示控制台。

配置 Community Edition 管理的身份验证领域

缺省情况下,Community Edition 管理一个名为 geronimo-admin 的领域,该领域使用 var/security 目录下的属性文件存储用户、密码和组信息。该领域中配置的唯一用户是 system,其密码为 manager,并属于 admin 组和角色。通过使用 Web 控制台菜单中的 Security - Console Realm 选项,您可以向缺省领域添加用户和组。

您可以在特定于 Community Edition 的部署计划 geronimo-web.xml 中配置该安全领域。您需要在 geronimo-web.xml 中添加清单 15 中的代码:

清单 15. Community Edition 中的安全领域配置
<security-realm-name>geronimo-admin</security-realm-name>
<sec:security>
 <sec:default-principal realm-name="geronimo-properties-realm">
  <sec:principalclass="org.apache.geronimo.
     security.realm.providers.GeronimoUserPrincipal" name="system"/>
  </sec:default-principal>
  <sec:role-mappings>
   <sec:role role-name="admin">
    <sec:realm realm-name="geronimo-admin">
      <sec:principalclass="org.apache.geronimo.
        security.realm.providers.GeronimoGroupPrincipal" name="admin"/>
      <sec:principalclass="org.apache.geronimo.
        security.realm.providers.GeronimoUserPrincipal" name="system"/>
     </sec:realm>
   </sec:role>
  </sec:role-mappings</sec:security>

在 Community Edition 中创建 Promotion 数据库表

使用一个基于 GUI 的 Web 控制台,您可以容易地在 Community Edition 中创建 Promotion 表:

  1. 启动服务器。
  2. 使用 http://localhost:8080/console 启动管理控制台。
  3. 输入缺省 user name (system)password (manager)。
  4. 在控制台导航窗格中,在 Embedded DB 下面选择 DB Manager ,如图 5 所示:
    图 5. 管理控制台中的 DB Portlet
    显示如何导航到 DB Manager 的屏幕快照
  5. 在下一个屏幕(图 6)上,将 Create DB 名称指定为 generalstore 并选择 Create
    图 6. 创建 generalstore 数据库
    显示 Run SQL 页面的屏幕快照
  6. Use DB 下拉框中,选择 generalstore 并运行清单 16 所示的脚本,如图 7 所示:

    清单 16. 用于在 Community Edition 中创建 Promotion 表的脚本

    create table promotion	 
     (id char (5) not null, 
       message char(40) not null, primary key(id));
      insert into promotion values ('1', 'Thank your for your order.');
      insert into promotion values ('2', 'Have a nice day!');
    图 7. 创建 Promotion 表
    显示 Run SQL 页面上的脚本代码的屏幕快照

在 Community Edition 中创建 Derby 数据源

  1. 使用 http://localhost:8080/console/ 启动管理控制台。输入缺省 user namepassword (systemmanager)。
  2. 在控制台导航窗格中,在 Services 下面选择 Database Pools
  3. 在下一个屏幕(图 8)上,选择 Using Geronimo database pool wizard:
    图 8. 选择 Geronimo 数据库池向导
    显示如何选择 Geronimo 数据库池向导的屏幕快照
  4. 将该数据库池命名为 SampleDS 并将 Database Type 设置为 Derby Embedded XA,如图 9 所示。选择 Next
    图 9. 在 Community Edition 中创建数据库池
    显示要在 Database Pools 页面上输入的值的屏幕快照
  5. 在 Database Pools 向导上,填充如图 10 所示的表单。这里要注意,PasswordAPP单击 Deploy
    图 10. 在 Community Edition 中创建数据库池
    显示数据库池的编辑页面的屏幕快照
  6. 在成功部署之后,您可以看到 SampleDS 数据源已添加到 Community Edition 中已部署的池列表中,如图 11 所示:
    图 11. 已部署的数据库池列表中的 SampleDS 数据源
    显示新的 SampleDS 数据源的屏幕快照
  7. 使用 geronimo-web.xml 部署计划中的 <dependency><resource-ref> 元素,将 SampleDSjdbc/storeDBweb.xml JNDI 引用相关联,如清单 17 所示。

    清单 17. geronimo-web.xml 部署计划中的代码片段

    <sys:dependency>
      <sys:groupId>console.dbpool</sys:groupId>
      <sys:artifactId>SampleDS</sys:artifactId>  
    </sys:dependency>
    	
    <naming:resource-ref>
      <naming:ref-name>jdbc/storeDB</naming:ref-name>
      <naming:resource-link>SampleDS</naming:resource-link>
    </naming:resource-ref>

创建 ActiveMQ JMS 连接工厂和队列

您可以使用 GUI Web 控制台容易地创建 Community Edition 管理的连接工厂和队列:

  1. 启动管理控制台。在控制台导航窗格中,在 Services 下面选择 JMS Resources。在下一个屏幕上选择 For ActiveMQ
  2. 在下一个屏幕上,填充如图 12 所示的表单。然后单击 Next
    图 12. 配置 JMS 资源组
    显示 JMS Resources 页面的值的屏幕快照
  3. 在下一个屏幕(图 13)上,选择 Add Connection Factory
    图 13. 添加连接工厂
    显示如何选择 Add Connection Factory 按钮的屏幕快照
  4. 选择 javax.jms.ConnectionFactory 作为工厂类型(图 14),然后单击 Next
    图 14. 添加连接工厂
    显示如何选择 JMS 工厂类型的屏幕快照
    .
  5. 填充如图 15 所示的表单。然后单击 Next
    图 15. 添加连接工厂
    显示用于配置连接工厂的值的屏幕快照
  6. 在下一个屏幕(图 16)上,选择 Add Destination 以添加队列。
    图 16. 添加目的地
    显示如何选择 Add Destination 按钮的屏幕快照
  7. 从下拉框中选择 javax.jms.Queue,如图 17 所示。单击 Next
    图 17. 设置目的地类型
    显示如何选择 JMS 目的地类型的屏幕快照
  8. Message Destination Name 设置为 jms/aQueue,如图 18 所示。单击 Next
    图 18. 添加队列
    显示消息目的地名称的屏幕快照
  9. 在下一个屏幕(图 19)上,选择 Deploy Now,这将在 Community Edition 上部署该资源计划。
    图 19. 将资源计划部署到 Community Edition
    显示如何选择 Deploy Now 按钮的屏幕快照
  10. 成功部署后,您可以看到该迁移作为可用的 JMS 资源之一出现,如图 20 所示:
    图 20. 可用资源列表中的迁移 JMS 资源
    显示迁移资源出现在 JMS 资源列表中的屏幕快照
  11. 通过使用 geronimo-web.xml 部署计划中的 <dependency><resource-ref> 元素,您可以关联已经在 web.xml 中的连接工厂和队列,如清单 18 所示。

    清单 18. geronimo-web.xml 部署计划中的代码片段

    	<sys:dependency>
    	 <sys:groupId>org.apache.geronimo.configs</sys:groupId>
    	 <sys:artifactId>activemq-ra</sys:artifactId>
    	 <sys:version>2.1.1</sys:version>
    	 <sys:type>car</sys:type>
    	</sys:dependency>
                     ...
                     ...
    	<naming:resource-ref> 
    	 <naming:ref-name>jms/ConnectionFactory</naming:ref-name>
    	 <naming:pattern>
    	   <naming:groupId>org.apache.geronimo.configs</naming:groupId>
    	   <naming:artifactId>activemq-ra</naming:artifactId>
    	   <naming:version>2.1.1</naming:version>
    	   <naming:name>DefaultActiveMQConnectionFactory</naming:name>
    	 </naming:pattern>
    	</naming:resource-ref>
    	
    	<naming:message-destination>
    	 <naming:message-destination-name>
    	  aQueue
    	 </naming:message-destination-name>
    	 <naming:admin-object-link>
    	  SendReceiveQueue
    	 </naming:admin-object-link>
    	</naming:message-destination>

从 Community Edition WAR 文件中删除不需要的服务

如果将示例 ShoppingStore_Tomcat.war 文件的大小(大约 9MB)与 ShoppingStore_CommunityEdition.war 文件的大小(大约 32KB)做一下比较,您可能疑惑为什么存在如此巨大的大小差异。原因在于,您需要在 Tomcat 安装的应用程序 WEB-INF\lib 目录中包括的所有服务(Axis、JMS、公共服务等)和 Derby 数据库驱动程序已经集成到 Community Edition 中。删除这些 jar 文件的优点在于,您不必集成和支持它们。

以下 ShoppingStore_Tomcat.war jar 文件包括在 WEB-INF\lib 中:

  • activeio-core-3.0.0-incubator.jar
  • apache-activemq-4.1.1.jar
  • axis.jar
  • commons-discovery-0.2.jar
  • commons-logging.jar
  • derby.jar
  • derbyclient.jar
  • derbynet.jar
  • derbytools.jar
  • jaxrpc.jar
  • jstl.jar
  • saaj.jar
  • standard.jar
  • wsdl4j-1.5.1.jar

这些 jar 文件也包括在 Community Edition 的 <WASCE_HOME>/repository 目录中。要确定 JAR 是否存在,可以在 /repository 目录中搜索不带版本(例如,activeio-core)或不带来源(例如,activemq)的组件名称。/repository 中的对应 jar 文件将包含版本(例如,axis1-4.jar)。未在 /repository 中列出的 JAR 文件(例如特定于应用程序的文件)将需要在 WEB-INF\l ib 中进行维护。

在此迁移示例中,Tomcat WEB-INF\lib 目录中的所有 JAR 文件都可以删除。大多数 Web 应用程序在 WEB-INF\lib 目录中放置某些特定于应用程序的 JAR 文件,因此减小库的能力视情况而异。数据库驱动程序 JAR 文件一般应该安装在 \repository 中并与应用程序共享。管理控制台工具将帮助下载和安装 \repository 中不可用的数据库驱动程序文件(即 Oracle 或 MySQL)(选择 Services - Database Pools - Using the Geronimo database pool wizard)。

此外,web.xml 文件中可能存在某些 <servlet> 参数,这些参数指向 WEB-INF\lib 目录中的 JAR 文件。您需要确定删除某个 JAR 文件是否需要对 web.xml 做出更改。


在 Community Edition 中部署应用程序

要部署应用程序,可以启动管理控制台并按照以下步骤操作:

  1. 在管理控制台导航窗格中,在 Applications 下面选择 Deploy New。
  2. 选择 Archive 文本框旁边的 Browse,并浏览到 Shoppingstore.war。单击 Install。此步骤将在 Community Edition 上部署应用程序,如图 21 所示:
    图 21. 在 Community Edition 上部署应用程序
    显示选择 Shoppingstore.war 文件的屏幕快照
  3. 使用 http://localhost:8080/Shopping/store.cgi 启动应用程序。在提示登录时,使用 system 作为 user name,使用 manager 作为 password

迁移问题故障排除

本文中的示例应用程序提供了用于典型 Tomcat 迁移的配置和部署计划示例。作为部署例子,示例中包括了许多不同的资源类型。管理控制台中的 Deploy New 菜单提供了无法部署的 WAR 文件的详细错误消息。

如果 WAR 文件无法部署,脚本部署工具也提供了错误信息。如果错误发生在应用程序测试过程中,请检查 Eclipse 服务器日志或 var\log\server.log 文件(在 Linux 中为 geronimo.out 文件),查找其中可能在访问应用程序时发生的 Java 错误。

一些常见的迁移问题包括:

  • 类加载器问题
  • 资源配置问题
  • 部署计划问题

我们将在下面几个部分中详细研究这些问题。

类加载器问题

缺省情况下,Community Edition 遵循首先从父配置(即从 \repository)中加载类的类加载器层次结构。Tomcat 首先从应用程序加载类。如果 Tomcat 应用程序使用较旧的组件(例如较旧版本的 Axis),而 API 结构已更改,可能就会出现问题。在此情况下,当您部署 WAR 时或在运行时,类加载器错误可能就会出现。

纠正类加载器问题的一种方法是向部署计划中的 <moduleId> 参数后面添加 hidden-classes 参数。hidden-classes 参数标识不应该从父配置加载类的名称。清单 19 显示了针对某个 Axis 类加载器问题的 geronimo-web.xml 示例。应用程序将使用 WEB-INF\lib 中的 axis.jar 文件:

清单 19. 针对某个 Axis 类加载器问题的 hidden-classes 代码
</moduleId>
<hidden-classes>
    <filter>org.apache.axis2<filter>
</hidden-classes>

另一种纠正类加载器问题的方法是将 inverse-classloading 参数添加到部署计划中的 <moduleId> 参数后面。逆向类加载致使 Community Edition 遵循在加载应用程序 WEB-INF\lib 类之后立即从父配置中加载类的类加载器层次结构。下面包括的清单 20 显示了用于逆向类加载器的 geronimo-web.xml 示例:

清单 20. 针对某个 Geronimo 类加载器问题的 inverse-classloading 代码
</moduleId>
<inverse-classloading/>

修改类加载器结构应该使应用程序能够成功迁移。然而,您应该在某个时候纠正应用程序代码以使用 Community Edition 中的组件,因为组件集成和支持是使用 Community Edition 而不使用 Tomcat 的主要优点。有关更多信息,请访问文档中的管理类路径

资源配置问题

诸如数据库和安全连接等资源可能导致部署和运行时问题。由于 Tomcat 具有不同的配置结构,并且使用 server.xmlcontext.xml,因此在迁移到 Community Edition 时可能会出现配置问题。在某些情况下,问题是参数不正确或访问问题。对于数据库,尝试在管理控制台中使用 Database Pools - Geronimo database pool wizard 来测试数据库连接。当您“部署”数据库时,该向导将对照数据库进行测试,如果连接不成功,则会出现错误。您可以编辑池以更改参数,然后重新测试,直到连接成功为止。对于安全领域,尝试在管理控制台中使用 Security Realms - Add new security realm 菜单来测试安全领域连接。Security Realm 向导中有一个菜单允许您输入登录用户名和密码以测试连接。如果登录成功,您可以编辑安全领域并重新测试,直到安全领域连接成功为止。

部署计划问题

geronimo-web.xml 部署计划需要特定的参数和格式才能正确工作。本文中使用的 General Store 应用程序在 ShoppinStore_WASCE.war 文件中包括了有效的 geronimo-web-xml 文件。可以从 Community Edition 下载站点获得示例应用程序包。这些示例包括各种带 geronimo-web.xml 部署计划的应用程序类型。您可以使用这些示例作为您自己的部署计划需求的基础。

此外,尝试使用管理控制台中的 Plan Creator 菜单,在由管理控制台创建的 Tomcat WAR 文件和资源连接(即数据库、JMS、安全连接)的基础上,创建 geronimo-web.xml 部署计划。此选项提供了一种创建 geronimo-web.xml 部署计划的简单方法。在部署 WAR 文件时,您可以通过使用 Plan 字段在 WAR 文件之外定义部署计划。有关部署 WAR 文件和外部部署计划的信息,请参见图 21


结束语

将应用程序从 Tomcat 6.0.x 迁移到 Community Edition V2.1 是相当简单的,因为 Tomcat 6.0.x 已完好无损地进行了集成,并且实际上是 Community Edition 的一部分。然而,由于 Community Edition 现在控制所有的配置管理,因此在 Tomcat 上通常位于 server.xmlcontext.xml 中的配置元素现在已迁移到:

  • config-substitution.properties:用于快速更改参数,例如连接器的端口号。
  • geronimo-web.xml:应用程序上下文的特定于 Community Edition 的部署计划;可以包括在存档文件的 WEB-INF 目录中。

通过将 Web 应用程序从 Tomcat 6.x 逐步迁移到 WebSphere Application Server Community Edition,我们看到了该迁移的要点包括:身份验证领域切换;JNDI 引用映射;设置 Derby 数据库;配置 JDBC 连接器、JMS 资源工厂和 JMS 队列。


下载

描述名字大小
Tomcat Web 压缩包ShoppingStore_Tomcat.war8.9MB
迁移到 Community Edtion 的 Web 压缩包ShoppingStore_CommunityEdition.war32KB

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere, Open source
ArticleID=339281
ArticleTitle=从 Apache Tomcat Version 6.0.x 迁移到 WebSphere Application Server Community Edition V2.1
publish-date=09242008