从 VisualAge for Java 迁移到 WebSphere Studio
 

2009-05-13 来源:网络

 

引言

虽然有一些关于迁移的循序渐进的好资料,但是多数资料没有提供足够的详尽的建议,例如,如何解决常见的 org.omg.CORBA.MARSHAL 错误。本文将帮助您把包含 EJB 和 Struts 的 J2EE Web 应用程序从 VisualAge for Java? 迁移到 WebSphere? Studio Application Developer 5.0(以下称为 WebSphere Studio)。本文包含从真实的项目中学到的技巧、注意事项和经验。这些信息有助于新手完成工作并且把中型项目的迁移时间从 2 周缩短到 1 周。

典型的 Web 应用程序体系结构

虽然在这里讨论应用程序体系结构是不合适的,但是这个体系结构列出了我们在完成迁移任务时必须完成的工作。本文把典型的 J2EE 项目 InterimDB 用作示例。实体 Bean 被用来表示应用程序的域对象。会话 Bean 被用来实现应用程序特有的工作流。添加业务委托层的目的是为了隐藏后端 EJB 系统的实现细节。我们还把 Apache Struts 用作 Web 框架,因为它被广泛应用于 J2EE 应用程序。以下几节讨论如何把每个层从 VisualAge for Java 迁移到 WebSphere Studio 5.0。

图 1. Web 应用程序体系结构
Web 应用程序体系结构

迁移 EJB 项目

这节讲述有关在 WebSphere Application Server V4 测试环境中把 EJB 项目从 VisualAge for Java 迁移到 WebSphere Studio V5 的过程和经验。如果您想了解详细的说明,请参阅 Migration Guide的第 8 章。

获取 EJB 导出工具

把 EJB 项目从 VisualAge for Java 迁移到 WebSphere Studio 的最好的方法是使用 VisualAge for Java V4 的 EJB 导出工具。如果您有 VisualAge for Java 的以前的版本,那么您需要升级。EJB 导出工具是 VisualAge for Java V4 的标准的功能部件。使用它的方法是按 F2键,然后单击 Add Features,选择 Export Tool for Enterprise Java Beans 1.1 4.0。如果您的旧的 EJB 项目有一些高级的功能(例如,EJB 关联)并且它的一个“组的关系有两个或多个外键被映射到相同的两个或多个表”,那么您必须安装这个工具的另一个修订包。您可以从 IBM VisualAge for Java 支持站点下载这个修订包 Export tool for EJB Fixpack 1.1 Version 4.1.5

导出 EJB 1.1 JAR

在您完成了以上的步骤后,您可以把旧的 EJB 项目作为 EJB 1.1 jar 导出:

  1. 在工作台的 EJB 页面中,用鼠标右键单击您要导出的 EJB 组,然后单击 Export -> EJB 1.1 JAR。您不能导出个别的 bean。
  2. 请确保 .class.java复选框都被选中。
  3. 选择您的数据库、导出目录和 jar 文件名,然后单击 Finish

图 2. 导出 EJB 组
导出 EJB 组

通过完成以上的导出过程,您把 EJB 组的所有的模式和映射信息导出到这个 EJB 1.1 jar 文件。

技巧:没有别的方法可以从 VisualAge for Java 中导出完整的模式和映射信息。

把 EJB 1.1 JAR 导入到 WebSphere Studio

在新的 WebSphere Studio IDE J2EE 透视图中:

  1. 选择 File -> Import -> EJB JAR file
  2. 单击 Next,然后选择从 VisualAge for Java 导出的 JAR 文件。
  3. 指定 EJB 项目和 .EAR 文件。
  4. 单击 Finish

您应当看到所有的东西(包括所有的模式和映射信息)被正确地导出到 WebSphere Studio。有两个新项目被创建:

  1. EJB 项目: InterimDB(这个名称与 VisualAge for Java 项目中的旧名称相同)
  2. 企业应用程序项目: InterimDBEAR

您还将在任务面板中看到警告。它们与 EJB 1.1 规范的新要求有关。稍后我们将解决有关的问题。

关于限定符的注意事项:在导出 EJB 1.1 jar 之前,您必须在 VisualAge for Java 的表编辑器中指定限定符。否则,您将看到如图 3 所示的 NULLID.CruiseTableColumns 。

