开发SOAP客户端
利用SAAJ,客户端能够以点对点的方式创建并且发送SOAP消息。JAXM为使用消息提供者的XML消息定义了API。JAXM依赖用于 Java 的带有附件的 SOAP API(SAAJ),它定义了在Java中操作带有附件的SOAP消息模型的API。Sun ONE Application Server不包括它所支持的JAXM消息提供者。然而它的确包含了示例应用程序,一个简单的JAXM提供者,演示了一个消息提供者如何处理来自客户端的异步SOAP消息。本节讲述以下主题:
SOAP消息是如何出现的?
当消息工厂生产的SOAP消息通过连接被发送到一个端点的时候,SOAP消息就出现了。本节讲述以下主题:
端点
端点标识消息的最终目的地。端点是由URLEndpoint类来定义的。如果不使用提供者,你可以构造或者查找到一个消息端点。
构造端点
你可以通过调用构造函数或者在名称服务中查找来初始化一个端点。
以下代码使用构造函数创建一个URLEndpoint:
myEndpoint = new URLEndpoint("http://host/myServlet")
使用端点发送消息
指定端点作为SOAPConnection.call方法的一个参数,该方法是用来发送SOAP消息的。
向多个端点发送消息
管理对象是封装了针对提供者的配置和命名信息的对象。如果使用管理对象定义端点,需要注意的是:可以把该管理对象绑定到多个URL——每个URL都能够处理到达的SOAP消息。
以下代码示例把lookup名称为myEndpoint的端点绑定到两个URL:http://www.myServlet1/
和 http://www.myServlet2/。这个语法允许你使用SOAP连接发布SOAP消息到多个端点。
imqobjmgr add
-t e
-l "cn=myEndpoint"
-o "imqSOAPEndpointList=http://www.myServlet1/
http://www.myServlet2/"
连接
想要利用SAAJ或JAXM发送SOAP消息,必须分别获得一个SOAPConnection 或ProviderConnection。你还可以使用消息队列传输消息;更多信息请参见Sun ONE消息队列开发人员指南。
SOAP 连接
SOAPConnection允许你直接向远程伙伴发送消息。通过调用静态方法SOAPConnectionFactory.newInstance(),可以容易地得到SOAPConnection对象。这种类型的连接既不保证可靠性也不保证安全性。
提供者连接
从ProviderConnectionFactory 获得的ProviderConnection可以创建到特定消息提供者的连接。当使用提供者发送SOAP消息的时候,消息被传递给提供者,然后提供者负责传递消息到它的最终目的地,这样保证了可靠并且安全的消息传输。
创建SOAP客户端
创建SOAP客户端之前,确定你已经设置了客户端环境。关于设置客户端环境的更多信息,请参见"配置客户端环境 "。
如果创建一个点对点客户端,你必须导入SAAJ API的javax.xml.soap程序包。如果创建一个pub/sub客户端,需要导入import JAXM API的javax.xml.messaging程序包。除此之外,你还必须导入以下程序包:
import java.net.*;
import java.io.*;
import java.util.*;
import javax.servlet.http.*;
import javax.servlet.*;
import javax.activation.*;
import javax.naming.*;
创建SOAP客户端并访问消息包括以下步骤:
获得连接
单独客户端
不使用消息提供者的客户端使用SOAPConnection对象创建连接。使用SoapConnection对象发送的消息直接从发送者到发送者指定的URL。
必须获得一个SOAPConnectionFactory对象来创建连接。SAAJ API通过提供SOAPConnectionFactory类的一个默认实现简化了这一过程。以下代码演示了如何获得该实现的一个实例:
SOAPConnectionFactory scf = SOAPConnectionFactory. newInstance();
现在,你可以使用scFactory创建SOAPConnection对象
SOAPConnection con = scf.createConnection();
创建消息
使用MessageFactory对象来创建消息。如果想要创建一个单独客户端,也就是既不使用消息提供者也不在容器中运行的客户端,你可以使用SAAJ API提供的MessageFactory类的实现。以下代码演示了如何获得默认消息工厂的一个实例,然后用它创建消息:
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage msg = mf.createMessage();
消息创建过程会完成SOAPPart的创建,它是SOAP 1.1规范中每个消息的必要部分。
SOAPPart sp = msg.getSOAPPart();
注意:
通常,使用默认的消息工厂创建消息。但是,你也可以编写自己的消息工厂实现,并且把它插入到系统属性中,如下所示:
通过扩展javax.xml.soap.MessageFactory实现消息工厂类。 javax.xml.soap是在SAAJ API中定义的程序包。
通过设定系统属性javax.xml.soap.MessageFactory为消息工厂实现类mypackage.MySOAPMessageFactoryImpl的完全路径名,指定希望被实例化的消息工厂类。
关于SOAP消息结构和组成部分的信息,请参见"SOAP消息的组成部分"。
向Header添加内容
创建一个SOAPHeaderElement对象,从而可以添加内容到header中。以下代码演示了如何使用SOAPEnvelope对象创建一个SOAPHeaderElement。
SOAPHeader hdr = envelope.getHeader();
Name headerName = envelope.createName("Purchase Order","PO", "http://www.sonata.com/order");
SOAPHeaderElement headerElement = hdr.addHeaderElement(headerName);
HeaderElement通过Name对象headerName进行标识。AddHeaderElement方法是用来添加或者创建header元素的。
为了添加内容到headerElement,请象以下代码示例那样使用addTextNode方法。
headerElement.addTextNode("order");
SOAPHeader对象包含一个内容为"order"的SOAPHeaderElement对象。
向消息添加内容
你可以向SOAPPart对象,或者一或多个AttachmentPart对象添加内容,或者可以向消息的这两个部分都添加内容。
为了向消息体添加内容,请创建一个SOAPBodyElement对象并添加一个使用SOAPElement.addTextNode方法建立的XML元素。下面的代码演示了如何添加内容到消息:
SOAPEnvelope envelope = sp.getSOAPEnvelope();
SOAPBody bdy = envelope.getSOAPBody();
SOAPBodyElement gltp = bdy.addBodyElement(envelope.createName("GetLastTradePrice", "ztrade", "http://wombat.ztrade.com"));
gltp.addChildElement(envelope.createName("symbol","ztrade", "http://wombat.ztrade.com")).addTextNode("SUNW");;
代码的前三行访问了SOAPBody对象body,目的是创建一个新SOAPBodyElement对象并把它添加到body上。CreateName方法需要Name对象作为参数,用来指定被添加的SOAPBodyElement。最后一行添加传递给addTextNode方法的XML字符串。
向消息添加一个附件
向消息添加附件的过程对于使用或不使用消息提供者的客户端来说都是一样的。使用AttachmentPart对象向消息中添加附件部分。
使用SOAPMessage对象创建AttachmentPart对象。SOAPMessage类含有三个创建附件的方法。第一个方法允许你创建一个没有内容的AttachmentPart。就是说,以后再使用AttachmentPart的方法setContent来添加内容到附件。
URL url = new URL(data);
AttachmentPart ap = msg.createAttachmentPart(new DataHandler(url));
SetContent有两个参数,对应内容的Java对象以及标识内容类型的String对象。内容是消息的SOAPBody部分,消息有一个值为"text/xml"的内容-类型(Content-Type)header,这是因为内容只能是XML格式。在AttachmentPart中,内容的类型只能被指定为该对象能够容纳的任意类型。
每个AttachmentPart都有一个或多个与之相关的header。setContent方法中用到的类型就是Content-Type这个header类型。这是唯一必须具备的header。你还可以设置其他可选的header,例如Content-Id和Content-Location。为了方便,JAXM和SAAJ API为Content-type、 Content-Id、和Content-Location这几个header提供了get和set方法。这些header在消息拥有多个附件的时候,可以帮助对附件的访问。
以下代码演示了如何使用setContent方法:
String stringContent = "Update address for Sunny Skies " + "Inc., to 10 Upbeat Street, Pleasant Grove, CA 95439";
ap.setContent(stringContent, "text/html");
ap.setContentId("update_address");
msg.addAttachmentPart(ap);
如果你还想附加一个jpeg图像,setContent方法的第二个参数必须被设为"image/jpeg"。下面的代码演示了如何使用setContent方法附加图片:
AttachmentPart ap2 = msg.createAttachmentPart();
byte[] jpegData = . . .;
ByteArrayInputStream stream = new ByteArrayInputStream(jpegData);
ap2.setContent(stream, "image/jpeg");
msg.addAttachmentPart(ap2);
AttachmentPart的另外两个方法允许你创建带内容的AttachmentPart对象。其中一个与AttachmentPart.setContent方法很象。它需要一个包含内容的Java对象和一个指定内容类型的String作为参数。对象可以是String、stream、 javax.xml.transform.Source对象、或 javax.activation.DataHandler对象。
另一个创建带内容的AttachmentPart对象的方法需要一个DataHandler对象作为输入参数,它是JavaBeans激活框架(JAF)的一部分
以下代码演示了如何在内容中使用DataHandler。首先为想要作为内容添加的文件创建一个java.net.URL对象。创建DataHandler对象,即javax.activation.DataHandler 对象dh,使用URL对象对其进行初始化,然后把dh传递给createAttachmentPart方法。
URL url = new URL("http://greatproducts.com/gizmos/img.jpg");
DataHandler dh = new DataHandler(url);
AttachmentPart ap = msg.createAttachmentPart(dh);
ap.setContentId("gyro_image")
msg.addAttachmentPart(ap);
发送消息
单独客户端
为了发送消息,单独客户端使用SOAPConnection的call方法。该方法需要两个输入参数,要发送的消息和消息的目的地,目的地是一个包含接收者URL的Endpoint对象。
利用SoapConnection的情况下,使用javax.xml.soap.SOAPConnection.call()发送消息。
例如:
URL urlEndpoint = new URL(to);
SOAPMessage reply = con.call(msg, urlEndpoint);
从响应消息中检索内容
客户端使用onMessage方法检索消息内容。客户端通过消息得到envelope,再通过envelope得到body,从而访问SOAPBody对象。访问SOAPBody对象是因为内容存放在该元素中。为了检索由Node.addTextNode方法添加的内容,请调用Node.getValue方法。GetValue返回调用元素的直接子元素的值。为了访问bodyElement,需要在body上调用getChildElement方法。以下代码演示了如何从响应消息中检索内容。
public SOAPMessage onMessage(SOAPMessage message)
{
SOAPEnvelop env = msg.getSOAPPart().getEnvelope();
env getBody()
.addChildElement(env.createName("Response"))
.addTextNode("This is a Response");
return msg;
}
想要从含有附件的消息中检索内容,你需要访问附件。没有参数的情况下,SOAPMessage.getAttachments方法返回指向所有AttachmentPart对象的java.util.Iterator对象。以下代码打印出了SOAPMessage对象消息中每一个AttachmentPart对象的内容。
java.util.Iterator it = message.getAttachments();
while (it.hasNext()) {
AttachmentPart attachment = (AttachmentPart)it.next();
Object content = attachment.getContent();
String id = attachment.getContentId();
System.out.print("Attachment " + id + " contains: " + content);
System.out.println("");
}
访问消息的附件部分
当收到带有附件的消息或是希望改变消息附件的时候,都需要访问消息的附件。没有附加信息的SOAPMesssage.getAttachments方法返回指向消息中所有AttachmentPart对象的java.util.Iterator对象。以下代码演示了如何访问附件从而获得SOAPMessage对象消息中每个AttachmentPart对象的内容。
java.util.Iterator it = msg.getAttachments();
while (it.hasNext()) {
AttachmentPart ap = it.next();
Object content = ap.getContent();
String id = ap.getContentId();
System.out.print("Attachment " + id + " contains: " + content);
System.out.println("");
}
组装并部署SOAP客户端
利用JAXM API和SAAJ API创建的应用程序被组装为web应用(WAR)或者基于J2EE平台的应用(EAR)。关于组装和部署web应用,请参见Sun ONE Application Server开发人员web应用指南。