A SOAP Example in Java

You can use SOAP with Java by using Web services, but doing so is more advanced than the Java work you've already seen in this book. In this example, you're going to use Java servlets on a Web server. For this example you'll use two servlets—one that sends the SOAP message and one that receives that message. The receiving servlet will decode the data in the SOAP message and return a new SOAP message indicating that it has understood.

You need a Web server that can run Java servlets for this example. The Tomcat server is the premier Web server for JavaServer Pages and servlets; you can download it from http://jakarta.apache.org/tomcat/. Downloading and installing Tomcat is not difficult; just use the installation directions that come with Tomcat. After you have Tomcat installed and running, navigate to http://localhost:8080/index.html, and you should see Tomcat running, as in Figure 18.1.

18fig01.jpg

Figure 18.1 Getting the Tomcat server running.

To support Web services, you also need some additional Java packages. There are two options when you're using SOAP with Java—you can download the Java XML pack, which is at (as of this writing) http://java.sun.com/xml/downloads/javaxmlpack.html, or you can download the Java Web Services Developer's Pack, which is at (as of this writing) http://java.sun.com/webservices/webservicespack.html. It's easiest to download the Java XML pack, which is a simple zipped file that holds the JAR files you'll need: jaxm-api.jar, saaj-api.jar, andactivation.jar. You also need servlet.jar to create servlets, and this file comes with Tomcat, in the lib directory.

There's another step you need to take at this point: You need to set up Tomcat to work with Java XML Messaging (JAXM). You should stop Tomcat if it's running and copy jaxm-docs.war, which comes with the Java XML Pack or the Java Web Services Developer's Pack, to the Tomcat webapps directory, and then you can restart Tomcat and navigate to http://localhost:8080/jaxm-docs/tomcat.html for directions. Setting up Tomcat for JAXM simply involves copying some JAR (Java archive) and WAR (Web archive) files.

With Tomcat set up, you're ready to write the two SOAP servlets you're going to use today: the server, ch18_04, and the client, ch18_05. For this example, you'll start by opening a new Web page, ch18_06.html, that has a link in it to the server servlet, ch18_04. When that link is clicked, the server will send a SOAP message to the client servlet, indicating how many laptops you have in stock, and the client servlet will then send back an acknowledging SOAP message. The actual SOAP messages will also be written to file so you can see what the two servlets sent each other. You'll start by creating the server servlet, ch18_04.

Creating the Server

The first servlet will create and send a SOAP message indicating that you have 216 laptops available. You start by creating a SOAP connection object named connection:

package soapExample;

import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.xml.soap.*;
import javax.activation.*;
import javax.servlet.http.*;

public class ch18_04 extends HttpServlet
{
    private SOAPConnection connection;

