• No results found

Use Provider API to create a web service

In document OCEWSD6_StudyGuide_MikalaiZaikin (Page 77-82)

Chapter 10. Create low-level SOAP web services

10.3. Use Provider API to create a web service

Prev Chapter 10. Create low-level SOAP web services. Next

10.3. Use Provider API to create a web service.

10.3.1. Process the entire SOAP message, using the SAAJ APIs.

SAAJ overview

Alt hough t he SAAJ API can be used from JAX-W S applicat ions, it can also be used alone. In fact , t he SAAJ API cont ains all t he classes t hat you need t o send and receive SOAP messages. All t he SAAJ classes belong t o t he javax.xml.soap package namespace.

As show n in t he figure below , t he core SAAJ API exposes classes t hat closely mimic t he act ual SOAP messages st ruct ure:

Figure 10.6. Core SAAJ 1.3 API

T he core SAAJ API includes t he follow ing classes and int erfaces:

SOAPMessage

T he SOAPMessage object represent s t he ent ire SOAP message. It has a single SOAPPart and possibly one or more AttachmentParts.

SOAPPart

T he SOAPPart object cont ains a SOAPEnvelope message. T he SOAPEnvelope represent s t he act ual SOAP Envelope.

SOAPEnvelope

T he SOAPEnvelope has an opt ional SOAPHeader and a mandat ory SOAPBody.

SOAPHeader

T he SOAPHeader represent s t he SOAP header block in a SOAP message and is allow ed t o be empt y as is t he case w it h t he header sect ion in a SOAP 1.1 or 1.2 message.

SOAPBody

T he SOAPBody element can cont ain eit her a SOAPFault object or t he act ual SOAP payload XML cont ent (SOAPBodyElement).

SOAPFault

T he SOAPFault object represent s a SOAP fault message.

T he SAAJ t ypes and t he t ypes from t he org.w3c.dom Java XML package are closely relat ed. In fact , many of t he classes in SAAJ ext end or implement behavior from classes in t he org.w3c.dom package namespace. An example of t his is t he SOAPPart object t hat implement s t he org.w3c.dom.Document int erface.

Accessing Element s of a Message T here are t w o w ays t o do t his.

First w ay:

SOAPPart soapPart = message.getSOAPPart();

SOAPEnvelope envelope = soapPart.getEnvelope();

SOAPHeader header = envelope.getHeader();

SOAPBody body = envelope.getBody();

Second w ay:

SOAPHeader header = message.getSOAPHeader();

SOAPBody body = message.getSOAPBody();

Adding Cont ent t o t he Body

T he SOAPBody object cont ains eit her cont ent or a fault . To add cont ent t o t he body, you normally creat e one or more SOAPBodyElement object s t o hold t he cont ent . You can also add subelement s t o t he SOAPBodyElement object s by using t he addChildElement met hod. For each element or child element , you add cont ent by using t he addTextNode met hod.

W hen you creat e any new element , you also need t o creat e an associat ed javax.xml.namespace.QName object so t hat it is uniquely ident ified.

QName object s associat ed w it h SOAPBodyElement or SOAPHeaderElement object s must be fully qualified; t hat is, t hey must be creat ed w it h a namespace URI, a local part , and a namespace prefix. Specifying a namespace for an element makes clear w hich one is meant if more t han one element has t he same local name.

T he follow ing code fragment ret rieves t he SOAPBody object body from message, const ruct s a QName object for t he element t o be added, and adds a new SOAPBodyElement object t o body:

SOAPBody body = message.getSOAPBody();

QName bodyName = new QName("http://wombat.ztrade.com", "GetLastTradePrice", "m");

SOAPBodyElement bodyElement = body.addBodyElement(bodyName);

At t his point , body cont ains a SOAPBodyElement object ident ified by t he QName object bodyName, but t here is st ill no cont ent in bodyElement. Assuming t hat you w ant t o get a quot e for t he st ock of Sun Microsyst ems, Inc., you need t o creat e a child element for t he symbol using t he addChildElement met hod. T hen you need t o give it t he st ock symbol using t he addTextNode met hod. T he QName object for t he new SOAPElement object symbol is init ialized w it h only a local name because child element s inherit t he prefix and URI from t he parent element : aut omat ically w hen you call met hods such as addBodyElement, addChildElement, and addTextNode. Not e t hat you can call t he met hod addTextNode only on an element such as bodyElement or any child element s t hat are added t o it . You cannot call addTextNode on a SOAPHeader or SOAPBody object because t hey cont ain element s and not t ext .

