内容


将 Java Swing 应用程序连接到 Geronimo 服务器

创建可以与 Geronimo EJB 应用程序对话的独立客户端

Comments

简介

本文将展示如何开发可以与运行在 Geronimo 应用服务器内部的 EJB 应用程序通信的独立(胖)客户端。基于我的前两篇文章 ——“将数据库连接到 Geronimo 应用服务器的三种方法”(developerWorks,2005 年 6 月)和“利用 Geronimo 深入 EJB Web 应用程序”(developerWorks,2005 年 7 月)—— 本文向您展示一个连接到使用 Geronimo EJB 应用程序构建的小型电话簿数据库的 Swing 客户端。您将阅读简要的设计说明,然后阅读有关运行该应用程序所需的客户端库的信息。接下来我将介绍联系服务器并对服务器上远程无状态会话 bean 执行操作的方法。最后,您将学习如何开发、编译并运行客户端应用程序,以及如何配置服务器以允许来自网络中特定客户端的安全访问。

要最有效地利用本文,您需要熟悉用于构建 Java 桌面应用程序的 Java Swing API 以及 Apache Maven 构建系统(参阅 参考资料 以链接到 Maven Web 站点)。

设计概述

首先简要介绍一下示例应用程序设计 —— 一个描述电话簿客户端应用程序的统一建模语言 (Unified Modeling Language, UML) 部署图 —— 如 图 1 所示。客户端应用程序通过其 EJB 端口连接到 Geronimo,并与 PhoneBook Session EJB 对话以通过 PhoneBook Entry Container-Managed Persistence (CMP) 操作数据库中的数据。

图 1. 电话簿客户端部署图
电话簿客户端部署图
电话簿客户端部署图

Geronimo 的默认发行版对 EJB 端口有限制。仅当客户端应用程序运行在同一机器上并且通过环回地址(localhost 或 127.0.0.1) 连接时才能连接到该端口。本文稍后的 配置 Geronimo 的 EJB 端口 一节提供了有关如何让其他机器上的客户端访问服务器的详细信息。

用于连接到 Geronimo 的客户端库

要让客户端应用程序能够连接到 Geronimo 的 EJB 端口并与 EJB 层通信,客户端类路径中必须要有下列 Java 库:

  • geronimo-spec-j2ee-1.4-rc4.jar
  • geronimo-kernel-1.0-SNAPSHOT.jar
  • geronimo-j2ee-1.0-SNAPSHOT.jar
  • geronimo-security-1.0-SNAPSHOT.jar
  • cglib-nodep-2.1.jar
  • openejb-core-2.0-SNAPSHOT.jar

从源代码编译 Geronimo 时,当您使用 Maven 构建脚本来编译电话簿客户端应用程序时,这些库被放置到本地 Maven 资源库中且可供访问。您可以在 project.xml 文件的依赖关系部分中查看所有这些库位于 Maven 资源库的哪个位置。

其中一些库在客户端与服务器的通信中起着非常重要的作用。Geronimo 使用 CGLib 库来执行动态代理生成。这使得服务器动态生成远程调用服务器端组件的代码。如果在调试器中检查客户端上 InitialContext 对象的 lookup() 方法返回的一个对象,可以看到动态生成的对象的类名包括 CGLib。geronimo-spec-j2ee.jar 文件包含所有的 Sun Java 2 Platform, Enterprise Edition (J2EE) 接口和类。没有该文件,客户端将无法理解任何动态代理实例。openejb-core.jar 文件是与服务器的 EJB 端口进行对话所必需的。用于在 Geronimo 服务器中执行远程目录查询的 Java Naming and Directory Interface (JNDI) 类就在该 .jar 文件中。最后的三个 .jar 文件提供了其他支持类,比如与 Geronimo 对话的安全主体。

执行远程会话本地查询