图 3. 表编辑器
表编辑器

生成部署代码

您必须重新生成 Application Server 的部署代码。如果您想了解详细的说明,请参阅 Migration Guide的第 8 章。

创建服务器和添加 JDBC 数据源

如果您想了解详细的说明,请参阅 Migration Guide第 8 章。

关于 JNDI 名称的注意事项:JNDI 名称(例如 jdbc/InterimDBDS )被用来配置实体 bean。如果您成功地启动 WebSphere Application Server 4 测试环境,那么您可在控制台中看到这样的消息:

[11/29/02 11:02:38:399 SGT] 58d81d1f ResourceBinde I WSVR0049I: Binding InterimDBDS as jdbc/InterimDBDS
[11/29/02 11:02:38:399 SGT] 58d81d1f ResourceBinde I binding jdbc/InterimDBDS into global name space 
[11/29/02 11:02:38:459 SGT] 58d81d1f ResourceBinde I binding jdbc/jdbc/InterimDBDS into local: name space
    

不要担心 jdbc/jdbc/InterimDBDS 。这是 WebSphere 在它的本地名称空间中指定 JNDI 名称的方式。

图 4. 编辑数据源
编辑数据源

修改代码

如果您想详细地了解从 EJB 1.0 升级到 EJB 1.1 所需进行的代码修改,请参阅 Migration Guide的第 9 章。这项工作很简单的。主要的修改是用新的 javax.ejb.EJBException 取代 java.rmi.RemoteException 。请确保在代码修改之后任务面板中不再出现警告。

关于 java.rmi.MarshalException 的经验:EJB 1.1 规范要求远程对象的参数或返回值是任何可序列化的对象。您需要注意 WebSphere Studio 任务面板中的警告,例如:“ The return type must be serializable at runtime. (EJB 1.1: 9.2.7) (RMI 1.3: 2.6) ”。请注意编译器的警告。

如果您遇到类似“ java.rmi.MarshalException: CORBA MARSHAL 0 ”和“ Unable to read value from underlying bridge ”的错误,那么您很可能把某些接口(例如 Collection、List 和 Map)用作远程方法的返回类型或参数。除非您很了解这个问题,否则很难找出它。

即使您使用了可序列化的对象 Vector,也可能会遇到这个问题。为了解决 Vector 问题,IBM 有一个 WebSphere Application Server V4 的修订包:e-fix PQ60580。不幸的是您无法在 WebSphere 支持页面上找到它。您不得不要求 IBM 支持为您提供它。但是,把 Vector 改为 ArrayList 常常可以解决这个问题。您可在 IBM WebSphere Studio 新闻组 有关 Collection 接口的讨论中看到有关这个问题的详细的讨论。或者,您可在 Google 的新闻组 ibm.software.websphere.studio.j2ee中搜索“Session home interface returns Collection”短语。

下一节讨论您的测试客户机与服务器(WebSphere Application Server V4)之间的 JRE 版本的区别。

迁移业务委托层

因为业务委托层委托 EJB 代码,所以打包委托类的最容易的解决方案是把它们放在 EJB 项目中。在我们的情况中,我们有用于委托类的 net.lido.aims.interimdb.client 包,而所有的 EJB 都在 net.lido.aims.domain 中。我们可以把 net.lido.aims.interimdb.client 包与 EJB 包一起导入到 InterimDBEJB项目中。在这层中应该没有其它修改。

迁移 EJB JUnit 测试客户机

保证单元测试套件可以运行是确保 EJB 可以运行的最佳方法。在我们的项目中,JUnit 起到了关键性的作用:它与其它工具(例如 Apache Ant 和自制的框架 JDBCFramework)一起帮助我们实现了几乎自动的单元测试环境。每个 EJB 包有不同的 *.test 包。例如, InterimDB项目采用以下打包策略:

  • Country 的域对象在 net.lido.aims.interimdb.domain.country 中;
  • 单元测试代码在 net.lido.aims.interimdb.domain.country.test 中。