T he cont ent t hat you have just added t o your SOAPBody object w ill look like t he follow ing:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

<SOAP-ENV:Body>

<m:GetLastTradePrice xmlns:m="http://wombat.ztrade.com">

<symbol>SUNW</symbol>

</m:GetLastTradePrice> object , or you access t he SOAPBody object t hrough t he SOAPPart and SOAPEnvelope object s.

T hen you access t he SOAPBody object 's SOAPBodyElement object , because t hat is t he element t o w hich cont ent w as added in t he example.

To get t he cont ent , w hich w as added w it h t he met hod SOAPElement.addTextNode, you call t he met hod Node.getValue. Not e t hat getValue ret urns t he value of t he immediat e child of t he element t hat calls t he met hod. T herefore, in t he follow ing code fragment , t he getValue met hod is called on bodyElement, t he element on w hich t he addTextNode met hod w as called.

To access bodyElement, you call t he getChildElements met hod on soapBody. Passing bodyName t o getChildElements ret urns a java.util.Iterator object t hat cont ains all t he child element s ident ified by t he Name object bodyName. You already know t hat t here is only one, so calling t he next met hod on it w ill ret urn t he

SOAPBodyElement you w ant . Not e t hat t he Iterator.next() met hod ret urns a Java Object, so you need t o cast t he Object it ret urns t o a SOAPBodyElement object before assigning it t o t he variable bodyElement:

SOAPBody soapBody = response.getSOAPBody();

QName bodyName = new QName("http://wombat.ztrade.com", "GetLastTradePrice", "m");

java.util.Iterator iterator = soapBody.getChildElements(bodyName);

For example, suppose you w ant t o add a conformance claim header t o t he message t o st at e t hat your message conforms t o t he W S-I Basic Profile. T he follow ing code fragment ret rieves t he SOAPHeader object from message and adds a new SOAPHeaderElement object t o it . T his SOAPHeaderElement object cont ains t he correct qualified name and at t ribut e for a W S-I conformance claim header:

SOAPHeader header = message.getSOAPHeader();

QName headerName = new QName("http://ws-i.org/schemas/conformanceClaim/", "Claim", "wsi");

SOAPHeaderElement headerElement = header.addHeaderElement(headerName);

headerElement.addAttribute(new QName("conformsTo"), "http://ws-i.org/profiles/basic/1.1/");

At t his point , header cont ains t he SOAPHeaderElement object headerElement ident ified by t he QName object headerName. Not e t hat t he addHeaderElement met hod

bot h creat es headerElement and adds it t o header.

A conformance claim header has no cont ent . T his code produces t he follow ing XML header:

<SOAP-ENV:Header>

<wsi:Claim

xmlns:wsi="http://ws-i.org/schemas/conformanceClaim/"

conformsTo="http://ws-i.org/profiles/basic/1.1/"/>

</SOAP-ENV:Header>

For a different kind of header, you might w ant t o add cont ent t o headerElement. T he follow ing line of code uses t he met hod addTextNode t o do t his:

headerElement.addTextNode("order");

Creat ing an AttachmentPart Object and Adding Cont ent

T he SOAPMessage object creat es an AttachmentPart object , and t he message also must add t he at t achment t o it self aft er cont ent has been added. T he SOAPMessage class has t hree met hods for creat ing an AttachmentPart object .

T he first met hod creat es an at t achment w it h no cont ent . In t his case, an AttachmentPart met hod is used lat er t o add cont ent t o t he at t achment : AttachmentPart attachment = message.createAttachmentPart();

You add cont ent t o at t achment by using t he AttachmentPart met hod setContent. T his met hod t akes t w o paramet ers: a Java Object for t he cont ent , and a String object for t he MIME cont ent t ype t hat is used t o encode t he object . Cont ent in t he SOAPBody part of a message aut omat ically has a Content-Type header w it h t he value

