|
Home
TOC Index |
|
Code Examples
The first part of this tutorial used code fragments to walk you through the fundamentals of using the JAXM API. In this section, you will use some of those code fragments to create applications. First, you will see the program
Request.java. Then you will see how to create and run the applicationMyUddiPing.java. Finally, you will see how to create and runSOAPFaultTest.java.
Note:<JWSDP_HOME>is the directory where you unpacked the Java Web Services Developer Pack.
Request.java
The class
Request.javaputs together the code fragments used in the section Client without a Messaging Provider and adds what is needed to make it a complete example of a client sending a request-response message. In addition to putting all the code together, it addsimportstatements, amainmethod, and atry/catchblock with exception handling. The fileRequest.java, shown here in its entirety, is a standalone client application that uses the SAAJ API (thejavax.xml.soappackage). It does not need to use thejavax.xml.messagingpackage because it does not use a messaging provider.import javax.xml.soap.*; import java.util.*; import java.net.URL; public class Request { public static void main(String[] args) { try { SOAPConnectionFactory scFactory = SOAPConnectionFactory.newInstance(); SOAPConnection con = scFactory.createConnection(); MessageFactory factory = MessageFactory.newInstance(); SOAPMessage message = factory.createMessage(); SOAPPart soapPart = message.getSOAPPart(); SOAPEnvelope envelope = soapPart.getEnvelope();SOAPHeader header = envelope.getHeader();SOAPBody body = envelope.getBody(); header.detachNode(); Name bodyName = envelope.createName( "GetLastTradePrice", "m", "http://wombats.ztrade.com"); SOAPBodyElement gltp = body.addBodyElement(bodyName); Name name = envelope.createName("symbol"); SOAPElement symbol = gltp.addChildElement(name); symbol.addTextNode("SUNW"); URL endpoint = new URL ("http://wombat.ztrade.com/quotes"; SOAPMessage response = con.call(message, endpoint); con.close(); SOAPPart sp = response.getSOAPPart(); SOAPEnvelope se = sp.getEnvelope(); SOAPBody sb = se.getBody(); Iterator it = sb.getChildElements(bodyName); SOAPBodyElement bodyElement = (SOAPBodyElement)it.next(); String lastPrice = bodyElement.getValue(); System.out.print("The last price for SUNW is "); System.out.println(lastPrice); } catch (Exception ex) { ex.printStackTrace(); } } }In order for
Request.javato be runnable, the second argument supplied to the methodcallhas to be a valid existing URI, which is not true in this case. See the JAXM code in the case study for similar code that you can run (JAXM Client). Also, the application in the next section is one that you can run.UddiPing.java and MyUddiPing.java
The sample program
UddiPing.javais another example of a standalone application. A Universal Description, Discovery and Integration (UDDI) service is a business registry and repository from which you can get information about businesses that have registered themselves with the registry service. For this example, theUddiPingapplication is not actually accessing a UDDI service registry but rather a test (demo) version. Because of this, the number of businesses you can get information about is limited. Nevertheless,UddiPingdemonstrates a request being sent and a response being received. The application prints out the complete message that is returned, that is, the complete XML document as it looks when it comes over the wire. Later in this section you will see how to rewriteUddiPing.javaso that in addition to printing out the entire XML document, it also prints out just the text content of the response, making it much easier to see the information you want.In order to get a better idea of how to run the
UddiPingexample, take a look at the directory<JWSDP_HOME>/samples/jaxm/uddiping. This directory contains the subdirectorysrcand the filesrun.sh(orrun.bat),uddi.properties,UddiPing.class, andREADME. TheREADMEfile tells you what you need to do to run the application, which is explained more fully here.The
READMEfile directs you to modify the fileuddi.properties, which contains the URL of the destination (the UDDI test registry) and the proxy host and proxy port of the sender. If you are in theuddipingdirectory when you call therun.sh(orrun.bat) script, the information inuddi.propertiesshould be correct already. If you are outside Sun Microsystem's firewall, however, you need to supply your proxy host and proxy port. If you are not sure what the values for these are, you need to consult your system administrator or other person with that information.The main job of the
runscript is to executeUddiPing. Once the fileuddi.propertieshas the correct proxy host and proxy port, you can call the appropriaterunscript as shown here. Note that you must supply two arguments,uddi.propertiesand the name of the business you want to look up.cd <JWSDP_HOME>/samples/jaxm/uddiping run.sh uddi.properties Microsoftcd <JWSDP_HOME>\samples\jaxm\uddiping run.bat uddi.properties MicrosoftWhat appears on your screen will look something like this:
Received replyfrom: http://www3.ibm.com/services/uddi/testregistry/inquiryapi<?xml version="1.0" encoding="UTF-8" ?><Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Body><busin essList generic="1.0" xmlns="urn:uddi-org:api" operator="www.ibm.com/services/uddi" truncated="false"><businessInfos><businessInfo businessKey="D7475060-BF58-11D5-A432- 0004AC49CC1E"><name>Microsoft Corporation</name><description xml:lang="en">Computer Software and Hardware Manufacturer</description><serviceInfos></serviceInfos></busin essInfo></businessInfos></businessList></Body></Envelope>If the business name you specified is in the test registry, the output is an XML document with the name and description of that business. However, these are embedded in the XML document, which makes them difficult to see. The next section adds code to
UddiPing.javathat extracts the content so that it is readily visible.Creating MyUddiPing.java
To make the response to
UddiPing.javaeasier to read, you will create a new file calledMyUddiPing.java, which extracts the content and prints it out. You will see how to write the new file later in this section after setting up a new directory with the necessary subdirectories and files.Setting Up
Because the name of the new file is
MyUddiPing.java, create the directorymyuddipingunder the<JWSDP_HOME>/samples/jaxmdirectory.cd <JWSDP_HOME>/samples/jaxm mkdir myuddipingThis new
myuddipingdirectory will be the base directory for all future commands relating toMyUddiPing.java.In place of the
run.shorrun.batscript used for runningUddiPing, you will be using anAntfile,build.xml, for setting up directories and files and for runningMyUddiPing. The advantage of using anAntfile is that it is cross-platform and can thus be used for both Unix and Windows platforms. Accordingly, you need to copy thebuild.xmlfile in theexamples/jaxmdirectory of the tutorial to your newmyuddipingdirectory. (The command for copying should be all on one line. Note that there is no space between "myuddiping/" "and "build", and there is a "." at the end of the command line.)cd myuddiping cp <JWSDP_HOME>/docs/tutorial/examples/jaxm/myuddiping/ build.xml .cd myuddiping copy <JWSDP_HOME>\docs\tutorial\examples\jaxm\myuddiping\ build.xml .Once you have the file
build.xmlin yourmyuddipingdirectory, you can call it to do the rest of the setup and also to runMyUddiPing. AnAntbuild file is an XML file that is sectioned into targets, with each target being an element that contains attributes and one or more tasks. For example, the target element whose name attribute ispreparecreates the directoriesbuildandsrcand copies the fileMyUddiPing.javafrom the<JWSDP_HOME>/docs/tutorial/examples/jaxm/myuddiping/srcdirectory to the newsrcdirectory. Then it copies the fileuddi.propertiesfrom theuddipingdirectory to themyuddipingdirectory that you created.To accomplish these tasks, you type the following at the command line:
ant prepareThe target named
buildcompiles the source fileMyUddiPing.javaand puts the resulting.classfile in thebuilddirectory. So to do these tasks, you type the following at the command line:ant buildNow that you are set up for running
MyUddiPing, let's take a closer look at the code.Examining MyUddiPing
We will go through the file
MyUddiPing.javaa few lines at a time. Note that most of the classMyUddiPing.javais based onUddiPing.java. We will be adding a section at the end ofMyUddiPing.javathat accesses only the content you want from the response that is returned by the methodcall.The first four lines of code import the packages used in the application.
import javax.xml.soap.*; import javax.xml.messaging.*; import java.util.*; import java.io.*;The next few lines begin the definition of the class
MyUddiPing, which starts with the definition of itsmainmethod. The first thing it does is check to see if two arguments were supplied. If not, it prints a usage message and exits.public class MyUddiPing { public static void main(String[] args) { try { if (args.length != 2) { System.err.println("Usage: MyUddiPing " + "properties-file business-name"); System.exit(1); }The following lines create a
java.util.Propertiesfile that contains the system properties and the properties from the fileuddi.propertiesthat is in themyuddipingdirectory.Properties myprops = new Properties(); myprops.load(new FileInputStream(args[0])); Properties props = System.getProperties(); Enumeration it = myprops.propertyNames(); while (it.hasMoreElements()) { String s = (String) it.nextElement(); props.put(s, myprops.getProperty(s)); }The next four lines create a
SOAPMessageobject. First, the code gets an instance ofSOAPConnectionFactoryand uses it to create a connection. Then it gets an instance ofMessageFactoryand uses it to create a message.SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance(); SOAPConnection connection = scf.createConnection(); MessageFactory msgFactory = MessageFactory.newInstance(); SOAPMessage msg = msgFactory.createMessage();The new
SOAPMessageobjectmsgautomatically contains aSOAPPartobject that contains aSOAPEnvelopeobject. TheSOAPEnvelopeobject contains aSOAPBodyobject, which is the element you want to access in order to add content to it. The next lines of code get theSOAPPartobject, theSOAPEnvelopeobject, and theSOAPBodyobject.SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope(); SOAPBody body = envelope.getBody();The following lines of code add an element with a fully-qualified name and then add two attributes to the new element. The first attribute has the name
"generic"and the value"1.0". The second attribute has the name"maxRows"and the value"100". Then the code adds a child element with the namenameand adds some text to it with the methodaddTextNode. The text added is the business name you will supply when you run the application.SOAPBodyElement findBusiness = body.addBodyElement( envelope.createName("find_business", "", "urn:uddi-org:api")); findBusiness.addAttribute( envelope.createName("generic", "1.0"); findBusiness.addAttribute( envelope.createName("maxRows", "100"); SOAPElement businessName = findBusiness.addChildElement( envelope.createName("name")); businessName.addTextNode(args[1]);The next line of code creates the Java
Objectthat represents the destination for this message. It gets the value of the property named "URL" from the system property file.Object endpoint = System.getProperties().getProperty("URL");The following line of code saves the changes that have been made to the message. This method will be called automatically when the message is sent, but it does not hurt to call it explicitly.
msg.saveChanges();Next the message
msgis sent to the destination thatendpointrepresents, which is the test UDDI registry. The methodcallwill block until it gets aSOAPMessageobject back, at which point it returns the reply.SOAPMessage reply = connection.call(msg, endpoint);In the next two lines, the first prints out a line giving the URL of the sender (the test registry), and the second prints out the returned message as an XML document.
System.out.println("Received reply from: " + endpoint); reply.writeTo(System.out);The code thus far has been based on
UddiPing.java. The next section adds code to createMyUddiPing.java.Adding New Code
The code we are going to add to
UddiPingwill make the reply more user-friendly. It will get the content from certain elements rather than printing out the whole XML document as it was sent over the wire. Because the content is in theSOAPBodyobject, the first thing you need to do is access it, as shown in the following line of code. You can access each element in separate method calls, as was done in earlier examples, or you can access theSOAPBodyobject using this shorthand version.SOAPBody replyBody = reply.getSOAPPart().getEnvelope().getBody();Next you might print out two blank lines to separate your results from the raw XML message and a third line that describes the text that follows.
System.out.println(""); System.out.println(""); System.out.print( "Content extracted from the reply message: ");Now you can begin the process of getting all of the child elements from an element, getting the child elements from each of those, and so on, until you arrive at a text element that you can print out. Unfortunately, the registry used for this example code, being just a test registry, is not always consistent. The number of subelements sometimes varies, making it difficult to know how many levels down the code needs to go. And in some cases, there are multiple entries for the same company name. Note that by contrast, the entries in a standard valid registry will be consistent.
The code you will be adding drills down through the subelements within the SOAP body and retrieves the name and description of the business. The method you use to retrieve child elements is the
SOAPElementmethodgetChildElements. When you give this method no arguments, it retrieves all of the child elements of the element on which it is called. If you know theNameobject used to name an element, you can supply that togetChildElementsand retrieve only the children with that name. In this example, however, you need to retrieve all elements and keep drilling down until you get to the elements that contain text content.Here is the basic pattern that is repeated for drilling down:
Iterator iter1 = replyBody.getChildElements(); while (iter1.hasNext()) { SOAPBodyElement bodyElement = (SOAPBodyElement)iter1.next(); Iterator iter2 = bodyElement.getChildElements(); while (iter2.hasNext()) {The method
getChildElementsreturns the elements in the form of ajava.util.Iteratorobject. You access the child elements by calling the methodnexton theIteratorobject. The methodIterator.hasNextcan be used in awhileloop because it returnstrueas long as the next call to the methodnextwill return a child element. The loop ends when there are no more child elements to retrieve.An immediate child of a
SOAPBodyobject is aSOAPBodyElementobject, which is why callingiter1.nextreturns aSOAPBodyElementobject. Children ofSOAPBodyElementobjects and all child elements from there down areSOAPElementobjects. For example, the calliter2.nextreturns theSOAPElementobjectchild2. Note that the methodIterator.nextreturns anObject, which has to be narrowed (cast) to the specific kind of object you are retrieving. Thus, the result of callingiter1.nextis cast to aSOAPBodyElementobject, whereas the results of callingiter2.next,iter3.next, and so on, are allcast to aSOAPElementobject.Here is the code you add to access and print out the business name and description:
Iterator iter1 = replyBody.getChildElements(); while (iter1.hasNext()) { SOAPBodyElement bodyElement = (SOAPBodyElement)iter1.next(); Iterator iter2 = bodyElement.getChildElements(); while (iter2.hasNext()) { SOAPElement child2 = (SOAPElement)iter2.next(); Iterator iter3 = child2.getChildElements(); String content = child2.getValue(); System.out.println(content); while (iter3.hasNext()) { SOAPElement child3 = (SOAPElement)iter3.next(); Iterator iter4 = child3.getChildElements(); content = child3.getValue(); System.out.println(content); while (iter4.hasNext()) { SOAPElement child4 = (SOAPElement)iter4.next(); content = child4.getValue(); System.out.println(content); } } } } connection.close(); } catch (Exception ex) { ex.printStackTrace(); } } }You have already compiled
MyUddiPing.javaby calling the following at the command line:ant buildWith the code compiled, you are ready to run
MyUddiPing. The following command will calljavaon the.classfile forMyUddiPing, which takes two arguments. The first argument is the fileuddi.properties, which is supplied by a property set inbuild.xml. The second argument is the name of the business for which you want to get a description, and you need to supply this argument on the command line. Note that any property set on the command line overrides the value set for that property in thebuild.xmlfile. The last argument supplied toAntis always the target, which in this case isrun.cd <JWSDP_HOME>/samples/jaxm/myuddiping ant -Dbusiness-name="Oracle" runHere is the output that will appear after the full XML message. It is produced by the code added in
MyUddiPing.java.Content extracted from the reply message: Oracle oracle powers the internet Oracle Corporation Oracle Corporation provides the software and services for e- business.Running
Antwith Microsoft as thebusiness-nameproperty instead of Oracle produces the following output:Received reply from: http://www- 3.ibm.com/services/uddi/testregistry/inquiryapi <?xml version="1.0" encoding="UTF-8" ?><Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Body><busin essList generic="1.0" xmlns="urn:uddi-org:api" operator="www.ibm.com/services/uddi" truncated="false"><businessInfos><businessInfo businessKey="D7475060-BF58-11D5-A432- 0004AC49CC1E"><name>Microsoft Corporation</name><description xml:lang="en">Computer Software and Hardware Manufacturer</description><serviceInfos></serviceInfos></busin essInfo></businessInfos></businessList></Body></Envelope> Content extracted from the reply message: Microsoft Corporation Computer Software and Hardware ManufacturerSOAPFaultTest.java
The code
SOAPFaultTest.java, based on the code fragments in a preceding section (SOAP Faults) creates a message with aSOAPFaultobject. It then retrieves the contents of theSOAPFaultobject and prints them out. You will find the code forSOAPFaultTestin the following directory:<JWSDP_HOME>/docs/tutorial/examples/jaxm/fault/srcHere is the file
SOAPFaultTest.java.import javax.xml.soap.*; import java.util.*; public class SOAPFaultTest { public static void main(String[] args) { try { MessageFactory msgFactory = MessageFactory.newInstance(); SOAPMessage msg = msgFactory.createMessage(); SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope(); SOAPBody body = envelope.getBody(); SOAPFault fault = body.addFault(); fault.setFaultCode("Client"); fault.setFaultString( "Message does not have necessary info"); fault.setFaultActor("http://gizmos.com/order"); Detail detail = fault.addDetail(); Name entryName = envelope.createName("order", "PO", "http://gizmos.com/orders/"); DetailEntry entry = detail.addDetailEntry(entryName); entry.addTextNode( "quantity element does not have a value"); Name entryName2 = envelope.createName("confirmation", "PO", "http://gizmos.com/confirm"); DetailEntry entry2 = detail.addDetailEntry(entryName2); entry2.addTextNode("Incomplete address: no zip code"); msg.saveChanges(); // Now retrieve the SOAPFault object and its contents //after checking to see that there is one if ( body.hasFault() ) { fault = body.getFault(); String code = fault.getFaultCode(); String string = fault.getFaultString(); String actor = fault.getFaultActor(); System.out.println("SOAP fault contains: "); System.out.println(" fault code = " + code); System.out.println(" fault string = " + string); if ( actor != null) { System.out.println(" fault actor = " + actor); } detail = fault.getDetail(); if ( detail != null) { Iterator it = detail.getDetailEntries(); while ( it.hasNext() ) { entry = (DetailEntry)it.next(); String value = entry.getValue(); System.out.println(" Detail entry = " + value); } } } catch (Exception ex) { ex.printStackTrace(); } } }Running SOAPFaultTest
To run
SOAPFaultTest, you use the Ant filebuild.xmlthat is in the directory<JWSDP_HOME>/docs/tutorial/examples/jaxm/fault.This Ant file does many things for you, including creating a
builddirectory where class files will go, creating the classpath needed to runSOAPFaultTest, compilingSOAPFaulTest.java, putting the resulting.classfile in thebuilddirectory, and runningSOAPFaultTest.To run
SOAPFaultTest, do the following:
- Go to the directory where the appropriate
build.xmlfile is located.cd <JWSDP_HOME>/docs/tutorial/examples/jaxm/fault- At the command line, type the following:
ant prepare
- This will create the
builddirectory, the directory where class files will be put.- At the command line, type
ant build
- This will run
javaconSOAPFaultTest.javausing the classpath that has been set up in thebuild.xmlfile. The resulting.classfile will be put in thebuilddirectory created by the prepare target.- At the command line, type
ant run
- This will execute the command
java SOAPFaultTest.Note that as a shortcut, you can simply type
ant run. The necessary targets will be executed in the proper order because if a target indicates that it depends on one or more other targets, those will be executed before the specified target is executed. In this case, theruntarget depends on thebuildtarget, which in turn depends on thepreparetarget, so theprepare,build, andruntargets will be executed in that order. As an even faster shortcut, you can type justant. The default target for thisbuild.xml fileisrun, so it has the same effect as typingant run.If you want to run
SOAPFaultTestagain, it is a good idea to start over by deleting thebuilddirectory and the.classfile it contains. You can do this by typing the following at the command line:ant cleanAfter running
SOAPFaultTest, you will see something like this:Here is what the XML message looks like: <?xml version="1.0" encoding="UTF-8"?> <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/ soap/envelope/"><soap-env:Header/><soap-env:Body><soap-env: Fault><soap-env:faultcode>Client</soap-env:faultcode><soap- env:faultstring>Message does not have necessary info</soap- env:faultstring><soap-env:faultactor>http://gizmos.com/order </soap-env:faultactor><soap-env:Detail><PO:order xmlns:PO= "http://gizmos.com/orders/">quantity element does not have a value</PO:order><PO:confirmation xmlns:PO="http://gizmos.com/ confirm">Incomplete address: no zip code</PO:confirmation> </soap-env:Detail></soap-env:Fault></soap-env:Body></soap-env: Envelope> Here is what the SOAP fault contains: fault code = Client fault string = Message does not have necessary info fault actor = http://gizmos.com/order Detail entry = quantity element does not have a value Detail entry = Incomplete address: no zip codeConclusion
JAXM provides a Java API that simplifies writing and sending XML messages. You have seen how to use this API to write client code for JAXM request-response messages and one-way messages. You have also seen how to get the content from a reply message. This knowledge was applied in writing and running the
MyUddiPingandSOAPFaultTestexamples. In addition, the case study (The Coffee Break Application) provides detailed examples of JAXM code for both the client and server.You now have first-hand experience of how JAXM makes it easier to do XML messaging.
|
Home
TOC Index |
|
This tutorial contains information on the 1.0 version of the Java Web Services Developer Pack.
All of the material in The Java Web Services Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.