有了以上的设置,您就可以容易地导出 VisualAge for Java 中的测试代码,然后把它们作为一般的 Java 源文件导入到 WebSphere Studio。如果您想了解有关 Java 项目的迁移的更为详细的信息,请参阅 Migration Guide的第 6 章。简而言之,您:

  1. 选择所有的测试包,把 Java 源代码从 VisualAge for Java 导出到 jar 文件中。
  2. 在 WebSphere Studio 中创建新的应用程序客户机项目 InterimDBEJBClient
  3. 在项目的构建路径中,选择以前的 EJB 项目 InterimDBEJB,这样,所有的服务器类都在构建类路径中。
  4. 使用现有的 EAR 项目 InterimDBEAR把 Java 源文件导入到以上创建的项目中。

关于类路径的经验:当您在客户机项目的构建路径中选择服务器 EJB 项目的时候,所有的服务器类路径被自动地添加到客户机项目的构建类路径和运行时类路径。但是,如果您有系统属性,那么您仍然需要配置它们。在我们的项目中,为了使服务器端的框架可以在客户机 JVM 和服务器 JVM(WebSphere Application Server 4)中运行,我们不得不设置一些系统属性。

关于 JVM 版本的注意事项:在缺省的情况下,您创建的应用程序客户机项目在 WebSphere Studio 的缺省 JVM 中运行,这个 JVM 与服务器 JVM(例如针对客户机应用程序优化的 WebSphere Application Server 4 的 JVM)之间存在细微的差别。这可能导致出现 java.rmi.MarshalException 错误。把缺省的 JRE 改为“WebSphere V4 JRE”就可以解决这个问题。

图 5. JRE 版本
JRE 版本

迁移 Struts

把 Struts V1.02 应用程序迁移到 WebSphere Studio 并不困难。步骤如下:

  1. 在 WebSphere Studio 中创建新的 Web 项目(例如,在我们的情况中是 InterimDBWeb),使用现有的 EAR 项目 InterimDBEAR。完成之后,您将看到在 Web 项目中创建了标准的 Java Source 和 Web Content 目录。
  2. 从 VisualAge for Java 中导出 Java 源代码并且导入到 Java Source 目录。
  3. 把 Web 内容 html/jsp/resource/etc 导入到 WebSphere Studio 中。最容易的导入方法是直接从 WebSphere Application Server 的已部署的目录中导入这些文件。例如,Web 内容被部署在 deployDIR/InterimDB/webapp 。把 /webapp 中的所有内容导入到 Web Content 目录。
  4. 把项目构建路径设置为服务器项目 InterimDBEJB。在这个 Web 项目中有服务器类路径的引用。
  5. 为了添加必要的 servlet 和标记库配置,请编辑 web.xml 文件,因为 WebSphere Application Server V3.5 不使用它。以下是我们的项目中用到的简单示例:
      
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
      PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
      "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
    <web-app>
      <!-- Action Servlet Configuration -->
      <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
        <init-param>
          <param-name>application</param-name>
          <param-value>ApplicationResources</param-value>
        </init-param>
        <init-param>
          <param-name>config</param-name>
          <param-value>/WEB-INF/struts-config.xml</param-value>
        </init-param>
        <init-param>
          <param-name>debug</param-name>
          <param-value>2</param-value>
        </init-param>
        <init-param>
          <param-name>detail</param-name>
          <param-value>2</param-value>
        </init-param>
        <init-param>
          <param-name>validate</param-name>
          <param-value>true</param-value>
        <init-param>
        <load-on-startup>2</load-on-startup>
      </servlet>
      
      <servlet>
       <servlet-name>SSFStartup</servlet-name>
       <display-name>SSFStartup</display-name>
       <servlet-class>framework.startup.SSFStartup</servlet-class>
       <load-on-startup>3</load-on-startup>
      </servlet>
      <servlet>
       <servlet-name>Startup</servlet-name>
       <display-name>Startup</display-name>
       <servlet-class>net.lido.aims.interimdb.domain.values.Startup</servlet-class>
       <load-on-startup>4</load-on-startup>
      </servlet>
      <!-- Action Servlet Mapping -->
      <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.do</url-pattern>
      </servlet-mapping>
      <!-- The Welcome File List -->
      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      <welcome-file-list>
      <!-- Application Tag Library Descriptor -->
      <!-- Struts Tag Library Descriptors -->
      <taglib>
        <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
        <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
      </taglib>
      <taglib>
        <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
        <taglib-location>/WEB-INF/struts-html.tld</taglib-location>
      </taglib>
      <taglib>
        <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
        <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
      </taglib>
    </web-app>