客户端通信部分的实现十分简单。将客户端连接到服务器时,Geronimo 与其他任何 J2EE 服务器没有任何不同,遵守健全的通过 JNDI 查询和远程方法调用 (RMI) 进行的通信标准。JNDI 查询是获得对远程对象的引用的标准访问。要通过 JNDI 进行连接,必须使用大量特定于 Geronimo 的属性来创建 InitialContext 实例,该实例用于执行查询。 清单 1 展示了有关如何创建会话的示例。

清单 1. 创建到 Geronimo 托管会话 bean 的远程会话
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
public void Connect() {
      String hostName = getHostName();
      String port = getPort();
      Properties props = new Properties();
      props.setProperty("java.naming.factory.initial",
                  "org.openejb.client.RemoteInitialContextFactory");
      props.setProperty("java.naming.provider.url", hostName+":"+port);
      props.setProperty("java.naming.security.principal", "username");
      props.setProperty("java.naming.security.credentials", "passwd");
      Context ic;
      try {
            ic = new InitialContext(props);
            PhoneBookSessionHome sessionHome = (PhoneBookSessionHome)
                  PortableRemoteObject.narrow(
                  ic.lookup(PhoneBookSessionHome.JNDI_NAME),
                  PhoneBookSessionHome.class);
            phoneBookSession = sessionHome.create();
      } catch (Throwable ex) {
            ex.printStackTrace();
      } finally {
            if (ic != null) {
                  ic.close();
            }
      }
}

清单 1 所示,创建了 Properties 对象并设置了四个属性。第一个并且是最重要的属性是 java.naming.factory.initial 属性,它必须设置为 org.openejb.client.RemoteInitialContextFactory。其他属性指定提供者 URL 以及安全主体和凭证。提供者 URL 是用冒号隔开的主机名和端口。

前已提及,EJB 端口当前只接受从客户端连接到 127.0.0.1 或 localhost 的连接。默认端口是 4201。尽管如此,主机名和端口都可以进行配置。有关详细信息,请参阅 配置 Geronimo 的 EJB 端口 一节。

创建好属性之后,就可以创建并使用 InitialContext 实例了。通过将属性传递给构造函数完成这一操作。创建好实例之后,可以执行查询。清单 1 包括一行复杂的代码,该行执行查询并对结果执行 PortableRemoteObject.narrow()。对于向用户隐藏有关协议传输 —— RMI 或者可能是 Internet Inter-ORB Protocol (IIOP)—— 的详细信息,这是必需的。完成之后,远程会话就可供使用了。在 清单 1 中,该行只创建了新 PhoneBookSession,并将其存储在一个字段中以供将来使用。

具有对远程会话的引用之后,该引用可用于所有操纵电话簿数据库信息的操作。现在只需要一个应用程序来练习该远程会话。

客户端的设计和开发

现在我们来深入研究一个小 Swing 应用程序的设计和开发,这个小应用程序用来浏览、创建、删除和修改电话簿数据库条目。我尽量将 Swing 行话减到最少,以防您比较熟悉的是另一种 GUI 技术,比如 Standard Widget Toolkit (SWT)。事实上,如果需要的话,应用程序架构已经使得将显示从应用程序内部逻辑分离出来并将其连接到另一种 GUI 技术变得非常容易。

应用程序架构如 图 2 所示,这是一个详细显示应用程序静态结构的 UML 类图。

图 2. 客户端应用程序的 UML 类图
客户端应用程序的 UML 类图
客户端应用程序的 UML 类图

图 2 中带绿色阴影的类是主要的应用程序类。Main 类是包含菜单和拆分窗格(其左侧是 PhoneNumberListPanel,右侧是 PhoneBookEditorPanel)的框架。该菜单还允许用户设置连接到哪个服务器的首选项,连接到服务器,并退出程序。Application 类是一个单身类(singleton class),用作应用程序的所有操作的控制器。它是惟一一个执行 EJB 操作的类,并保存对 PhoneBookSession 无状态会话 bean 的引用。

