среда, 20 июля 2011 г.

simple webservice call from groovy

This is a method of fast and simple webservice call using groovy.

Prerequisites:
Java 6
Groovy 1.7.5
Log4j (you can comment it out from code)
SoapUI (or other tool that could call webservice and show the request and response)

Idea and call example:
//Next line ignores all SSL restrictions when working with HTTPS
//Comment it if SSL certificates must be checked
WSCallout.trustAll();

//the endpoint of your service (could be loa=cated in wsdl)
String endpoint="https://esb-test:8243/services/echo.echoHttpsSoap11Endpoint";
//Usernametoken authentication (null if the service does not require it)
def auth = WSCallout.getUsernameToken("admin","FooPass");
//Soap action (unique operation name) could be located in wsdl
String action="urn:echoString";
//Payload of the message
def payload = XML.builder()."echo:echoString"("xmlns:echo":"http://test"){
    "in" ("fooooo-data")
};
/*
At his moment payload will contain the following XML in groovy.util.Node:


    fooooo-data

*/

//Now call web service and get a result in groovy.util.Node
def result = WSCallout.callSoap11(endpoint, payload, auth, action);

//print the result
println( XML.toString( result ) );


The groovy class to do that:
/**
 * web service caller
 */
package groovy.abi; 
//import javax.xml.namespace.*
import javax.xml.ws.*
import javax.xml.soap.*;
import java.net.HttpURLConnection;
//TRUST ALL
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
import java.security.SecureRandom;
import javax.net.ssl.KeyManagerFactory;

import org.apache.log4j.Logger;
import org.apache.log4j.Level;

public class WSCallout{

    public static groovy.util.Node callSoap11(endpointUrl,payload,headers,action,throwFault=true,timeout=40000,Logger logger=null){
        groovy.util.NodeBuilder builder = groovy.util.NodeBuilder.newInstance();
        def envelop = builder."soapenv:Envelope"("xmlns:soapenv": "http://schemas.xmlsoap.org/soap/envelope/") {
            "soapenv:Header"()
            "soapenv:Body"()
        };
        def msgId=Integer.toHexString(payload.hashCode());
        if(headers!=null)envelop["soapenv:Header"][0].append(headers);
        if(payload!=null)envelop["soapenv:Body"][0].append(payload);
        if(logger!=null) {
            if(logger.isEnabledFor(Level.TRACE)){
                logger.trace("WSCallout.send msgId::="+msgId+" envelop::="+XML.toString(envelop));
            }else if(logger.isDebugEnabled()){
                logger.debug("WSCallout.send msgId::="+msgId+" body::="+XML.toString(payload));
            }
        }
        def method = action;
        if(method==null || method.trim().length()==0){
            method = XML.localName(payload);
        }
        if(method==null || method.trim().length()==0){
            method = "undefined";
        }
        try {
            HttpURLConnection conn = (new URL(endpointUrl)).openConnection();
            conn.setConnectTimeout(3000);
            conn.setReadTimeout(timeout);
            conn.addRequestProperty("Content-Type","text/xml;charset=UTF-8");
            conn.addRequestProperty("Accept","text/xml");
            if(action!=null)conn.addRequestProperty("SOAPAction",'"'+action+'"');
            conn.setDoOutput(true);
            
            ByteArrayOutputStream baos=new ByteArrayOutputStream();
            groovy.xml.XmlUtil.serialize(envelop,baos);
            conn.setFixedLengthStreamingMode( baos.size() );
            
            OutputStream ost = conn.getOutputStream();
            ost.write(     baos.toByteArray() );
            
            ost.flush(); 
            // Get the response
            def statusCode = conn.getResponseCode();
            InputStream ist=null;
            try{
                ist=conn.getInputStream();
            }catch(java.io.IOException e){
                try{
                    ist=conn.getErrorStream();
                }catch(Exception){}
                if(ist==null)throw new SOAPException("IO Error receiving data from server: "+e.getMessage(),e);
            }
            groovy.util.XmlParser parser = new XmlParser();
            byte[] resp=ist.getBytes();
            ost.close();
            ist.close();
            try{
                envelop = parser.parse(new java.io.ByteArrayInputStream(resp));
            }catch(Exception e){
                throw new java.text.ParseException("Expected soap envelop as response for "+method+", but received: \n"+new String(resp,"UTF-8"),-1 );
            }
        } catch (java.net.SocketTimeoutException e) {
            throw new java.io.IOException("Failed to call remote service \""+method+"\" in "+(timeout/1000)+" seconds.",e);
        }
        
        def soapenv = new groovy.xml.Namespace("http://schemas.xmlsoap.org/soap/envelope/", "soapenv");
        def body =  envelop[soapenv.Body][0];
        if(body==null)throw new java.text.ParseException("Expected soap envelop as response for "+method+", but received: \n"+XML.toString(envelop),-1 );
        payload = body.children()[0];
        
        if(logger!=null) {
            if(logger.isEnabledFor(Level.TRACE)){
                logger.trace("WSCallout.recv msgId::="+msgId+" envelop::="+XML.toString(envelop));
            }else if(logger.isDebugEnabled()){
                logger.debug("WSCallout.recv msgId::="+msgId+" body::="+XML.toString(payload));
            }
        }
        
        if( throwFault && payload.name().equals( new groovy.xml.QName("http://schemas.xmlsoap.org/soap/envelope/","Fault") ) ){
            def msg=payload["faultstring"].text();
            throw new SOAPException("Remote service ["+method+"] error: "+msg);
        }
        return payload;
    }
    
    public static groovy.util.Node getUsernameToken(String user,String pass){
        groovy.util.NodeBuilder builder = groovy.util.NodeBuilder.newInstance();
        def id="UT-"+Long.toHexString( System.currentTimeMillis() );
        def header = builder."wsse:Security"("xmlns:wsse":"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd") {
            "wsse:UsernameToken"( "wsu:Id":id, "xmlns:wsu":"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" ) {
                "wsse:Username" ( user )
                "wsse:Password" ( Type:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText", pass )
            }
        };
    
    }
    
    public static groovy.util.Node getUsernameToken2002(String user,String pass){
        groovy.util.NodeBuilder builder = groovy.util.NodeBuilder.newInstance();
        def id="UT-"+Long.toHexString( System.currentTimeMillis() );
        def header = builder."wsse:Security"("xmlns:wsse":"http://schemas.xmlsoap.org/ws/2002/07/secext") {
            "wsse:UsernameToken" {
                "wsse:Username" ( user )
                "wsse:Password" ( Type:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText", pass )
            }
        };
    
    }
    
    
    public static String getSoap11Fault(obj){
        String msg;
        String details="";
        if(obj instanceof String){
            msg=obj;
        }else if(obj instanceof Throwable){
            msg=obj.getMessage();
            if(msg==null||msg.trim().length()==0||"null".equalsIgnoreCase(msg))msg=""+obj;
            for(StackTraceElement i in obj.getStackTrace()){
                if(i.getFileName()?.matches(".*\\.groovy")){
                    details=(details.length()==0?'':details+"\r\n\t\t")+i.getMethodName()+" "+i.getFileName()+":"+i.getLineNumber();
                }
            }
        }else{
            msg=""+obj;
        }
        def builder = groovy.util.NodeBuilder.newInstance();
        def body = builder."soapenv:Fault"("xmlns:soapenv": "http://schemas.xmlsoap.org/soap/envelope/") {
            "faultcode"   ("soapenv:Server")
            "faultstring" (msg)
            "detail"      (details)
        };
        return groovy.xml.XmlUtil.serialize(body);
        
    }
    
    
    private static HostnameVerifier allowAllHostsVerifier = new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    return true;
                }
            };

    
    
    public static void allowAllHosts(con){
        if(con instanceof HttpsURLConnection){
            con.setHostnameVerifier(allowAllHostsVerifier);
        }
    }
    
    //TRUST ALL
    private static TrustManager[] trustAllCerts = null;
    
    public static void trustAll() {
        try {
            HttpsURLConnection.setDefaultHostnameVerifier(allowAllHostsVerifier);
            //init certificates
            if( trustAllCerts==null ){
                trustAllCerts=new TrustManager[1];
                trustAllCerts[0] = new X509TrustManager() {
                        public void checkClientTrusted( final X509Certificate[] chain, final String authType ) {}
                        public void checkServerTrusted( final X509Certificate[] chain, final String authType ) {}
                        public X509Certificate[] getAcceptedIssuers() {return null;}
                    } ;            
            }
            
            
            //KeyManagerFactory kmf=
            SSLContext sslContext = SSLContext.getInstance( "TLS" );
            sslContext.init( null, trustAllCerts, new java.security.SecureRandom() );
            SSLSocketFactory sslSockFact=sslContext.getSocketFactory();
            HttpsURLConnection.setDefaultSSLSocketFactory(sslSockFact);
        } catch(Exception e) {
            throw new IllegalStateException(e.getMessage());
        }
    }
    
}

public class XML{
    public static String toString(groovy.util.Node node){
        if(node==null)return null;
        return groovy.xml.XmlUtil.serialize(node);
    }
    
    public static void toStream(groovy.util.Node node, java.io.OutputStream os){
        groovy.xml.XmlUtil.serialize(node, os);
    }
    
    public static groovy.util.NodeBuilder builder(){
        return groovy.util.NodeBuilder.newInstance();
    }
    
    public static groovy.util.Node parse(java.io.InputStream stream){
        return new groovy.util.XmlParser().parse(stream);
    }
    
    public static groovy.util.Node parse(String uri){
        return new groovy.util.XmlParser().parse(uri);
    }
    
    public static groovy.util.Node parseText(String s){
        return new groovy.util.XmlParser().parseText(s);
    }
    
    public static groovy.xml.Namespace ns(String uri, String prefix){
        return new groovy.xml.Namespace(uri, prefix);
    }
    
    public static groovy.xml.Namespace ns(String uri){
        return new groovy.xml.Namespace(uri);
    }
    
    public static groovy.xml.Namespace ns(groovy.util.Node node){
        if( node.name() instanceof groovy.xml.QName ){
            return new groovy.xml.Namespace( node.name().getNamespaceURI(), node.name().getPrefix() );
        }
        return new groovy.xml.Namespace();
    }
    
    public static String localName(groovy.util.Node node){
        def name=node.name();
        if(name instanceof String){
            return name.replaceFirst(".*:(.*)","\$1");
        }else if(name instanceof groovy.xml.QName){
            return name.getLocalPart();
        }
        return null;
    }
}