"text/xml" because t he cont ent must be in XML. In cont rast , t he t ype of cont ent in an AttachmentPart object must be specified because it can be any t ype.

Each AttachmentPart object has one or more MIME headers associat ed w it h it . W hen you specify a t ype t o t he setContent met hod, t hat t ype is used for t he header Content-Type. Not e t hat Content-Type is t he only header t hat is required. You may set ot her opt ional headers, such as Content-Id and Content-Location. For convenience, SAAJ provides get and set met hods for t he headers Content-Type, Content-Id, and Content-Location. T hese headers can be helpful in accessing a part icular at t achment w hen a message has mult iple at t achment s. For example, t o access t he at t achment s t hat have part icular headers, you can call t he SOAPMessage met hod getAttachments and pass it a MIMEHeaders object cont aining t he MIME headers you are int erest ed in.

T he follow ing code fragment show s one of t he w ays t o use t he met hod setContent. T he Java Object in t he first paramet er can be a String, a st ream, a

javax.xml.transform.Source object , or a javax.activation.DataHandler object . T he Java Object being added in t he follow ing code fragment is a String, w hich is plain t ext , so t he second argument must be "text/plain". T he code also set s a cont ent ident ifier, w hich can be used t o ident ify t his AttachmentPart object . Aft er you have added cont ent t o at t achment , you must add it t o t he SOAPMessage object :

String stringContent = "10 Upbeat Street, Pleasant Grove, CA 95439";

attachment.setContent(stringContent, "text/plain");

attachment.setContentId("update_address");

message.addAttachmentPart(attachment);

T he ot her t w o SOAPMessage.createAttachment met hods creat e an AttachmentPart object complet e w it h cont ent . One is very similar t o t he

AttachmentPart.setContent met hod in t hat it t akes t he same paramet ers and does essent ially t he same t hing. It t akes a Java Object cont aining t he cont ent and a String giving t he cont ent t ype. A s w it h AttachmentPart.setContent, t he Object can be a String, a st ream, a javax.xml.transform.Source object , or a javax.activation.DataHandler object .

T he ot her met hod for creat ing an AttachmentPart object w it h cont ent t akes a DataHandler object , w hich is part of t he JavaBeans Act ivat ion Framew ork (JAF). Using a DataHandler object is fairly st raight forw ard. First , you creat e a java.net.URL object for t he file you w ant t o add as cont ent . T hen you creat e a DataHandler object init ialized w it h t he URL object : care of set t ing t he Content-Type header for you, somet hing t hat is possible because one of t he t hings a DataHandler object does is t o det ermine t he dat a t ype of t he file it cont ains.

Accessing an AttachmentPart Object

If you receive a message w it h at t achment s or w ant t o change an at t achment t o a message you are building, you need t o access t he at t achment . T he SOAPMessage class provides t w o versions of t he getAttachments met hod for ret rieving it s AttachmentPart object s. W hen it is given no argument , t he met hod

SOAPMessage.getAttachments() ret urns a java.util.Iterator object over all t he AttachmentPart object s in a message. W hen getAttachments is given a MimeHeaders object , w hich is a list of MIME headers, getAttachments ret urns an it erat or over t he AttachmentPart object s t hat have a header t hat mat ches one of t he headers in t he list . T he follow ing code uses t he getAttachments met hod t hat t akes no argument s and t hus ret rieves all t he AttachmentPart object s in t he SOAPMessage object message. T hen it print s t he cont ent ID, t he cont ent t ype, and t he cont ent of each AttachmentPart object :

java.util.Iterator iterator = message.getAttachments();

while (iterator.hasNext()) {

AttachmentPart attachment = (AttachmentPart)iterator.next();

String id = attachment.getContentId();

String type = attachment.getContentType();

System.out.print("Attachment " + id + " has content type " + type);

if (type.equals("text/plain")) {

Object content = attachment.getContent();

System.out.println("Attachment contains:\n" + content);

} }

10.3.2. Process only the SOAP body, using JAXB.

Developing a dispat ch client t hat uses JAXB

Example below demonst rat es how JAX-W S allow s you t o w ork w it h JAXB object s from a dispat ch client :

private static final String TNS = "http://java.boot.by/";

