您的位置:首页 > 运维架构 > 网站架构

利用 J2EE 连接器架构和 SOAP 构建“Web服务就绪”的企业级应用

2008-05-01 05:57 1031 查看
利用 J2EE 连接器架构SOAP 构建Web服务就绪”的企业级应用,第二部分
作者:Venkat Amirisetty和 Marina Sum
2003年3月26日

Sun Java System Connector Builder 2.0的“什么”和“为什么”。
Sun Java System Connector Builder生成的、Web服务就绪的连接器。
生成的SOAP服务的其他特性。
结论。
关于作者。

在2002年12月,我们发布了这一系列文章的第一部分并受到了读者的大量有价值的评价。在写这一系列文章的第二部分时,我们在以下方面结合了读者的建议:
如何使用Sun Java System Connector Builder来实现紧耦合的交互和松耦合的交互。
如何构建连接器,使它支持带附件的简单对象访问协议(Simple Object Access Protocol,SOAP)和安全超文本传输协议(Hypertext Transmission Protocol, Secure,HTTPS)上的SOAP
注意: 本文章中的源代码是从与Sun Java System Connector Builder一起发布的Customer Order Tracking System (COTS)样例资源适配器中抽取出来的。要采用样例代码,请下载Sun Java System Connector Builder,并部署COTS资源适配器。或者只把样例当作一般的指南,并在开发你自己的资源适配器时将样例的方法作为参考使用。
Sun Java System Connector Builder 2.0的“什么”和“为什么”
Sun Java System Connector Builder 2.0由一套工具、组件和库组成,利用这些东西可以构建资源适配器,使之遵从用于企业信息系统(Enterprise Information Systems,EIS)和资产应用的Java 2 Platform, Enterprise Edition (J2EE) Connector Architecture 1.0。你可以利用J2EE Connector 1.0 Specification 中描述的公共客户接口(Common Client Interface,CCI)API来访问资源适配器。可选地,你也可以添加SOAP服务层到资源适配器和为集成企业应用构建Web服务解决方案。
资源适配器利用J2EE连接器架构服务提供者接口(Service Provider Interface,SPI)实现的优势,该实现提供了连接管理、事务控制和身份验证。因此,有了Sun ONE Connector Builder,你就可以利用你在现有定制的或单独的应用上的投资,并可以将它们与其他J2EE Web服务应用相集成。
请参见关于如何利用Sun Java System Connector Builder来为EIS构建资源适配器的概述。
Sun Java System Connector Builder生成的、Web服务就绪的连接器
Sun Java System Connector Builder 2.0生成以下东西,以允许连接器具有SOAP服务:
SOAP服务端点:Java交互对象(Java Interaction Objects,JIO)。
服务端点的部署描述符。
Java对象到XML(或者反之)的串行化器和反串行化器。
SOAP服务客户端。
利用Ant构建脚本,来打包SOAP服务、部署描述符和库户端。
另外,Sun Java System Connector Builder 2.0还包含一个用于部署SOAP服务的工具。
注意Sun Java System Connector Builder 2.0生成SOAP服务,你可以将这些服务部署到Apache SOAP 2.2中。要准备基于JAX-RPC(用于基于XML的远程过程调用的Java API,Java API for XML-based remote procedure call)的SOAP服务,请使用Sun Java System Studio 4中的JAX-RPC支持。
下图演示了组件和交互流程。