    public void init(ServletConfig servletConfig) throws ServletException
    {
        super.init(servletConfig);

        try {

           SOAPConnectionFactory connectionFactory =

                       SOAPConnectionFactory.newInstance();

               connection = connectionFactory.createConnection();

           } catch(Exception e) {}
    }

When the servlet is called, its doGet method will be executed, and that's the method where most of your code will go. Here, you create a MessageFactory object and a SOAP message:

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException
{
    String outString ="<HTML><H1>Sending and reading the SOAP Message</H1><P>";

    try {

           MessageFactory messageFactory = MessageFactory.newInstance();

           SOAPMessage outgoingMessage = messageFactory.createMessage();
        .
        .
        .

Create the parts of the message, including the envelope, header, and body, like this:

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException
{
    String outString ="<HTML><H1>Sending and reading the SOAP Message</H1><P>";

    try {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage outgoingMessage = messageFactory.createMessage();

        SOAPPart soappart = outgoingMessage.getSOAPPart();

           SOAPEnvelope envelope = soappart.getEnvelope();

           SOAPHeader header = envelope.getHeader();

           SOAPBody body = envelope.getBody();
    .
    .
    .

Now you add an element named <laptops:numberAvailable> to the SOAP message's body and indicate that there are 216 laptops available, like this:

body.addBodyElement(envelope.createName("numberAvailable", "laptops",
"http://www.XMLPowerCorp.com")).addTextNode("216");

You can also add attachments to SOAP messages, which you'll do next. In this case, you'll send a text attachment. A handy text file is the ch18_06.html document that you browse to in order to run this example, and here's how to attach it to the SOAP message:

StringBuffer serverUrl = new StringBuffer();
serverUrl.append(request.getScheme()).append("://")
    .append(request.getServerName());
serverUrl.append(":").append(request.getServerPort())
    .append(request.getContextPath());
String baseUrl = serverUrl.toString();
URL url = new URL(baseUrl + "/ch18_06.html");

AttachmentPart attachmentpart =
    outgoingMessage.createAttachmentPart(new DataHandler(url)) ;
attachmentpart.setContentType("text/html");
outgoingMessage.addAttachmentPart(attachmentpart) ;

Now you will write our SOAP message to a file, out.msg, so you can look at it later and send that message to the client:

URL client = new URL(baseUrl + "/ch18_05");

FileOutputStream outgoingFile = new FileOutputStream("out.msg");
outgoingMessage.writeTo(outgoingFile);
outgoingFile.close();

outString += "SOAP outgoingMessage sent (see out.msg). <BR>";

SOAPMessage incomingMessage = connection.call(outgoingMessage, client);

The SOAP message you get back from the client, which should acknowledge that there are 216 laptops available, is in the incomingMessage object, which you write to the file in.msg so you can take a look at it later:

if (incomingMessage != null) {
    FileOutputStream incomingFile = new FileOutputStream("in.msg");
    incomingMessage.writeTo(incomingFile);
    incomingFile.close();
    outString += "SOAP outgoingMessage received (see in.msg).</HTML>";
}
    .
    .
    .

That completes the server, which is your ch18_04 servlet. The server's code, ch18_04.java, is shown in Listing 18.4.

Example 18.4. SOAP Server (ch18_04.java)

package soapExample;

import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.xml.soap.*;
import javax.activation.*;
import javax.servlet.http.*;

public class ch18_04 extends HttpServlet
{
    private SOAPConnection connection;

    public void init(ServletConfig servletConfig) throws ServletException
    {
        super.init(servletConfig);

        try {
        SOAPConnectionFactory connectionFactory =
                    SOAPConnectionFactory.newInstance();
            connection = connectionFactory.createConnection();
        } catch(Exception e) {}
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException
    {
        String outString =
            "<HTML><H1>Sending and reading the SOAP Message</H1><P>";

        try {
            MessageFactory messageFactory = MessageFactory.newInstance();
            SOAPMessage outgoingMessage = messageFactory.createMessage();

            SOAPPart soappart = outgoingMessage.getSOAPPart();
            SOAPEnvelope envelope = soappart.getEnvelope();
            SOAPHeader header = envelope.getHeader();
            SOAPBody body = envelope.getBody();

            body.addBodyElement(envelope.createName("numberAvailable",
            "laptops",
            "http://www.XMLPowerCorp.com")).addTextNode("216");

            StringBuffer serverUrl = new StringBuffer();
            serverUrl.append(request.getScheme()).append("://").
                append(request.getServerName());
            serverUrl.append(":").append(request.getServerPort()).
                append(request.getContextPath());
            String baseUrl = serverUrl.toString();
            URL url = new URL(baseUrl + "/ch18_06.html");

            AttachmentPart attachmentpart = outgoingMessage.
                createAttachmentPart(new DataHandler(url));
            attachmentpart.setContentType("text/html");
            outgoingMessage.addAttachmentPart(attachmentpart);

            URL client = new URL(baseUrl + "/ch18_05");

            FileOutputStream outgoingFile = new FileOutputStream("out.msg");
            outgoingMessage.writeTo(outgoingFile);
            outgoingFile.close();

            outString += "SOAP outgoingMessage sent (see out.msg). <BR>";

            SOAPMessage incomingMessage = connection.
                call(outgoingMessage, client);

            if (incomingMessage != null) {
                FileOutputStream incomingFile = new FileOutputStream("in.msg");
                incomingMessage.writeTo(incomingFile);
                incomingFile.close();
                outString +=
                    "SOAP outgoingMessage received (see in.msg).</HTML>";
            }

        } catch(Throwable e) {}

        try {
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(outString.getBytes());
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {}
    }
}

Creating the Client

The next step is to create the client, the ch18_05 servlet, which gets the server's SOAP message, interprets it, and sends a message back, indicating that it has understood the incoming message. Start by basing this servlet on the JAXMServlet class so that it can handle SOAP messages and creating a MessageFactory object so you can send SOAP messages:

package soapExample;

import java.util.*;
import javax.servlet.*;
import javax.xml.soap.*;
import javax.servlet.http.*;
import javax.xml.messaging.*;

public class ch18_05 extends JAXMServlet implements ReqRespListener
{
    static MessageFactory messageFactory = null;

    public void init(ServletConfig servletConfig) throws ServletException
    {
        super.init(servletConfig);

           try {

               messageFactory = MessageFactory.newInstance();

           } catch (Exception ex) {}
    }
        .
        .
        .

Now you can decipher the incoming SOAP message by getting the value of the <laptops:numberAvailable> element and storing it in a variable named element, like this:

public SOAPMessage onMessage(SOAPMessage msg)
{
    try {

           SOAPPart soappart = msg.getSOAPPart();

           SOAPEnvelope incomingEnvelope = soappart.getEnvelope();

           SOAPBody body = incomingEnvelope.getBody();


           Iterator iterator = body.getChildElements(

           incomingEnvelope.createName("numberAvailable", "laptops",

               "http://www.XMLPowerCorp.com"));


           SOAPElement element;

           element = (SOAPElement) iterator.next();
        .
        .
        .

The number of laptops left in stock can now be accessed with element.getValue(), and here's how to create a SOAP message to send back to the server, indicating that you've gotten that data:


               SOAPMessage message = messageFactory.createMessage();

               SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();


               envelope.getBody().addChildElement(envelope.

                   createName("Response")).addTextNode(

                   "Got the SOAP message indicating there are " +

                   element.getValue() +

                   " laptops available."

               );
        .
        .
        .
}

Finally, send the new SOAP message that acknowledges the number of laptops back to the client by returning the new message, which automatically sends it back to the server servlet, ch18_04, as you can see in ch18_05.java, the SOAP client, in Listing 18.5.

Example 18.5. A SOAP Client (ch18_05.java)

package soapExample;

import java.util.*;
import javax.servlet.*;
import javax.xml.soap.*;
import javax.servlet.http.*;
import javax.xml.messaging.*;

public class ch18_05 extends JAXMServlet implements ReqRespListener
{
    static MessageFactory messageFactory = null;

    public void init(ServletConfig servletConfig) throws ServletException
    {
        super.init(servletConfig);
        try {
            messageFactory = MessageFactory.newInstance();
        } catch (Exception ex) {}
    }

    public SOAPMessage onMessage(SOAPMessage msg)
    {
        try {
            SOAPPart soappart = msg.getSOAPPart();
            SOAPEnvelope incomingEnvelope = soappart.getEnvelope();
            SOAPBody body = incomingEnvelope.getBody();

            Iterator iterator = body.getChildElements(
            incomingEnvelope.createName("numberAvailable", "laptops",
                "http://www.XMLPowerCorp.com"));

            SOAPElement element;
            element = (SOAPElement) iterator.next();

            SOAPMessage message = messageFactory.createMessage();
            SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();

            envelope.getBody().addChildElement(envelope
                .createName("Response")).addTextNode(
                "Got the SOAP message indicating there are " +
                    element.getValue() +
                " laptops available."
            );

            return message;
        } catch(Exception e) {return null;}
    }
}

To compile these new servlets, ch18_04.java and ch18_05.java, you need to have servlet.jar, jaxm-api.jar, saaj-api.jar, and activation.jar in the Java classpath environment variable. For example, if those JAR files are in the same directory as ch18_04.java and ch18_05.java, here's what this looks like:

%set classpath=servlet.jar;jaxm-api.jar;saaj-api.jar;activation.jar
%javac ch18_04.java
%javac ch18_05.java

If the JAR files are in the same directory as ch18_04.java and ch18_05.java, you need to make sure to preface every JAR file filename with its correct path.

This gives you the compiled files you need, ch18_04.class and ch18_05.class. How can you run the server, ch18_04.class? Here, you'll use an HTML document, ch18_06.html, to call the ch18_04.class servlet by using a hyperlink. Listing 18.6 shows how this HTML document works. When the user clicks the hyperlink, the server servlet is called, the server servlet sends a SOAP message to the client servlet, and the client servlet returns a SOAP message to the server.

Example 18.6. The SOAP Example Introduction Page (ch18_06.html)

<HTML>
    <HEAD>
        <TITLE>SOAP and Java</TITLE>
    </HEAD>

    <BODY>
        <H1>SOAP and Java</H1>

           Click <A HREF="ch18_04">here</a> to send the SOAP message.
    </BODY>
</HTML>

Now you need to install all that you've done in the Tomcat server. To do that, begin by creating a file named web.xml that will tell Tomcat about the ch18_04.class and ch18_05.class files so that you can use those files with Tomcat. Here's what web.xml looks like:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>
    <servlet>
        <servlet-name>
            ch18_04
        </servlet-name>
        <servlet-class>
            soapExample.ch18_04
        </servlet-class>
    </servlet>

    <servlet>
        <servlet-name>
            ch18_05
        </servlet-name>
        <servlet-class>
            soapExample.ch18_05
        </servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>
            ch18_04
        </servlet-name>
        <url-pattern>
            /ch18_04
        </url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>
            ch18_05
        </servlet-name>
        <url-pattern>
            /ch18_05
        </url-pattern>
    </servlet-mapping>
</web-app>

Now that you have all the files you'll need, you can install them in the Tomcat webapps directory in order to make them available through the Tomcat server. You'll install these files in a directory named JavaSoap and place your actual servlet code in a directory named soapExample (which is the Java package for those servlets). Here's what the completed directory structure looks like:

webapps [This is a directory]
|____JavaSoap [This is a directory]
     |____ch18_06.html [Our starting Web page]
     |____WEB-INF [This is a directory]
          |____web.xml [Configures Tomcat]
          |____classes [This is a directory]
               |____soapExample [This is a directory]
                    |____ch18_04.class [The server servlet]
                    |____ch18_05.class [The client servlet]

After you copy these files as shown here, start Tomcat (or if it was already started, stop it and start it again). Now all you need to do is navigate a browser to http://localhost:8080/soap/ch18_06.html, as shown in Figure 18.2.

18fig02.gif

Figure 18.2 The Java SOAP example's opening page.

Now click the hyperlink shown in Figure 18.2 in order to call the server servlet, which sends the first SOAP message, stating the number of laptops available in stock, to the client servlet, which sends back an acknowledgement. Figure 18.3 shows the results of calling the server servlet.

18fig03.gif

Figure 18.3 The results of the Java SOAP example.

What does the SOAP message sent from the server to the client look like? You can see it in the file out.msg, which is written to the Tomcat bin directory. Note that out.msg contains not only your SOAP message, but also the attached text, ch18_06.html:

------=_Part_4_6912871.1056396066449
Content-Type: text/xml

<?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>
        <laptops:numberAvailable
            xmlns:laptops="http://www.XMLPowerCorp.com">
            216
        </laptops:numberAvailable>
    </soap-env:Body>
</soap-env:Envelope>
------=_Part_4_6912871.1056396066449
Content-Type: text/html

<HTML>
    <HEAD>
        <TITLE>SOAP and Java</TITLE>
    </HEAD>

    <BODY>
        <H1>SOAP and Java</H1>
        Click <A HREF="ch18_04">here</a> to send the SOAP message.
    </BODY>
</html>

------=_Part_4_6912871.1056396066449--

Here's what the SOAP message the client sent back to the server, as the code stored in in.msg, looks like (note that the client is acknowledging the data the server sent):

<?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>
        <Response>
            Got the SOAP message indicating there are 216 laptops available.
        </Response>
    </soap-env:Body>
</soap-env:Envelope>

In this example you've been able to send, interpret, and reply to a SOAP message in Java. You've taken a look at programming examples in both .NET and Java now, and as you can see, both packages give SOAP support. You've just scratched the surface so far—covering the uses of SOAP can take whole books—but you have an idea what SOAP is good for from what you've seen. We'll turn now to RDF.

+ Share This