Sunday, October 27, 2013

I'm relative new to the webservices world and my research seems to have confused me more than enlighten me, my problem is that I was given a library(jar) which I have to extend with some webservice functionality.
This library will be shared to other developers, and among the classes in the jar will be classes that have a method which calls a webservice (that essentially sets an attribute of the class, does some business logic, like storing the object in a db, etc and sends back the object with those modifications). I want to make the call to this service as simple as possible, hopefully as simple so that the developer using the class only need to do.
Car c = new Car("Blue");
c.webmethod();
I have been studying JAX-WS to use on the server but seems to me that I don't need to create awsimport in the server nor the wsimport on the client, since I know that both have the classes, I just need some interaction between classes shared in both the server and the client. How do you think makes sense to do the webservice and the call in the class?
share|improve this question
 
Your question is a bit unclear. The method you want to create will (1) get the object from the web service; (2) work with the object a little; and (3) post it back to the web service. Is that it? –  acdcjunior Apr 11 at 3:36
 
No, the object will be created in the client, it will be sent to the ws in the call, the ws will set a variable, for example currentTime, do some business logic like to store it in a db, and then sent the object back to the client with the currentTime now set. Hope I explained my self a little better. Thank you. –  jpz Apr 11 at 4:57
up vote24down voteaccepted
I understand your problem is how to call a SOAP (JAX-WS) web service from Java and get it's returning object. In that case, you have two possible approaches:
    • Generate the Java classes through wsimport and use them; or
    • Create a SOAP client that:
      1. Serializes the object to XML;
      2. Calls the web method through HTTP manipulation; and
      3. Parse the returning XML response back into an object.
About the first approach (using wsimport):
I understand that you already have the services' (entities or other) business classes and that thewsimport generates a whole new set of classes (that are somehow duplicates of the classes you already have).
I'm afraid, though, in this scenario, you can only either:
  • Adapt (edit) the wsimport generated code to make it use your business classes (this is difficult and somehow not worth it - bear in mind everytime the WSDL changes, you'll have to regenerate and readapt the code); or
  • Give up and use the wsimport generated classes.
About the second approach (create your custom SOAP client):
In order to implement the second approach, you'll have to:
    • Make the call:
      • Use the SAAJ (SOAP with Attachments API for Java) framework (see below, it's shipped with JSE 1.6) to make the calls; or
      • You can also do it through java.net.HttpUrlconnection (and some java.iohandling).
    • Turn the objects into XML and vice-versa:
      • Use an OXM (Object to Xml Mapping) framework such as JAXB to serialize/deserialize the XML from/into objects
      • Or, if you must, manually create/parse the XML (this can be the best solution if the received object is only a little bit differente from the sent one).
Creating a SOAP client using classic java.net.HttpUrlConnection is not that hard (but not that simple either), and you can find in this link a very good starting code.
I recomment you use the SAAJ framework:
SOAP with Attachments API for Java (SAAJ) is mainly used for dealing directly with SOAP Request/Response messages which happens behind the scenes in any Web Service API. It allows the developers to directly send and receive soap messages instead of using JAX-WS.
See below a working example (run it!) of a SOAP web service call using SAAJ. It calls this web service.
import javax.xml.soap.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class SOAPClientSAAJ {

    /**
     * Starting point for the SAAJ - SOAP Client Testing
     */
    public static void main(String args[]) {
        try {
            // Create SOAP Connection
            SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
            SOAPConnection soapConnection = soapConnectionFactory.createConnection();

            // Send SOAP Message to SOAP Server
            String url = "http://ws.cdyne.com/emailverify/Emailvernotestemail.asmx";
            SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(), url);

            // Process the SOAP Response
            printSOAPResponse(soapResponse);

            soapConnection.close();
        } catch (Exception e) {
            System.err.println("Error occurred while sending SOAP Request to Server");
            e.printStackTrace();
        }
    }

    private static SOAPMessage createSOAPRequest() throws Exception {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage soapMessage = messageFactory.createMessage();
        SOAPPart soapPart = soapMessage.getSOAPPart();

        String serverURI = "http://ws.cdyne.com/";

        // SOAP Envelope
        SOAPEnvelope envelope = soapPart.getEnvelope();
        envelope.addNamespaceDeclaration("example", serverURI);

        /*
        Constructed SOAP Request Message:
        
            
            
                
                    mutantninja@gmail.com
                    123
                
            
        
         */

        // SOAP Body
        SOAPBody soapBody = envelope.getBody();
        SOAPElement soapBodyElem = soapBody.addChildElement("VerifyEmail", "example");
        SOAPElement soapBodyElem1 = soapBodyElem.addChildElement("email", "example");
        soapBodyElem1.addTextNode("mutantninja@gmail.com");
        SOAPElement soapBodyElem2 = soapBodyElem.addChildElement("LicenseKey", "example");
        soapBodyElem2.addTextNode("123");

        MimeHeaders headers = soapMessage.getMimeHeaders();
        headers.addHeader("SOAPAction", serverURI  + "VerifyEmail");

        soapMessage.saveChanges();

        /* Print the request message */
        System.out.print("Request SOAP Message = ");
        soapMessage.writeTo(System.out);
        System.out.println();

        return soapMessage;
    }

    /**
     * Method used to print the SOAP Response
     */
    private static void printSOAPResponse(SOAPMessage soapResponse) throws Exception {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        Source sourceContent = soapResponse.getSOAPPart().getContent();
        System.out.print("\nResponse SOAP Message = ");
        StreamResult result = new StreamResult(System.out);
        transformer.transform(sourceContent, result);
    }

}
(The code above was taken and adapted from this page.)
About using JAXB for serializing/deserializing, it is very easy to find information about it. You can start here: http://www.mkyong.com/java/jaxb-hello-world-example/.
share|improve this answer