LZSOAPService.java :  » Ajax » Laszlo-4.0.10 » org » openlaszlo » remote » swf » soap » Java Open Source

Java Open Source » Ajax » Laszlo 4.0.10 
Laszlo 4.0.10 » org » openlaszlo » remote » swf » soap » LZSOAPService.java
/* *****************************************************************************
 * LZSOAPService.java
 * ****************************************************************************/

/* J_LZ_COPYRIGHT_BEGIN *******************************************************
* Copyright 2001-2007 Laszlo Systems, Inc.  All Rights Reserved.              *
* Use is subject to license terms.                                            *
* J_LZ_COPYRIGHT_END *********************************************************/

package org.openlaszlo.remote.swf.soap;

import org.openlaszlo.iv.flash.api.action.Program;
import org.openlaszlo.remote.swf.soap.encoding.SWFSimpleDeserializerFactory;
import org.openlaszlo.remote.swf.soap.encoding.SWFObjectDeserializerFactory;
import org.openlaszlo.remote.swf.soap.encoding.LZObjectSerializerFactory;
import org.openlaszlo.server.LPS;
import java.io.IOException;
import java.net.URLDecoder;
import java.rmi.RemoteException;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.rpc.JAXRPCException;
import javax.xml.soap.SOAPHeader;
import org.apache.axis.AxisFault;
import org.apache.axis.client.Service;
import org.apache.axis.client.Call;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.encoding.DeserializerFactory;
import javax.xml.rpc.encoding.SerializerFactory;
import javax.xml.rpc.encoding.TypeMappingRegistry;
import javax.xml.rpc.encoding.TypeMapping;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.HandlerRegistry;
import javax.xml.soap.SOAPException;
import org.apache.axis.Constants;
import org.apache.axis.message.SOAPBodyElement;
import org.apache.axis.message.SOAPHeaderElement;
import org.apache.log4j.Logger;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;

public class LZSOAPService
{
    private static Logger mLogger = Logger.getLogger(LZSOAPService.class);

    String mServiceName;
    String mPort;
    String mEndpointAddress;
    String mTransport;
    String mTargetNS;
    String mXMLSchemaNS;
    String mSOAPEncodingNS;
    Service mService;
    TypeMappingRegistry mTypeMappingRegistry;
    HandlerRegistry mHandlerRegistry;
    TypeMapping mDefaultTypeMapping;
    TypeMapping mDefaultSOAPEncodingTypeMapping;

    /** URL for wsdl. This gets set in SOAPDataSource. */
    String mWSDL;

    /** Map of SWF of services (synchronized) (key is version string like swf6,
     * swf7, etc.) */
    Hashtable mClientSOAPServiceMap = new Hashtable();

    /** Map of LZSOAPOperations. */
    Map mOperations = null;

    /** Map of schema complex types. */
    Map mSchemaComplexTypes = null;



    /** Keep one DeserializerFactory around. */
    DeserializerFactory mSWFObjectDeserializerFactory = 
        new SWFObjectDeserializerFactory();
    SerializerFactory mObjectSerializerFactory = new LZObjectSerializerFactory();

    public LZSOAPService(String wsdl, String serviceName, String port, 
                         String endpointAddress, String transport,
                         String targetNS, String xmlSchemaNS,
                         String soapEncodingNS)
        throws ServiceException {

        mWSDL = wsdl;
        mServiceName = serviceName;
        mPort = port;
        mEndpointAddress = endpointAddress;
        mTransport = transport;
        mTargetNS = targetNS;
        mXMLSchemaNS = xmlSchemaNS;
        mSOAPEncodingNS = soapEncodingNS;

        mService = new Service(new QName(mTargetNS, mServiceName));

        mTypeMappingRegistry = mService.getTypeMappingRegistry();
        mHandlerRegistry = mService.getHandlerRegistry();

        getHandlerChain().add(new HandlerInfo(LZSOAPHandler.class, null, null));

        // Register default type mapping and default soap encoding type mapping.
        mDefaultTypeMapping = LZDefaultTypeMapping.getSingleton();
        mDefaultSOAPEncodingTypeMapping = new LZDefaultSOAPEncodingTypeMapping();
        mTypeMappingRegistry.registerDefault(mDefaultTypeMapping);
        mTypeMappingRegistry.register(Constants.URI_SOAP11_ENC, mDefaultSOAPEncodingTypeMapping);
    }