关于 ApplicationResources.properties 文件的注意事项:您必须按照 web.xml 中操作 servlet 的定义把这个文件添加到 Java Source 中的正确的包中。在以上的示例中,它位于 Java Source 的根目录中。在编译期间,它被自动地复制到 WEB-INF\classes 目录中。

如果您把这个文件放在 WEB-INF\classes 目录中而 Java Source 中没有它的副本,那么在编译之后它将被转移。

图 6. Application.properties 文件
Application.properties 文件

WebSphere Studio V5 中 Struts 的支持

各种各样的新工具可以支持 WebSphere Studio 中 Struts 的开发。这些工具不在本文的讨论范围之内。感兴趣的读者可在 WebSphere Studio 的联机帮助中找到更多的信息。

但是,您必须解决由强大的新功能所带来的小问题。例如,您必须总是在 struts-config.xml 文件中的操作定义中给出表单 bean 的名称,有时候这并不适用。这是我们在这个项目中遇到的唯一的问题。您可能遇到的另一个问题是每当您修改 struts-config.xml 文件时 WebSphere Studio 把许多时间花在验证上。通过禁用 Struts 插件,您可以绕开验证。为此,您可以修改位于 <WebSphere Studio V5 Install>\wstools\eclipse\plugins\com.ibm.etools.struts_5.0.1 目录中的 plugin.xml 的名称。请确保不要删除 plugin.xml 文件。修改它的名称,例如 plugin_org.xml

项目实用程序 JAR

来自 IBM 的 Tim deBoer 提供了您可以下载的好插件: ZIP 创建工具,这个工具使您可在 WebSphere Studio V4 中从您的实用程序 Java 项目中自动地在 EAR 项目中创建实用程序 jar 文件。在开发期间,这个 jar 文件总是与实用程序项目同步。

WebSphere Studio 有一个类似于这个 ZIP 创建工具的功能。您可在企业应用程序的应用程序部署描述符的模块面板中使用它。它被称为项目实用程序 JAR。如果您在这里添加您的 Java 项目,那么当您导出 EAR 项目时将自动地创建 jar 文件。

区别在于您无法在 EAR 项目中看到创建的 jar 文件。您无法使 EAR 中的其它项目创建对它的引用。通过在 WebSphere Studio V4 中使用 ZIP 创建工具,项目的 jar 文件在开发期间被创建并被自动地更新。在编译时和运行时也引用这个文件。由 WebSphere Studio 中项目实用程序 JAR 文件创建的 jar 文件仅用于运行时。您需要使编译器能够打开实用程序项目。那些没有项目源文件的其他开发者怎么办?对于这个问题,我们在我们的项目中采用了另一种方式。

图 7. 项目实用程序 Jar
项目实用程序 Jar

再谈类路径

Migration Guide的第 12 章讨论了如何设置构建路径和把所有的相关的 jar 文件放在哪里。一般的规则是:使它成为局部的和内部的。如果类或 jar 仅由一个模块使用,那么把它们放在这个模块中。否则,把它们放在 EAR 项目中。

根据我们的经验,最好的解决方案是把所有的相关的类和 jar 文件都放在 EAR 项目中。它们包括我们的框架类 SSFramework.jar、第三方 jar(例如 ant.jar 和 log4j.jar)等。您的项目的构建类路径可以容易地引用它们,您不必担心运行时,因为它们已在 EAR 文件中。

图 8. Java 构建路径
Java 构建路径

图 9. Java JAR 相关性
Java JAR 相关性

结束语

本文提供了有关把 J2EE 应用程序从 VisualAge for Java 迁移到 WebSphere Studio V5 的 IDE 的建议。讨论的主题包括 EJB、Struts、JUnit、类路径和打包。通过阅读本文和来自 IBM 的各种资料,现在开发者的水平有所提高,因而能够更高效地完成他们的工作。


火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。
资源网站: UML软件工程组织