用 Apache AXIS 编写基于 JMS 的应用程序
本文将帮助开发者用 Apache AXIS 编写基于 JMS 的应用程序。在本文中,您将使用 AXIS 框架构建一个基于 JMS SOAP 的体系结构,MQSeries 作为中间件,WSDK 作为部署 SOAP 应用程序的工具。 本文假定您熟悉 AXIS 处理系统。文中示例所需的软件如下:[*]IBM WSDK(WebSphere SDK for Web Services)。
[*]带有 JMS 支持压缩包 ma88_win.zip 的 MQSeries 5.2。
[*]样本代码 ws-jms.zip。
本文假定上述软件已经安装和配置好了。(请参阅参考资料以获得下载信息) Apache AXIS 框架介绍
Axis 框架是来自 Apache Group 的、基于 java 的、最新的 SOAP 规范(SOAP 1.2)和 SOAP with Attachments 规范(来自 Apache Group )的开放源代码实现。下面是该 AXIS 框架的主要特征:
[*]灵活的消息传递框架:AXIS 框架提供了灵活的消息传递框架,这个消息传递框架包括处理程序,链,序列化程序和反序列化程序。处理程序是一个处理请求、响应和故障流的对象。处理程序可被组合在一起成为链,而且可以使用一个灵活的部署描述符来配置这些处理程序的顺序。
[*]灵活的传输框架:Axis 提供了一个传输框架,这个传输框架可以帮助您创建自己的可插式传输发送器和传输侦听器。在本文中,您将构建自已的 JMS 传输和侦听器来发送和接收 SOAP 消息。
[*]数据编码支持:Axis 按照 XML Schema 规范提供各种数据类型的自动序列化,并且提供一种功能程序来使用您自己定制的序列化器和反序列化器。
[*]其他特征:Axis 完全支持 WSDL 以及日志记录、出错以及故障处理机制。
AXIS 体系结构概览
AXIS 体系结构的核心组件包括:
[*]AxisEngine:它起到了类似于其他组件的中央控制器的作用。它既可以在服务器端实现,也可以在客户机端实现。
[*]MessageContext:MessageContext 类是 SOAP 请求和响应的一个包装器。它为 AXIS 消息处理系统中的其他组件提供一条消息的上下文信息。
[*]处理程序和链: 处理程序是 AXIS 系统中的基本构件。一个处理程序带有一个 MessageContext,它执行操作并且返回到进行调用的代码。链是一个特殊的处理程序,它代表了其他处理程序的顺序。
[*]传输:传送进入 AXIS 引擎的消息和到客户机的响应消息。
[*]序列化器和反序列化器:它们是将数据从本机格式转换到 XML 以及将数据从 XML 再转换回本机格式所必需的。
[*]部署文件:AXIS 系统定义了一个基于 XML 的部署描述符 - 被称作 Web 服务部署描述符(Web Service Deployment Descriptor(WSDD)),这个部署描述符定义了 AXIS 系统在服务器端和在客户机端的配置。
设计 JMS SOAP 框架
JMS 定义了一种标准的方式供 Java 应用程序通过面向消息的中间件(Message Oriented Middleware(MOM))来创建和交换信息。您将用 MQSeries 作为 MOM。您将开发一个基于点到点(Point to Point(P2P))消息的系统,该系统使消息能够通过一个名为队列的通道在生产者和消费者之间进行交换。队列是这样一个目的地:生产者向它发送消息, 接收者从中取消息。每条消息仅被此模型中的一个接收方使用。
图 1 用 AXIS 描绘了 JMS SOAP 框架系统的体系结构概况。
图 1. JMS SOAP 体系结构
http://www-900.ibm.com/developerWorks/cn/webservices/ws-jms/jms-arch.jpg
AXIS 的一个显著特征是它使框架既能够在服务器端配置,也能够在客户机端配置以进行基于客户机消息处理。在这个例子中,您将使用基于 AXIS 的部署描述符在服务器端和客户机端配置 AXIS 框架。服务器端部署描述符将告诉服务器端的 AXIS 服务器要调用哪个 Web 服务。客户机端部署描述符将告诉客户机端的 AXIS 服务器要使用哪个传输处理程序来传输 SOAP 消息。 您将构建自已的 JMS 传输处理程序来传输 SOAP 消息。
上面的框架可以使用下面的步骤来演示:
[*]MSSOAP 客户机构造 org.apache.axis.client.Call 对象并设置位置、调用参数、服务、方法名称以及传输机制(即 JMSMqseries Transport)。然后,它调用 AXISClient。
[*]AXISClient 检查部署描述符(client-deploy.wsdd)中的传输对象,并装入为 JMSMqseries Transport 部署的传输处理程序(JMSSOAPHandler)。
[*]JMSSOAPHandler 接收包装在 MessageContext 对象中的 SOAP 请求,并把该 SOAP 请求放入 RequestQueue。
[*]当消息到达 RequestQueue 时,JMSSOAPListener 事件 onMessage() 被触发,onMessage() 接收 SOAP 请求并创建一个 AXISServer 引擎的实例。
[*]AXISServer 引擎接着调用相应的 Web 服务,并把请求参数传给它。
[*]接着,AXISServer 接收来自 Web 服务的响应并把 SOAP 响应放入 ResponseQueue。
[*]SOAP 消息放进 ResponseQueue 后,通知 JMSSOAPHandler。然后,JMSSOAPHandler 接收来自于 tResponseQueue 的 SOAP 消息并把控制权返还给 JMSSOAP 客户机。
[*]接着,JMSSOAP 客户机接收 SOAP 消息,对结果进行解压缩并在控制台上显示。
构建应用程序框架
运行应用程序之前,您需要安装 Queue Manager 和 Queues、绑定到 JNDI 以进行 JMS 通信、在 WSDK 中安装 AXIS 框架并部署服务器端和客户机端基于 AXIS 的描述符。请在参考资料部分下载包含用于建立 MQSeries 队列的批处理文件以及应用程序的源代码和部署描述符的 zip 文件。请将 zip 文件解压缩到 C: 驱动器。
建立队列
[*]运行 C:\mqjms\batch 文件夹中 mqsetup.bat 文件。这个批处理文件要求在您的环境路径变量中设置 MQSeries 安装程序中的 bin 文件夹(如 C:\mqseries\bin)。运行完这个批处理文件之后,您将看到消息“All valid MQSC commands were processed”。用 Start -> Programs -> IBM MQSeries -> MQSeriesExplorer 打开 MQSeries 浏览器以确保已经创建了队列管理器和队列。图 2 显示了 QueueManager“MQJMS.QManager”已被创建并正在运行。 图 2. MQSeries 的 Queue 管理器配置
http://www-900.ibm.com/developerWorks/cn/webservices/ws-jms/mq.jpg
[*]点击左窗格中“MQJMS.QManager”下面的“Queues”文件夹。您应该会看到已创建两个队列“RequestQueue”和“ResponseQueue”,如图 3 所示。
图3. MQSeries 的请求/响应队列配置
http://www-900.ibm.com/developerWorks/cn/webservices/ws-jms/mqque.jpg
这就完成了队列的建立。 建立 JMS 和 JNDI 管理
在您的应用程序中,JNDI 访问利用基于文件的 FSContext 版本(可以从 http://java.sun.com/products/jndi/index.html 获得)。FSContext.jar 文件也包含在 MQSeries JMS Support 压缩包 ma88_win.zip 中。把 ma88_win.zip 解压到一个文件夹(如 C:\ProgramFiles\MQSeries\Java),并将文件夹 C:\ProgramFiles\MQSeries\Java\lib 和 C:\ProgramFiles\MQSeries\Java\bin 添加到系统中的 PATH 环境变量中。还要将 C:\ProgramFiles\MQSeries\Java\lib 文件夹中的所有 jar 文件添加到系统的 CLASSPATH 环境变量中。您还可以运行 C:\mqjms\batch 文件夹下的 classpath.cmd 批处理文件,该批处理文件设置了必要的路径变量和 CLASSPATH 变量。只需修改 classpath.cmd 文件中的 MQ_JAVA_INSTALL_PATH 变量使其指向您的 MQSeries JMS 安装目录。
修改 MQSeries JMS 管理使用的 C:\ProgramFiles\MQSeries\Java\bin 中的 JMSAdmin.config 配置文件,以指出应用程序将要使用的 JNDI 实现的上下文工厂和 Web 地址。取消对下面这行代码的注释:
INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory
并取消对其余两个 INITIAL_CONTEXT_FACTORY 变量的注释。还要取消对下面这行代码注释:
PROVIDER_URL=file:/C:/JNDI-Directory
并取消对其余两个 PROVIDER_URL 变量的注释。
C:\mqjms\batch 文件夹中提供了一个样本配置文件以供参考。
在 C: 驱动器上建一个名为 JNDI-Directory 的目录以存储 JNDI 对象。转到 C:\ProgramFiles\MQSeries\Java\bin 目录并运行 JMSAdmin 批处理文件,您应该会看到 InitCtx 变量。
依次输入下列内容:
def qcf(MQ_JMS_MANAGER) qmgr(MQJMS.QManager)
按 Enter
def q(JMS_RequestQueue) qmgr(MQJMS.QManager) queue(RequestQueue)
按 Enter
def q(JMS_ResponseQueue) qmgr(MQJMS.QManager) queue(ResponseQueue)
按 Enter
现在,您已经将队列绑定到 JNDI 对象了。
在 WSDK 中安装 AXIS 框架
WSDK 附带了 AXIS 的测试版本。所以,您只需在 WSDK 上安装并部署 AXIS 框架即可。为此,请使用下列步骤:
[*]axis 目录包括了在 WSDK 中部署 AXIS 框架所需的结构。它在 WEB-INF 目录下包含了 web.xml 文件,该文件包含了一个用于注册 org.apache.axis.transport.http.AxisServlet servlet 的映射。还要把必需的 AXIS 框架类从 C:\wsdk\lib 拷贝到 C:\wsdk\services\applications\axis\WEB-INF\lib 文件夹。
[*]C:\wsdk\services\applications\axis\deployment 目录下的部署文件夹包含 PriceServiceDeploy.wsdd 文件,该文件是用于部署名为“PriceService”的 Web 服务的部署描述符。
接下来,您继续部署 AXIS 框架。请使用下列步骤:
[*]打开窗口命令提示符,转到 C:\wsdk\bin 目录。设置路径变量使之包括 C:\wsdk\bin 和 C:\wsdk\sdk\bin,并运行 wsdkconfig 命令。wsdkconfig 工具启动。单击 Next 按钮以前进到配置服务部分,并选择 application\axis 服务,如图 4 所示。单击 Next 两次,最后单击 Finish 以部署 AXIS 框架。您应该会接收到消息“The application server has been configured for WSDK”。 图 4. 在 WSDK 上部署 AXIS 框架
http://www-900.ibm.com/developerWorks/cn/webservices/ws-jms/wsdk.jpg
接着,让我们来继续部署 Web 服务。 部署 Price Web 服务
为了部署 Price Web 服务,请遵循下列步骤:
[*]转到 C:\mqjms\batch 目录并执行 classpath.cmd 批处理文件,以便将必需的类放入 CLASSPATH 环境。转到 C:\mqjms 目录,并通过输入 javac naveen\jms\*.java 来编译您的源文件。
[*]通过导航到 Start -> Programs -> IBM WebSphere SDK for Web Services -> Start App Server 来启动与 WebSphere Studio Application Developer 相关联的 WebSphere Application 服务器。
[*]转到 C:\wsdk\bin 目录并执行下面的命令以部署 Price Web 服务: axisDeploy c:\mqjms\naveen\jms\PriceServiceDeploy.wsdd -l http://localhost:80/axis/services/AdminService
其中 C:\mqjms\naveen\jms\PriceServiceDeploy.wsdd 是部署文件的位置,http://localhost:80/axis/services/AdminService 是部署 AXIS 框架的 URL。
执行完上面的命令后,您应该会接收到消息“- Processing file c:\mqjms\naveen\jms\PriceServiceDeploy.wsdd”
处理完成
[*]现在您需要在客户机端配置 JMSMqseries Transport。为此,请执行下面的命令: java org.apache.axis.utils.Admin client c:\mqjms\naveen\jms\jmsclient-deploy.wsdd
客户机用来指明部署信息的选项仅供客户端使用。现在您已经完成了体系结构的部署。
分析应用程序代码
分析 JMSSOAPClient.java 文件
从 JMSSOAPClient.java 文件的 30-44 行开始。
清单 1. JMSSOAPClient.java
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new java.net.URL(endpointURL));
QName qname= new QName("PriceService", methodName);
call.setOperationName(qname);
call.addParameter("price", XMLType.XSD_STRING, ParameterMode.PARAM_MODE_IN);
call.setTransport(new JMSMqseriesTransport());
call.setReturnType(XMLType.XSD_FLOAT);
在清单 1 中,您通过创建 org.apache.axis.client 开始分析。 调用对象,然后设置 web 服务的位置;调用它的参数、服务、方法名称以及传输机制(JMSMqseries Transport)。
51 行:Float price = (Float) call.invoke(params);。
接下来您可以调用 Price Web 服务。因为您定义了自己的定制 Transport 机制,所以 AXISClient 会检查部署描述符(client-deploy.wsdd)中的传输对象并装入为“JMSMqseriesTransport”部署的传输处理程序 (JMSSOAPSender)。这样,JMSSOAPSender 被调用并获得控制权。
现在接着分析 JMSSOAPSender.java.
分析 JMSSOAPSender.java 文件
24 行:public class JMSSOAPSender extends BasicHandler。
JMSSOAPSender 扩展 org.apache.axis.handlers.BasicHandler,从而将自己归为 AXIS 系统的一个处理程序。
在构造函数中,创建 Initial Context 工厂的上下文来查询 Request Queue。
73 行:public void invoke(MessageContext msgContext)。
Axis 引擎调用这个方法。在该方法中,您通过调用所提供的助手方法从 SOAP 信封中检索 SOAP 消息,如清单 2 所示。
清单 2. JMSSOAPSender.java
// Get a string representation of SOAP Envelope
SOAPEnvelope soapEnvelope = axisMsg.getSOAPEnvelope();
Element envElement = soapEnvelope.getAsDOM();
String strSOAPBody = XMLUtils.ElementToString(envElement);
接着,您通过调用 91 行的 sender.send(jmsMsg) 将 SOAP 消息发送到 Request Queue 中,然后等待直到回复消息到达位于第 96 行的 TextMessage replyMsg = (TextMessage) receiver.receive() 的 Response Queue 为止。
在 103 行,您把响应包装到 org.apache.axis.Message 对象中,并通过调用 setResponseMessage 方法设置 msgContext 中的响应对象,这样响应对于 JMSSOAPclient 来说是可用的,如下所示:
org.apache.axis.Message responseMsg = new org.apache.axis.Message(replyMsg.getText());
msgContext.setResponseMessage(responseMsg);
当消息到达 Request Queue 时,JMSSOAPListener.java onMessage (javax.jms.Message msg) 就被执行,这是因为它一直在异步侦听 Request Queue。
现在来继续分析 JMSSOAPListener.java 代码。
分析 JMSSOAPListener.java 文件
在第 79 行,您创建一个 AxisEngine 实例和一个 MessageContext 实例,并与引擎相关联,如下所示:
AxisEngine engine = getAxisEngine();
msgContext = new MessageContext(engine);
第 53 行的 getAxisEngine() 方法负责从配置文件中创建 AxisServer 配置,它位于:
"C:\WSDK\WebSphere\installedApps\wsdk.ear\axis.war\WEB-INF\server-config.wsdd".
第 101 到 107 行从 MessageContext 获得响应,并使用分析 JMSSOAPSender 文件中讨论过的助手方法把它转换成字符串表示。
第 119 行,您通过调用
sender.send(jmsResponseMsg); 向 Response Queue 发送一个响应。这就导致 JMSSOAPSender 执行, JMSSOAPSender 在等待消息到达 Response Queue 时是暂挂的。
JMSSOAPSender 接收消息并把响应传送回给 JMSSOAPclient,JMSSOAPclient 在控制台上显示响应。
下面让我们来继续看运行的代码。
运行应用程序
为运行应用程序,请执行下面步骤序列:
[*]通过转到 C:\mqjms 目录并输入:
java naveen.jms.JMSSOAPListener 来启动 JMSSOAPListener。 您应该会接收到消息“JMSSOAPListener readyto receive messages”。
[*]接着,打开一个新的命令窗口并转到 C:\mqjms\batch 目录,运行 classpath.cmd 变量来初始化 CLASSPATH 变量。然后通过输入下面的命令来运行 JMSSOAPClient:
java naveen.jms.JMSSOAPClient。 您应该会收到下列输出片段消息:
JMSSOAP Sender called
JMS-SOAP Request: < SOAP-ENV ....>
Sending JMS-SOAP Request to Request Queue
Sent JMS-SOAP Request to Response Queue
Waiting to Receive JMS-SOAP Response from Response Queue
Received JMS-SOAP Response from Response Queue
JMS-SOAP Response:
End of JMSSOAPSender
The Price is $1500.5
JMSSOAPClient 已经成功地用 JMS 作为传输媒介来发送和接收 SOAP 信息了。
[*]在 JMSSOAPListener 控制台上,您可以看到,当新的 SOAP 请求到达 Request Queue 时,onMessage() 事件被激活。MSSOAPListener 创建了一个 AXISServer 实例,并把 SOAP 请求传递给它,然后接收返回的响应,并把它放在 Response Queue 上。您可以在控制台上接收到下面的输出消息:
onMessage event Executed
Getting response message from Price WebService
Sending JMS-SOAP Response to the Response Queue
Waiting for Next JMS-SOAP Requests
您已经成功地使用 JMS 协议和 SOAP 请求通信了。这种体系结构可以应用于 SOAP 消息的同步处理和异步处理
页:
[1]