    public synchronized byte[] createClientSOAPService(String swfversion, int swfnum) 
        throws ServiceException {
        byte[] swfobj = (byte[])mClientSOAPServiceMap.get(swfversion);
        if (swfobj == null) {
            try {
                swfobj = ClientSOAPService.createObject(this, swfnum);
                mClientSOAPServiceMap.put(swfversion, swfobj);
            } catch (IOException e) {
throw new ServiceException(
/* (non-Javadoc)
 * @i18n.test
 * @org-mes="could not create client SOAP service object"
 */
                        org.openlaszlo.i18n.LaszloMessages.getMessage(
                                LZSOAPService.class.getName(),"051018-130")
); 
            }
        }
        return swfobj;
    }

    /**
     * Get client SWF representation of service.
     */
    public byte[] getClientSOAPService(int swfnum) 
        throws ServiceException {
        String swfversion = LPS.getSWFVersion(swfnum);
        byte[] swfobj = (byte[])mClientSOAPServiceMap.get(swfversion);
        if (swfobj == null) swfobj = createClientSOAPService(swfversion, swfnum);
        return swfobj;
    }

    /**
     * Invoke operation with parameters. Parameters are represented in XML like:
     *
     *     <params>
     *         <param>param1</param>
     *         <param>param2</param>
     *         <param>param3</param>
     *     <params>
     *
     * In document style, the string in the <param> element should be an
     * XML-escaped string. For example, suppose you were trying to send two
     * documents that looked like:
     *
     *     doc1: <a>1</a>
     *     doc2: <b>2</b>
     *
     * The XML parameter string should look as follows:
     *
     *    <params>
     *        <param>%3Ca%3E1%3C/a%3E</param>
     *        <param>%3Cb%3E2%3C/b%3E</param>
     *    </params>
     *
     * @param operation operation to invoke
     * @param xml XML from client that includes header and body. The format looks like:
     *
     *     <e><h>XML_HEADER</h><b>XML_BODY</b></e>
     *
     * where XML_BODY is
     *
     *     <params>
     *         <param>PARAM1</param>
     *         <param>PARAM2</param>
     *         <param>...</param>
     *     </params>
     *
     * @return object array where the first parameter is a string indicating the
     * style used to invoke the function (rpc|document) and the second is the
     * return value. For document styles, an array of SOAPBody message items are
     * returned.
     */
    public Object[] invoke(String operation, String xml) 
        throws AxisFault, ServiceException, RemoteException {

        mLogger.debug("invoke()");

        try {
            Element envelope = LZSOAPUtils.xmlStringToElement(xml);

            Element body = LZSOAPUtils.getFirstElementByTagName(envelope, "b");
            Element paramsEl = LZSOAPUtils.getFirstElementByTagName(body, "params");

            Object[] callArr = createCall(operation, paramsEl);
            Call call = (Call)callArr[0];
            Object[] params = (Object[])callArr[1];

            Element header = LZSOAPUtils.getFirstElementByTagName(envelope, "h");
            NodeList headerNodes = header.getChildNodes();
            for (int i=0; i < headerNodes.getLength(); i++) {
                Node headerNode = (Node)headerNodes.item(i);
                if (headerNode.getNodeType() != Node.ELEMENT_NODE) continue;
                call.addHeader(new SOAPHeaderElement((Element)headerNode));
            }

            // Pass back style and return value from call
            Object returnValue = call.invoke(params);

            // Return header, if any
            SOAPHeader responseHeader = 
                call.getResponseMessage().getSOAPEnvelope().getHeader();

            LZSOAPOperation op = (LZSOAPOperation)mOperations.get(operation);
            return new Object[]{ op.getStyle(), returnValue, responseHeader };

        } catch (AxisFault e) {
            mLogger.error("AxisFault");
            throw e;
        } catch (IOException e) {
            mLogger.error("IOException", e);
            throw new ServiceException(e.getMessage());
        } catch (org.xml.sax.SAXException e) {
            mLogger.error("SAXException:", e);
            throw new ServiceException(e.getMessage());
        } catch (SOAPException e) {
            mLogger.error("SOAPException", e);
            throw new ServiceException(e.getMessage());
        }

    }