public static void main(String... args) throws Exception { // Define the service name, port name, and endpoint address QName serviceName = new QName(TNS, "HelloMessengerService");

QName portName = new QName(TNS, "HelloMessenger");

String endpoint = "http://localhost:80/Hello";

// Create a service that can bind to the HelloMessenger port Service service = Service.create(serviceName);

service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpoint);

// Create a JAXB enabled Dynamic Dispatch client

JAXBContext context = JAXBContext.newInstance("by.boot.java");

Dispatch<Object> dispatch = service.createDispatch(portName, context, Service.Mode.PAYLOAD);

// Create JAXB request object

ObjectFactory objectFactory = new ObjectFactory();

SayHello request = objectFactory.createSayHello();

request.setArg0("Mikalai");

JAXBElement<SayHello> requestMessage = objectFactory.createSayHello(request);

// Invoke the HelloMessenger Web service

JAXBElement<SayHelloResponse> responseMessage = (JAXBElement<SayHelloResponse>)dispatch.invoke(requestMessage);

// Get the JAXB response

SayHelloResponse response = responseMessage.getValue();

String value = response.getReturn();

T he lines in bold illust rat e w here JAXB funct ionalit y is being used.

T he key point t o not e w it h regards t o t he dispat ch client creat ion is t hat t he Service.createDispatch met hod is invoked w it h a JAXBContext and a PAYLOAD service mode. T he PAYLOAD argument specifies t o t he JAX-W S run t ime t hat it should t ake care of handling t he SOAP envelope det ails. T he JAXBContext argument specifies t hat w e w ill let JAXB handle t he marshalling and unmarshalling of t he act ual SOAP payload.

Aft er creat ion of t he dispat ch client , t he applicat ion demonst rat es how t he generat ed ObjectFactory class is used t o produce t he request object s t hat w ill be sent over t he w ire. Since t he generat ed classes (SayHello and SayHelloResponse) in t his example have not been annot at ed w it h a @XmlRootElement by t he JAXB binding compiler, JAXB requires t hat t hey be w rapped in a JAXBElement w rapper.

Developing a JAX-WS logical handler t hat uses JAXB

JAXB w orks w ell w it h logical handlers t hat are unaw are of t he act ual t ransport prot ocol det ails. Example below demonst rat es a logical JAX-W S handler t hat t ransforms out going payload t ext t o uppercase:

import javax.xml.bind.JAXBContext;

public boolean handleMessage(LogicalMessageContext ctx) {

String outboundProp = MessageContext.MESSAGE_OUTBOUND_PROPERTY;

boolean outbound = (Boolean) ctx.get(outboundProp);

if (outbound) { try {

LogicalMessage message = ctx.getMessage();

JAXBContext context = JAXBContext.newInstance(SayHelloResponse.class);

SayHelloResponse response = (SayHelloResponse) message.getPayload(context);

response.setReturn(response.getReturn().toUpperCase());

message.setPayload(response, context);

} catch (JAXBException e) { e.printStackTrace();

} }

return true /* continue chain */;

}

public void close(MessageContext ctx) {}

public boolean handleFault(LogicalMessageContext ctx) { return false;

} }

T he lines t hat involve JAXB are highlight ed in bold. T he handler checks w het her t he current message being handled is out bound or inbound. If t he message is out bound, it get s t he JAXB payload object from t he LogicalMessage, updat es t he ret urn value t o uppercase, and overrides t he ent ire payload. T he SayHelloResponse object in t his example w as generat ed w it h an @XmlRootElement annot at ion. T herefore, w e did not need t o be concerned w it h t he JAXBElement w rapper.

Prev Up Next

10.2. Describe the functions and capabilities of JAXB, including the JAXB process flow, such as XML-to-Java and Java-to-XML, and the binding and validation mechanisms provided by JAXB.

Home

10.4. Use Dispatch API to create a dynamic web service client.

Host ing provided by PerfoHost: KVM VPS provider. See PefoHost 's KVM VPS vs OpenVZ/Virt uozzo vs XEN VPS comparat ive chart . CRM-export er: Vehicle Dat abase Script 1999-2011

In document OCEWSD6_StudyGuide_MikalaiZaikin (Page 77-82)