图1
SOAP服务端点:Java交互对象(JIO)
在该场景中,你将在Web服务器中部署一个资源适配器,并从远程客户端与该资源适配器交互。为了能够远程交互,该资源适配器必须是用servlet包装的或者允许远程方法调用(Remote Method Invocation,RMI)。要了解详细情况,请参见这一系列文章的第一部分。
注意由于CCI的广泛特性和潜在的串行化问题,允许CCI的RMI将是代价昂贵的。如果你在本地客户端库上面创建资源适配器,那么问题将会恶化。这里有一个建议:利用servlets包装资源适配器的交互规范,servlets接受XML作为输入或者返回XML作为输出。
SOAP提供直观的标准编码。因为CCI位于太低的层次,很难通过SOAP被暴露,所以用JIO包装它。JIO是根据资源适配器的交互规范生成的Java对象。JIO接受必需的变量,以利用CCI作为输入,并返回结果作为输出。在这种情况下,你利用Sun ONE Connector Builder生成JIO作为资源适配器的一部分。
JIO包含两组过载方法:
xecute – 该方法的变体充当CCI交互规范和输入输出记录。因此,这些变体接受输入记录并返回输出记录。这些变体以下列各项作为输入参数:
只有输入记录。
输入记录和ConnectionFactory Java命名和目录接口(Java Naming and Directory Interface,JNDI)查找名称。
输入记录、JNDI查找名称和JNDIEnv上下文。
所有这三个变体都返回输出记录。
xecuteAPI – 三个方法直接充当EIS API的输入输出参数。因此,它们接受所有单独的API输入参数,并返回API的返回参数。这些变体以下列各项作为输入参数:
只有API的输入参数。
API的输入参数和ConnectionFactory JNDI查找名称。
API的输入参数、ConnectionFactory JNDI查找名称和JNDIEnv上下文。
所有三个变体都返回API的返回参数。
请参见生成的JID的样例代码,以了解与Sun ONE Connector Builder一起发布的COTS样例资源适配器的GetCustomer交互规范。
服务端点的部署描述符
需要一个部署描述符以在SOAP运行时环境中注册一个服务。描述符必须遵从运行时所需要的格式。Apache SOAP运行时要求是:
服务惟一的统一资源名称(Uniform Resource Name,URN)——服务的惟一名称。
提供者信息——提供者类型、范围、类名称、方法名称等。
类型映射——编码样式、全限定的类名称,以及对于参与输入变量和输出变量的对象图的每种数据类型的Java对象到XML(及反之)串行化器和反串行化器类名称。
每个部署描述符列出它相应的JIO类作为提供者类,并将JIO的execute和executeAPI方法暴露为SOAP可访问的。另外:
execute充当CCI输入输出记录和交互规范。因此,如果使用execute,你必须在SOAP请求中构建输入记录。
executeAPI充当API方法参数。因此,如果使用executeAPI,你可以在SOAP请求中发送API方法参数。部署描述符也为出现在输入输出参数图中的每个惟一类列出类型映射,以及它的Java对象到XML(及反之)类名称(串行化器和反串行化器)的详细信息。
请参见生成的部署描述符的样例代码,以了解COTSAPIGetCustomer JIO。
Java对象到XML(及反之)串行化器和反串行化器
依赖于你为现有输入输出参数的类型指定的要求,Sun Java System Connector Builder还创建所需的Java对象到XML(或反之)模板串行化器或反串行化器。
对于每种输入输出参数类型,Sun Java System Connector Builder提示你指定串行化器或反串行化器类信息。对于每种数据类型,可以指定以下各项:
是否是JavaBeans组件(bean)。
Sun Java System Connector Builder是否必须生成一个模板类型映射类或者数据类型的串行化器或反串行化器类的名称。
将要生成的模板类型映射类包含实现所需要的marshall和unmarshall方法。因为Apache SOAP运行时在一般安装之后提供marshalling或unmarshalling类。Sun ONE Connector Builder跳过某些类型的对象。对于集合,你必须指定参与类及其相应串行化器或反串行化器的信息。
生成的类型映射类实现Apache SOAP运行时所需的串行化器和反串行化器接口。该类包含两个方法——marshall(Java对象到XML)和unmarshall(XML到Java对象),二者都是用户自定义点。
请参见生成的模板串行化器-反串行化器的样例代码,以了解非bean数据类型。
SOAP服务客户端
通过Java交互对象(Java Interaction Objects,JIO)进行的SOAP和HTTP之间的交互以及其他生成的支持基础结构启用了资源适配器。一旦这些服务被部署在SOAP运行时中,通过发送一个SOAP XML消息到Apache SOAP提供的SOAPRPCRouter servlet,你就可以从外部客户端访问这些服务了。Apache SOAP还为客户端提供某些帮助类和框架,以构造SOAP XML消息并与Apache SOAP运行时交互。客户端stub的生成包括为每个在资源适配器上开发的基于JIO的SOAP服务创建一个Java类。
每个生成的客户端包含四个方法。main是执行的开始点,在这里,类说明它自己并调用execute方法。execute返回的Return参数在main中输出。然后是下面的步骤:
execute调用initClient方法,该方法创建一个SOAP映射注册中心并用类型映射的详细信息填充它。
execute创建一个SOAP“调用”对象,并在其上设置方法名称、编码样式和映射注册中心的值。
execute通过调用方法populateInputData在调用对象上设置参数。方法populateInputData是一个用户自定义点,它创建输入参数的一个向量、添加单独的输入参数到该向量,并返回该向量。
execute在调用对象上设置输入参数详细信息,然后利用SOAP服务的URL调用call.invoke()方法。
execute检查任何SOAP故障的响应。
在没有故障时,execute返回main的响应值。
如果有故障存在,execute输出该故障的详细信息并返回null。
请参见生成的SOAP客户端的样例代码,以了解COTSAPIGetCustomer SOAP服务。
利用Ant构建脚本,来打包SOAP服务、部署描述符和库户端
Sun Java System Connector Builder为每个资源适配器生成一个基于Ant的构建脚本(build.xml),该脚本包含你将采用来编译和打包生成的SOAP服务的目标。例如,build.xml包含目标package_SOAP,你可以利用该目标将Java交互对象(Java Interaction Objects,JIO)和资源适配器打包在一起。
为了适应部署和使用,Sun Java System Connector Builder还将部署描述符和SOAP服务客户端打包到独立的Java档案文件(JAR)中。
通过使用Sun Java System Studio IDE或者直接运行build.xml,你可以执行这些目标。
SOAP服务的部署工具
Sun Java System Connector Builder提供一个命令行工具icwsdeploy,用于将资源适配器SOAP服务部署或解除部署到目标服务器环境。icwsdeploy接受利用构建脚本创建的部署描述符包并因而部署SOAP服务。
生成的SOAP服务的其他特性
本节描述两个其他过程,你可以将它们添加到Sun Java System Connector Builder生成的SOAP服务的顶部。
HTTPS访问。
附件处理。
HTTPS访问
通过为HTTPS上的SOAP交互启用由Sun Java System Connector Builder生成的SOAP服务,你就可以安全地访问这些SOAP服务了。执行以下步骤:
通过配置Web服务器使用安全套接字层(Secure Sockets Layer,SSL),以确保Web服务器的安全。
这一步是特定于服务器的,请参见你的服务器管理文档。
修改生成的SOAP服务客户端代码,以启用SOAP-HTTPS交互。
执行以下步骤,以允许SOAP服务客户端使用安全的通信。
注意 下面的样例提供一般的指导方针。它只运行在Java 2 Platform, Standard Edition (J2SE) 环境中。在你的服务器环境中,请遵照类似但也许不完全一样的步骤。
使用keytool来为SSL身份验证创建client.keystore文件。确保在客户端代码中指定该文件。键入:
% jdk1.3.1/bin/keytool -import -alias
alias_name /-file client.cer -keystore client.keystore
在提示出现时,键入密码。
如果是第一次键入该命令,那么可键入任何密码。
该目录中的client.cer证书是利用服务器验证了的,该服务器利用Verisign14天试用SSL证书确保了安全。 因此,有了client.cer,你就可以创建你自己的client.keystore文件了。
为了避免错误,请从你安装在你的浏览器上的证书创建client.keystore以通过HTTPS访问Web服务器。
下载Java安全套接字扩展(Java Secure Socket Extension,JSSE),并将三个JAR文件(jsse.jar、jnet.jar和jcert.jar)复制到生成的资源适配器的lib/ext目录中。
修改客户端代码,如下所示:
添加这两个重要的语句到客户端代码中:
import javax.net.ssl.SSLSocketFactory;
import java.security.Security;
添加下面三行到initClient()方法:
// Specify where to find key material for the default
// TrustManager (specify the correct location of the file).
System.setProperty("javax.net.ssl.trustStore",
?"C://jdk1.3.1//bin//client.keystore"
);
// Use Sun's reference implementation of a URL handler
// for the "https" URL protocol type.
System.setProperty("java.protocol.handler.pkgs",
?"com.sun.net.ssl.internal.www.protocol");
// Dynamically register Sun's SSL provider.
Security.addProvider(new
com.sun.net.ssl.internal.ssl.Provider());
在URL字段中指定正确的值,如下所示:
theURL = new URL("https://localhost:483/SOAP/servlet/rpcrouter");
参见创建自定义SOAP服务客户端的样例代码,以利用HTTPS上的SOAP访问COTSAPIGetCustomer服务。
要了解为安全通信设置客户端的详细信息,请参见Apache站点上的论文“为SSL通信设置设置Apache Tomcat和简单Apache SOAP客户端”。
附件处理
可以在SOAP消息体中直接传输大多数常规数据类型,比如String和Date。但是,如果必须传递一个二进制大对象(Binary Large Object,BLOB)作为方法参数,SOAP体将不能保留该对象的值。因此,万维网联盟(World Wide Web Consortium,W3C)已在它的SOAP with Attachments Specification中指定了一个机制,以传递这样的值作为SOAP主体的附件。Apache SOAP 2.2支持该规范。
下面几节研究了使用附件处理机制的两种实现方法,并指出了每种方法的优缺点。要理解这些方法,请考虑一个带有方法void executeAPI(String name, Image img)的Java交互对象(Java Interaction Object,JIO),该方法以一个名称保存一个图像。JIO的实现与资源适配器交互以完成它的工作。
方法1:使用自定义的串行化器
要在SOAP RPC中发送BLOB,你可以为该对象类型创建一个自定义的串行化器,而不是使用MimePart串行化器。在该方法中,自定义的串行化器可以使用Apache SOAP 2.x中内置的Base64Serializer。另外,实际的对象数据不是作为MIME附件发送,而是作为基于64编码的字节流的SOAP主体的一部分。
下面是必须对组件所做的更改:
SOAP服务——服务器端的SOAP运行时接收请求。当看到指定为java.awt.Image的类型时,它就会调用自定义的串行化器来将数据反串行化为图像类型,然后再利用String和Image参数调用executeAPI。你不必自定义由Sun ONE Connector Builder生成的JIO。
自定义的串行化器——自定义的串行化器使用Apache SOAP内置的Base64Serializer来串行化和反串行化自定义的对象——在这里是Image类型。Base64Serializer在串行化和反串行化时处理一个字节数组对象。因此,自定义的串行化器的marshall方法必须首先将图像转换为一个字节数组,并将该字节数组对象传递给Base64Serializer的marshall方法。类似地,在unmarshall方法中,自定义的串行化器必须首先调用Base64Serializer的unmarshall方法,然后利用产生的字节数组类型的Bean值,从字节数组构造一个Image对象,并返回Image类型的新的Bean。
要完成这一串行化和反串行化,自定义的串行化器可以做以下二者之一:
在需要时,从Base64Serializer扩展,并委派给super类方法。
在需要时,说明一个Bean64Serializer对象,并在该对象上调用marshall和unmarshall方法。 以下样例代码演示了unmarshall方法:
public org.apache.SOAP.util.Bean
unmarshall(java.lang.String inScopEEncStyle,
org.apache.SOAP.util.xml.QName elementType,
org.w3c.dom.Node src,
org.apache.SOAP.util.xml.XMLJavaMappingRegistry xjmr,
org.apache.SOAP.rpc.SOAPContext ctx)
throws java.lang.IllegalArgumentException{
//Instantiate a Base64Serializer object.
Base64Serializer srlizr = new Base64Serializer();
//Call its unmarshall method with the same parameters.
Bean bn = srlizr.unmarshall(inScopEEncStyle,
elementType, src, xjmr, ctx);
//Take the byte array value from the resulting
/bean from base64 unmarshall method.
byte barr[] = (byte [])bn.value;
//Create an image from the byte array.
Image img = Toolkit.getDefaultToolkit().createImage(barr);
//Create and return a new bean of type Image.
return new Bean(java.awt.Image.class, img);
}
部署描述符——你必须指示服务器端的SOAP运行时使用自定义的串行化器来串行化类型java.awt.Image的对象。通过部署描述符来实现这一点。
假设SOAPattach.SOAP.serializers.ImageSerializer是自定义的串行化器-反串行化器的全限定类名称。添加以下项到部署描述符:

SOAP服务客户端—— 当客户端遇到java.awt.Image类型时,它必须向SOAP运行时声明将要使用的自定义串行化器。要进行这一声明,请创建SOAPMappingRegistry对象并设置mapTypes。
下面是样例代码:
//Create the registry and add mappings with the serializer info.
theRegistry = new SOAPMappingRegistry();
//Create our new custom serializer object.
mypkg.ImageSerializer serializer1 = new mypkg.ImageSerializer();
//Add the mapping to SOAP mapping registry.
theRegistry.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:xml-SOAP-j2EEca-SOAPattach-serverSaveImage",
"Image"),
java.awt.Image.class, serializer1, serializer1);
客户端不执行参数转换。正如方法所表明的,客户端创建String和Image对象,并将它们设置为SOAP调用对象上的参数。
下面是样例代码:
//Create the parameter vector.
Vector params = new Vector();
//Create and add the name parameter to the parameter vector.
String fileName = new String("theNewFileName");
params.addElement(new Parameter("name",String.class,fileName, null));
//Create an Image object.
Image img = Toolkit.getDefaultToolkit().getImage("c://employEEimage.jpg");
//Add the image parameter to the parameter vector.
params.addElement( new Parameter("image", java.awt.Image.class, img, null);
return params;
SOAP运行时看到java.awt.Image类型时,它就调用自定义的串行化器来串行化Image对象。
考虑该方法的优缺点:
优点
只需要最小的自定义。
LOB可以出现在对象图中的任何地方。
LOB可以为JIO签名的两种类型服务:execute和executeAPI。
缺点
你必须编写自定义的串行化器。但是正如样例所演示的,这是一个很直观的过程。
方法2:使用内置的MimePart串行化器
Apache SOAP包含一个MimePart串行化器,该串行化器可以串行化或反串行化类型为InputStream、DataSource、DataHandler和MimeBodyPart的对象。从而,当一个参数是这四种类型中的某一种时,它就执行以下动作:
利用该对象的值创建一个多用途的网络邮件扩充协议(Multipurpose Internet Mail Extensions,MIME)信封和一个MIME附件。
添加附件到SOAP主体。
要传递BLOB到方法参数,通过采用前面四种数据类型的任何一种,你可以利用该内置的运行时支持(尽可能使用DataHandler)。因为BLOB被作为附件发送,所以该方法也叫做附件方法。
下面是必须对组件所做的更改:
SOAP服务—— 因为附件总是被反串行化为DataHandler类型,所以当服务器端的SOAP运行时接收到一个附件时,它就调用MimePart串行化器来反串行化DataHandler类型。运行时查找具有签名(String, DataHandler)的方法executeAPI,所以你必须提供一个包装方法作为原始方法的过载实现,例如:
void
executeAPI(String name, javax.activation.DataHandler dh)
在该包装方法中,你转换DataHandler到正确的类型,即Image,然后调用原始的方法。参见下面的样例代码:
void executeAPI(String name, javax.activation.DataHandler dh) {
//Create a ByteArrayInputStream from the DataHandler content.
ByteArrayInputStream fis = (ByteArrayInputStream) dh.getContent();
//Find the available size of the ByteArrayInputstream
//and read that into a byte array.
int size = fis.available();
byte b[] = new byte[size];
fis.read(b);
//Create the image from the byte array.
Image img = Toolkit.getDefaultToolkit().createImage(b);
//Call the original method with the name and image.
executeAPI(name,img);
}
部署描述符——你不必更改部署描述符。实现使用Apache SOAP的默认内置支持,所以你不必添加任何附加的映射信息到部署描述符。另外,Apache SOAP只在部署时使用方法名称并在运行时映射参数信息,你不必为任何过载方法指定参数类型。
SOAP服务客户端——不是直接使用Image类型,客户端必须将图像(java.awt.Image)转换为DataHandler类型,并添加DataHandler对象作为方法的参数。客户端还必须在SOAP调用对象上设置参数。
SOAP服务客户端的populateInputData(...)方法中做适当更改。下面的样例代码演示了populateInputData方法:
private Vector populateInputData() {
// Create the parameter vector
Vector params = new Vector();
//create and add the name parameter to the parameter vector
String fileName = new String("theNewFileName");
params.addElement(new
Parameter("name",String.class,fileName, null));
// create and add the image parameter to the parameters vector.
DataSource ds = new ByteArrayDataSource(new
File("c://employEEimage.jpg"), "image/jpeg");
DataHandler dh = new DataHandler(ds);
params.addElement(new Parameter("img",
DataHandler.class, dh, null));
return params;
}
考虑该方法的优缺点:
优点
发送BLOB作为附件时有效的。
必自定义或指定任何串行化器或反串行化器。
缺点
不能将该方法用于execute方法变体,因为这些变体只暴露输入和输出记录,而不暴露单独的参数。
在对象图的深层需要BLOB时,不能使用该方法。要使该方法工作,BLOB必须位于图的顶层。
必须自定义多个区域:服务器、客户端代码,等等。
评价
方法1比方法2有以下优点:
务客户端可以使用JIO方法签名(execute and executeAPI)的两种类型。
LOB可以出现在对象图的任何地方——顶部、中间或者叶子节点下面。
必自定义生成的JIO。
结论
有了Sun Java System Connector Builder,可以有效地构建Web服务就绪的连接器。通过提供端到端特性设置(适配器、SOAP服务端点、部署描述符和构建脚本的生成器),Sun ONE Connector Builder帮助你为SOAP交互完全地、无缝地和直观地启用资源适配器。
另外,通过生成的代码的简单自定义,可以为HTTPS上的SOAP交互和附件处理增强生成的服务。
请你自己探索Sun Java System Connector Builder的强壮性和通用性!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: