org.paxml.bean.SoapTag.java Source code

Java tutorial

Introduction

Here is the source code for org.paxml.bean.SoapTag.java

Source

/**
 * This file is part of PaxmlCore.
 *
 * PaxmlCore is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * PaxmlCore is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with PaxmlCore.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.paxml.bean;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.stream.XMLStreamException;

import org.apache.axiom.om.OMDocument;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.paxml.annotation.Tag;
import org.paxml.core.Context;
import org.paxml.core.ObjectTree;
import org.paxml.core.PaxmlRuntimeException;
import org.paxml.util.AxiomUtils;
import org.paxml.util.Elements;

/**
 * Soap tag impl.
 * 
 * @author Xuetao Niu
 * 
 */
@Tag(name = "soap")
public class SoapTag extends BeanTag {
    /**
     * SOAP envelope namespace.
     */
    public static final String SOAP_NS = "http://schemas.xmlsoap.org/soap/envelope/";
    /**
     * Number of retries for http.
     */
    public static final int RETRY = 3;

    private String url;
    private boolean responseless = false;
    private Map headers;
    private Object body;
    private String targetNamespace;

    /**
     * {@inheritDoc}
     */
    @Override
    protected Object doInvoke(Context context) throws Exception {

        HttpClient client = new HttpClient();
        PostMethod method = new PostMethod(url);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        write(out);

        // method.setRequestHeader(headerName, headerValue);
        method.setRequestBody(out.toString("UTF-8"));
        method.setRequestHeader("Content-Type", "text/xml;charset=UTF-8");
        if (headers != null) {
            Map<?, ?> hd = (Map<?, ?>) this.headers;
            for (Map.Entry<?, ?> entry : hd.entrySet()) {
                Object obj = entry.getValue();
                if (obj != null) {
                    method.setRequestHeader(entry.getKey().toString(), obj.toString());
                }
            }
        }

        // Provide custom retry handler is necessary
        method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler(RETRY, false));

        // method.setr
        try {
            // Execute the method.
            int statusCode = client.executeMethod(method);

            if (statusCode != HttpStatus.SC_OK) {
                throw new PaxmlRuntimeException("Http post failed: " + method.getStatusLine());
            }

            // Read the response body.
            byte[] responseBody = method.getResponseBody();

            // Deal with the response.
            // Use caution: ensure correct character encoding and is not binary
            // data
            return read(new ByteArrayInputStream(responseBody));
        } finally {
            // Release the connection.
            method.releaseConnection();
        }
    }

    private String getWsdlUrl() {
        return url + "?WSDL";
    }

    private String detectTargetNamespace() {
        InputStream in = null;
        try {
            in = new URL(getWsdlUrl()).openStream();
            OMElement root = AxiomUtils.getRootElement(in);
            if (root != null) {
                String ns = AxiomUtils.getAttribute(root, "targetNamespace");
                return StringUtils.isNotBlank(ns) ? ns : null;
            }
            return null;
        } catch (Exception e) {
            return null;
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    private Object read(InputStream in) throws IOException, XMLStreamException {
        if (responseless) {
            return null;
        }
        OMElement root = AxiomUtils.getRootElement(in);
        OMElement bd = AxiomUtils.getFirstChildElement(root, "Body");

        OMElement ele = bd.getFirstElement();
        if (SOAP_NS.equals(ele.getNamespaceURI())) {
            OMElement code = AxiomUtils.getFirstChildElement(ele, "faultcode");
            OMElement string = AxiomUtils.getFirstChildElement(ele, "faultstring");
            throw new PaxmlRuntimeException("Soap fault code (" + code == null ? " "
                    : code.getText() + "): " + string == null ? "" : string.getText());
        }
        return fromXml(ele.getFirstElement());

    }

    private void write(OutputStream out) throws IOException, XMLStreamException {
        if (targetNamespace == null) {
            targetNamespace = detectTargetNamespace();
        }
        if (targetNamespace == null) {

            throw new PaxmlRuntimeException("No @targetNamespace attribute given on <soap> tag,"
                    + " and the target namespace cannot be detected from WSDL: " + getWsdlUrl());
        }
        OMFactory factory = AxiomUtils.getOMFactory();
        Map<?, ?> bd = (Map<?, ?>) this.body;

        OMNamespace targetNs = factory.createOMNamespace(targetNamespace, "ns");

        OMNamespace ns = factory.createOMNamespace(SOAP_NS, "soapenv");

        OMDocument doc = AxiomUtils.newDocument();
        doc.setXMLEncoding("UTF-8");

        OMElement root = factory.createOMElement("Envelope", ns);
        doc.addChild(root);

        OMElement headerEle = factory.createOMElement("Header", ns);
        root.addChild(headerEle);

        OMElement bodyEle = factory.createOMElement("Body", ns);
        root.addChild(bodyEle);

        Iterator<?> it = bd.entrySet().iterator();
        if (!it.hasNext()) {
            throw new PaxmlRuntimeException("No webservice operation name given!");
        }
        toXml(bodyEle, bd, targetNs, factory);

        doc.serializeAndConsume(out);
    }

    private Object fromXml(OMElement ele) {
        if (ele == null) {
            return null;
        }
        if (ele.getFirstElement() == null) {
            // simple value, return the text
            return ele.getText();
        } else {
            ObjectTree tree = new ObjectTree(ele.getLocalName());

            populateTree(tree, ele);

            return tree;
        }
    }

    private void populateTree(ObjectTree tree, OMElement ele) {

        if (ele.getFirstElement() == null) {
            tree.addValue(ele.getLocalName(), ele.getText());
        } else {
            ObjectTree subTree = new ObjectTree(ele.getLocalName());
            tree.addValue(ele.getLocalName(), subTree);
            for (OMElement child : new Elements(ele)) {
                populateTree(subTree, child);
            }
        }

    }

    private void toXml(OMElement ele, Object obj, OMNamespace ns, OMFactory factory) {
        if (obj == null) {
            return;
        }
        if (obj instanceof Map) {
            for (Map.Entry<?, ?> entry : ((Map<?, ?>) obj).entrySet()) {
                String name = entry.getKey().toString();
                Object value = entry.getValue();
                OMElement child = factory.createOMElement(name, ns.getNamespaceURI(), "");
                ele.addChild(child);
                toXml(child, value, ns, factory);
            }
        } else if (obj instanceof List) {
            for (Object value : ((List<?>) obj)) {
                toXml(ele, value, ns, factory);
            }
        } else {
            ele.setText(obj.toString());
        }
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Map getHeaders() {
        return headers;
    }

    public void setHeaders(Map headers) {
        this.headers = headers;
    }

    public Object getBody() {
        return body;
    }

    public void setBody(Object body) {
        this.body = body;
    }

    public boolean isResponseless() {
        return responseless;
    }

    public void setResponseless(boolean responseless) {
        this.responseless = responseless;
    }

    public String getTargetNamespace() {
        return targetNamespace;
    }

    public void setTargetNamespace(String targetNamespace) {
        this.targetNamespace = targetNamespace;
    }

}