    Node getParamValue(Element param) {
        NodeList list = param.getChildNodes();
        int len = list.getLength();
        if (len == 0) {
            return null;
        } 

        // if a subelement exists, the param must be an array or object.
        for (int i=0; i < list.getLength(); i++) {
            Node node = list.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                return param;
            }
        }

        return list.item(0);
    }


    /**
     * @return true if paramNode is text node, else false.
     */
    public boolean isTextNode(Node paramNode) {
        return (paramNode == null || paramNode.getNodeType() == Node.TEXT_NODE);
    }

    /**
     * @return true if paramNode is an element node, else false.
     */
    public boolean isElementNode(Node paramNode) {
        return (paramNode.getNodeType() == Node.ELEMENT_NODE);
    }

    /**
     * @return list of rpc parameters
     */
    public List setRPCParams(Call call, NodeList paramsList, List parts, 
                             LZSOAPOperation op)
        throws ServiceException, IOException, SAXException, DOMException {

        if (mLogger.isDebugEnabled()) {
            mLogger.debug("setRPCParams");
        }

        int pos = 0; // parameter position
        List params = new ArrayList();
        for (int i=0; i < paramsList.getLength(); i++) {

            Node node = (Node)paramsList.item(i);
            if (node.getNodeType() != Node.ELEMENT_NODE) continue;

            Element p = (Element)node;
            Node paramNode = getParamValue(p);

            LZSOAPPart part = (LZSOAPPart)parts.get(pos);
            ComplexType type = part.getType();

            if (type.isArray()) {

                if (! isElementNode(paramNode)) {
                    throw new ServiceException(
/* (non-Javadoc)
 * @i18n.test
 * @org-mes="parameter " + p[0] + " should an array"
 */
                        org.openlaszlo.i18n.LaszloMessages.getMessage(
                                LZSOAPService.class.getName(),"051018-304", new Object[] {new Integer(pos + 1)})
                    );
                }

                call.addParameter(part.getName(), type.getBase().getName(), 
                                  ArrayList.class, part.getParameterMode());

                ArrayWrapper aw = new ArrayWrapper((Element)paramNode, type);
                ArrayList list = new ArrayList();
                list.add(aw);
                params.add(list);
                if (mLogger.isDebugEnabled()) {
                    mLogger.debug("array param: " + aw);
                }

            } else {

                call.addParameter(part.getName(), type.getName(),
                                  part.getParameterMode());

                if (isTextNode(paramNode)) { // primitive param
                    Text text = (Text)paramNode;
                    String strValue = (text != null ? text.getData() : "");
                    params.add(((LZSOAPPart)parts.get(pos)).valueOf(strValue));
                    if (mLogger.isDebugEnabled()) {
                        mLogger.debug(
/* (non-Javadoc)
 * @i18n.test
 * @org-mes="primitive param: " + p[0]
 */
                        org.openlaszlo.i18n.LaszloMessages.getMessage(
                                LZSOAPService.class.getName(),"051018-335", new Object[] {strValue})
);
                    }

                } else if (isElementNode(paramNode)) { // object param
                    ObjectWrapper ow = new ObjectWrapper((Element)paramNode);
                    params.add(ow);
                    if (mLogger.isDebugEnabled()) {
                        mLogger.debug("object param: " + ow);
                    }

                } else {
                    throw new ServiceException(
/* (non-Javadoc)
 * @i18n.test
 * @org-mes="bad parameter " + p[0] + ": " + p[1]
 */
                        org.openlaszlo.i18n.LaszloMessages.getMessage(
                                LZSOAPService.class.getName(),"051018-353", new Object[] {new Integer(pos + 1), paramNode})
                        );
                }

            }

            ++pos;
        }

        if (params.size() != parts.size()) {
            throw new ServiceException(
/* (non-Javadoc)
 * @i18n.test
 * @org-mes="wrong number of params"
 */
                        org.openlaszlo.i18n.LaszloMessages.getMessage(
                                LZSOAPService.class.getName(),"051018-368")
);
        }

        // Set return type
        parts = op.getOutputMessage().getParts();
        int size = parts.size();
        if (size > 1) {
            throw new ServiceException(
/* (non-Javadoc)
 * @i18n.test
 * @org-mes="multiple return values unsupported"
 */
                        org.openlaszlo.i18n.LaszloMessages.getMessage(
                                LZSOAPService.class.getName(),"051018-382")
);
        }

        // If return type isn't void, set it.
        if (size != 0){
            LZSOAPPart part = (LZSOAPPart)parts.get(0);
            ComplexType type = part.getType();
            if (type != null) {
                call.setReturnType(type.getName());
            } else {
                mLogger.warn(
/* (non-Javadoc)
 * @i18n.test
 * @org-mes="type of return unspecified"
 */
                        org.openlaszlo.i18n.LaszloMessages.getMessage(
                                LZSOAPService.class.getName(),"051018-399")
); 
            }
        }

        return params;
    }

    /**
     * @return list of document style parameters
     */
    public List setDocumentParams(Call call, NodeList paramsList, List parts, 
                                  LZSOAPOperation op)
        throws ServiceException, IOException, SAXException, DOMException {

        if (mLogger.isDebugEnabled()) {
            mLogger.debug(
/* (non-Javadoc)
 * @i18n.test
 * @org-mes="setDocumentParams"
 */
                        org.openlaszlo.i18n.LaszloMessages.getMessage(
                                LZSOAPService.class.getName(),"051018-421")
);
        }

        call.setProperty(Call.OPERATION_STYLE_PROPERTY, "document");
        call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
        call.setProperty(Call.SOAPACTION_URI_PROPERTY, op.getSoapAction());

        List params = new ArrayList();
        for (int i=0; i < paramsList.getLength(); i++) {

            Node node = (Node)paramsList.item(i);
            if (node.getNodeType() != Node.ELEMENT_NODE) continue;

            Element p = (Element)node;

            // get the XML string and convert to an element
            Text text = (Text)p.getFirstChild();
            String data = URLDecoder.decode(text.getData());
            Element docElement = LZSOAPUtils.xmlStringToElement(data);
            params.add(new SOAPBodyElement(docElement));

        }

        return params;
    }

    /**
     * @param operation name of operation.
     * @param paramsEl parameter element nodes.
     * @return array with Call object as first value and a parameter array to invoke call with.
     */
    public Object[] createCall(String operation, Element paramsEl) throws ServiceException {
        LZSOAPOperation op = (LZSOAPOperation)mOperations.get(operation);
        if (op == null) {
            throw new ServiceException(
/* (non-Javadoc)
 * @i18n.test
 * @org-mes="could not find operation named " + p[0]
 */
                        org.openlaszlo.i18n.LaszloMessages.getMessage(
                                LZSOAPService.class.getName(),"051018-462", new Object[] {operation})
                                );
        }

        try {
            Call call = (org.apache.axis.client.Call)
                mService.createCall(new QName(mTargetNS, mPort));
            call.setOperationName(new QName(mTargetNS, op.getName()));
            call.setTargetEndpointAddress(mEndpointAddress);

            NodeList paramsList = paramsEl.getChildNodes();
            List parts = op.getInputMessage().getParts();

            List params = null;
            if (op.getStyle().equals("document"))
                params = setDocumentParams(call, paramsList, parts, op);
            else /* rpc */
                params = setRPCParams(call, paramsList, parts, op);

            return new Object[]{ call, params.toArray() };
        } catch (IOException e) {
            mLogger.error("IOException", e);
            throw new ServiceException("IOException: " + e.getMessage());
        } catch (SAXException e) {
            mLogger.error("SAXException", e);
            throw new ServiceException("SAXException: " + e.getMessage());
        } catch (DOMException e) {
            mLogger.error("DOMException", e);
            throw new ServiceException("DOMException: " + e.getMessage());
        }
    }

    public TypeMappingRegistry getTypeMappingRegistry() {
        return mTypeMappingRegistry;
    }

    public HandlerRegistry getHandlerRegistry() {
        return mHandlerRegistry;
    }

    public List getHandlerChain() {
        return mHandlerRegistry.getHandlerChain(new QName(mTargetNS, mPort));
    }

    public Service getService() {
        return mService;
    }

    /** Set map of LZSOAPOperations. */
    public void setOperations(Map operations) {
        mOperations = operations;
    }

    /** @return map of LZSOAPOperations. */
    public Map getOperations() {
        return mOperations;
    }

    public String getTargetNS() {
        return mTargetNS;
    }

    public String getSOAPEncodingNS() {
        return mSOAPEncodingNS;
    }

    public String getServiceName() {
        return mServiceName;
    }

    public String getPort() {
        return mPort;
    }

    public String getEndpointAddress() {
        return mEndpointAddress;
    }

    public String getTransport() {
        return mTransport;
    }

    /** WSDL URL for this SOAP service. */
    public String getWSDL() {
        return mWSDL;
    }

    /** Set WSDL URL for this SOAP service. */
    public void setWSDL(String wsdl) {
        mWSDL = wsdl;
    }

    /**
     * This gets called by WSDLParser after WSDL schema is read. 
     */
    public void setSchemaComplexTypes(Map schemaComplexTypes) {
        mSchemaComplexTypes = schemaComplexTypes;

        // now register these complex types with type mapper.
        if (mSchemaComplexTypes != null) {
            Iterator iter = mSchemaComplexTypes.values().iterator();
            while (iter.hasNext()) {
                ComplexType value = (ComplexType)iter.next();
                if ( value.getType() == ComplexType.TYPE_STRUCT ) {
                    QName structQName = value.getName();
                    // Just to be safe, registering in both default type mapping
                    // and SOAP type mapping.
                    mDefaultTypeMapping.register(ObjectWrapper.class, structQName,
                                                 mObjectSerializerFactory, 
                                                 mSWFObjectDeserializerFactory);
                    mDefaultSOAPEncodingTypeMapping.register(ObjectWrapper.class, structQName,
                                                             mObjectSerializerFactory, 
                                                             mSWFObjectDeserializerFactory);
                    if (mLogger.isDebugEnabled()) {
                        mLogger.debug(
/* (non-Javadoc)
 * @i18n.test
 * @org-mes="registered type mapping for object: " + p[0]
 */
                        org.openlaszlo.i18n.LaszloMessages.getMessage(
                                LZSOAPService.class.getName(),"051018-581", new Object[] {structQName})
);
                    }
                } 
                // NOTE: arrays/collections are handled by default type mapping
                // in LZDefaultTypeMapping. -pk
            }
        }
    }

    /**
     * @return map of ComplexType.
     */
    public Map getSchemaComplexTypes() {
        return mSchemaComplexTypes;
    }

    public void toComplexTypesXML(StringBuffer sb) {
        sb.append("<complex-types>");
        if (mSchemaComplexTypes != null) {
            Iterator iter = mSchemaComplexTypes.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry)iter.next();
                ComplexType ct =(ComplexType)entry.getValue();
                ct.toXML(sb);
            }
        }
        sb.append("</complex-types>");
    }

    public void toOperationXML(StringBuffer sb) {
        sb.append("<operations>");
        Iterator iter = mOperations.keySet().iterator();
        while (iter.hasNext()) {
            String key = (String)iter.next();
            LZSOAPOperation op = (LZSOAPOperation)mOperations.get(key);
            op.toXML(sb);
        }
        sb.append("</operations>");
    }

    public void toXML(StringBuffer sb) {
        sb.append("<service")
            .append(" name=\"").append(mServiceName).append("\"")
            .append(" port=\"").append(mPort).append("\"")
            .append(" endpoint=\"").append(mEndpointAddress).append("\"")
            .append(" transport=\"").append(mTransport).append("\"")
            .append(" target-namespace=\"").append(mTargetNS).append("\">");
        toOperationXML(sb);
        toComplexTypesXML(sb);
        sb.append("</service>");
    }

//     public String toString() {
//         return "-- SOAPService ------------------------------\n"
//             + "service="  + mServiceName + "\n"
//             + "port="     + mPort + "\n"
//             + "endpoint=" + mEndpointAddress + "\n"
//             + "transport=" + mTransport + "\n"
//             + "target namespace=" + mTargetNS + "\n\n"
//             + "    ==== OPERATIONS ====\n\n"
//             + toOperationString()
//             + "    ==== SCHEMA COMPLEX TYPES ====\n\n"
//             + stringComplexTypes()
//             + "---------------------------------------------";
//     }

//     public String toOperationString() {
//         StringBuffer buf = new StringBuffer(); 
//         Iterator iter = mOperations.keySet().iterator();
//         while (iter.hasNext()) {
//             String key = (String)iter.next();
//             LZSOAPOperation op = (LZSOAPOperation)mOperations.get(key);
//             buf.append(op).append("\n");
//         }
//         return buf.toString();
//     }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.