橙色的两个接口定义系统中的主要事件。每当 Application 决定电话号码列表需要更新时,就会激活 DataChangeEventPhoneNumberListModel 注册该事件。因为它是 PhoneNumberListPanel 中的主要数据模型列表视图,所以列表是通过模型更改来更新的。这与 Swing 应用程序的设计方法一致。

PhoneNumberListPanelPhoneBookEditorPanel 类都实现 PhoneBookSelectionListener 接口并注册来自 Application 单身类的事件。当它们收到事件时,它们相应地更新当前的选择。如果是 PhoneBookEditorPanel,当前选择导致 Name 和 Number 字段由来自当前选择的电话簿条目中的数据填充。

如果希望节省编写用户接口代码的时间,通常可以在 Internet 上找到高质量的免费工具。优秀的工具有 JGoodies Forms 1.0.5 和 FormLayoutMaker,FormLayoutMaker 是一个用于可视化创建窗体的小工具(参阅 参考资料 以获得到这些工具的链接)。FormLayoutMaker 工具生成代表 JGoodies 窗体布局约束的 XML 文件。这些工具帮助我快速创建了 Phone Number 编辑面板和 Preferences 面板的窗体。

构建应用程序

编译应用程序有两种方法。我使用 Eclipse Visual Editor (VE) 插件 1.2 版本在 Eclipse 中开发了该应用程序。它生成应用程序的大部分代码框架,但它是以一种非入侵的方式完成的(没有代码标记和不可访问的代码块),所以如果没有安装 VE 的话也应该没有问题。可以只加载项目并尝试运行它。

您可能需要设置 MAVEN_REPO 构建变量以指向本地 Maven 资源库。还需要构建与本文一起提供的源代码中包括的 Geronimo 和 PhoneBook 服务器应用程序(参阅 下载)。这是因为,要编译客户端应用程序,包含服务器应用程序中 EJB 接口的 .jar 文件必须发布到本地 Maven 资源库中。PhoneBook 的 Maven 构建脚本通过下列 Maven 构建脚本段完成该操作:

清单 2. Maven 构建脚本段
<goal name="client" prereqs="java:compile">
      <ant:jar destfile="target/${pom.artifactId}-client.jar">
            <fileset dir="target/classes">
                  <include name="**/*.class"/>
            </fileset>
      </ant:jar>
      <artifact:install artifact="target/${pom.artifactId}-client.jar"
            type="jar" project="${pom}"/>
</goal>

用于构建应用程序的第二种方法就是使用 Maven。在 PhoneBook 目录中解压文件并运行 maven 命令。然后在 PhoneBookClient 目录中进行相同操作。如果一切顺利,就已经在目标子目录中创建了 UberJar —— 一个包含运行客户端所需的所有内容的 JAR 文件。

两种构建方法运行得同样好。使用 Maven 方法的优点是如果您尚未下载依赖关系,则它会自动从 ibiblio Web 站点(参阅 参考资料)上的远程 Maven 资源库中下载这些依赖关系。所以如果 Eclipse 中的依赖关系有问题,就在项目上至少运行一次 Maven 来校正缺少的库。

运行应用程序

确保 PhoneBook 服务器应用程序部署到 Geronimo 服务器中且正在运行。然后键入下列命令:

java -jar phonebook-client-uber.jar

将会看到应用程序弹出,如 图 3 所示。

图 3. Geronimo 电话簿客户端应用程序
Geronimo 电话簿客户端应用程序
Geronimo 电话簿客户端应用程序

首先,从 File 菜单中选择 Connect。如果是连接到 localhost:4201 端口,则应该获得一个连接;否则,控制台窗口将会显示错误消息。可以通过选择 Edit > Preferences、更改信息并尝试重新连接来更改连接的服务器和端口。一旦连接上之后,可以通过在电话号码编辑器中键入姓名和号码并单击 Save 来创建新记录。该记录将显示在姓名列表中。通过选择条目并单击 Delete 来删除条目。通过选择条目、进行修改并单击 Save 来更改条目。

配置 Geronimo 的 EJB 端口

当前,配置 Geronimo 的 EJB 端口的方法需要编辑 XML 文件,然后重新编译 Geronimo。Tom McQueeney 的大型 Geronimo Live blog 上的一篇短文清楚介绍了如何使用 openejb\modules\assembly\src\plan\j2ee-server-plan.xml 文件更改 Geronimo Jetty 监听端口的详细信息(参阅 参考资料 以链接到该 blog)。同一文件还包含 EJB 端口的配置信息(参阅 清单 3)。

清单 3. j2ee-server-plan.xml 文件中的代码段
<gbean name="EJBNetworkService" 
class="org.openejb.server.StandardServiceStackGBean">
        <attribute name="name">EJB</attribute>
        <attribute name="port">4201</attribute>
        <attribute name="address">127.0.0.1</attribute>
        <attribute name="allowHosts">127.0.0.1</attribute>
        <attribute name="logOnSuccess">HOST,NAME,THREADID,USERID</attribute>
        <attribute name="logOnFailure">HOST,NAME</attribute>
        <reference name="Executor"><name>DefaultThreadPool</name></reference>
        <reference name="Server">
            <gbean-name>openejb.server:name=EJBServer,*</gbean-name>
        </reference>
</gbean>

您需要编辑 j2ee-server-plan.xml 文件并更改 allowHosts 属性。Geronimo 支持许多不同类型的地址。必须用下列模式之一输入逗号分隔的地址列表:

  • 最后一格为 0 的 IP 地址。例如,192.168.10.0 允许 192.168.10 网络上的任何机器与服务器通信。
  • 任何完全指定的 IP 地址。
  • 分解的 IP 地址。这是一种特殊模式,允许指定地址的网络部分和以大括号扩住的主机地址列表。例如,192.168.10.{5,6,7} 允许以下三个机器访问服务器:192.168.10.5、192.168.10.6 和 192.168.10.7。
  • 网络掩码 IP 地址。这是网络管理员熟悉的一种地址。基于精确的位模式匹配规则(超出本文范围),IP 地址与网络掩码相匹配。例如,192.168.255.255 允许 192.168.* 网络中的所有地址访问服务器。
  • 准确的 IPv6 地址。当将来的 IP 网络到来时,Geronimo 将准备好服务,允许列出特定的 IP 地址。
  • 网络掩码 IPv6 地址。

有关服务器接受的特定模式的详细信息,请咨询源代码文件 —— ServiceAccessController.java —— 位于来源的 openejb\modules\core\src\java\org\openejb\server 目录中。在此将会找到与支持的每个地址类型相匹配的明确的正则表达式。

对 j2ee-server-plan.xml 文件进行修改之后,重新编译并更新服务器部署,您将具有一个专门满足您需要的服务器。(如果只想查看针对同一机器上的服务器运行的客户端,则无需这样做。默认情况下,Geronimo 被配置来完成这些操作。)

结束语

本文提供了一个构建独立(胖)客户端的具体示例,该客户端可以与运行在 Geronimo 应用服务器内部的 EJB 应用程序进行对话。Geronimo 团队已经认真实现了健全的标准,推广用简单的 JNDI 查询方法获得与无状态会话 bean 的远程连接。如果只想让简单的应用程序运行,那么这是一个好消息,因为它只需要您编写少量代码。

按照我所介绍的模式,您能够将许多比较大的数据库连接到与 Geronimo 服务器位于同一机器上的客户端应用程序。使用本文提供的指示,您还能够配置 Geronimo 服务器以允许从连接到您的网络或 Internet 上的其他机器访问服务器 EJB 端口。不妨尝试一下。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source, Java technology
ArticleID=93051
ArticleTitle=将 Java Swing 应用程序连接到 Geronimo 服务器
publish-date=08242005