Package org.jboss.soa.esb.services.soapui

Source Code of org.jboss.soa.esb.services.soapui.SoapUIClientService$SmooksCache

/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA  02110-1301, USA.
*
* (C) 2005-2006, JBoss Inc.
*/
package org.jboss.soa.esb.services.soapui;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.wsdl.Definition;
import javax.wsdl.Import;
import javax.wsdl.Part;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.httpclient.HttpClient;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.jboss.internal.soa.esb.soap.OGNLUtils;
import org.jboss.internal.soa.esb.util.ESBProperties;
import org.jboss.internal.soa.esb.util.LRUReferenceCountCache;
import org.jboss.internal.soa.esb.util.LRUReferenceCountCacheResource;
import org.jboss.internal.soa.esb.util.XMLHelper;
import org.jboss.internal.soa.esb.util.LRUReferenceCountCache.LRUReferenceCountCacheEntry;
import org.jboss.internal.soa.esb.util.stax.events.ESBStaxXMLEvent;
import org.jboss.internal.soa.esb.util.stax.util.ESBXMLEventStreamReader;
import org.jboss.mx.util.MBeanProxyExt;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.dom.YADOMUtil;
import org.jboss.soa.esb.http.HttpClientFactory;
import org.jboss.system.ServiceMBeanSupport;
import org.jboss.system.server.ServerConfig;
import org.jboss.system.server.ServerConfigImplMBean;
import org.milyn.Smooks;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.support.soap.SoapMessageBuilder;
import com.eviware.soapui.impl.wsdl.support.xsd.SampleXmlUtil;
import com.eviware.soapui.impl.wsdl.support.xsd.SchemaException;
import com.eviware.soapui.impl.wsdl.support.xsd.SchemaUtils;
import com.eviware.soapui.model.iface.MessagePart;
import com.eviware.soapui.model.iface.Operation;
import com.eviware.soapui.settings.WsdlSettings;


/**
* Soap UI Soap Client Service MBean.
*
* @author <a href="mailto:tom.fennelly@jboss.com">tom.fennelly@jboss.com</a>
*/
public class SoapUIClientService extends ServiceMBeanSupport implements SoapUIClientServiceMBean {

    private static final String FAULT_PREFIX = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">"
      + "<soapenv:Body><soapenv:Fault><faultcode>?</faultcode><faultstring>?</faultstring><detail>" ;
    private static final String FAULT_SUFFIX = "</detail></soapenv:Fault></soapenv:Body></soapenv:Envelope>" ;

    private static final String IS_CLONE_ATTRIB = "is-clone";
    private static Logger logger = Logger.getLogger(SoapUIClientService.class);
    private final WsdlCache wsdlCache;
    private final SmooksCache smooksCache;
    private static final String SOAPUI_OPTIONAL_COMMENT = "Optional:";
    private static final String REMOVE_POSTFIX = " to be removed";
    private static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
    private static final String XMLSCHEMA_INSTANCE_URI = "http://www.w3.org/2001/XMLSchema-instance";
    private static final String NILLABLE_TAG_NAME = "nillable";
    private static final String XMLNS_XSI = "xmlns:xsi";
    private static final String XSI_NIL = "xsi:nil";
    /**
     * The SoapUI property file.
     */
    private String propertyFile ;
    /**
     * The name of the generated property file.
     */
    private static final String SOAP_UI_PROPERTY_FILE = "soapui-settings.xml" ;
    /**
     * The additional schema resources.
     */
    private String schemas ;

    private String serverDataDir;
    /**
     * The name of the SoapUI schema directory.
     */
    private static final String SOAP_UI_SCHEMA_DIRECTORY = "soapui-schemas" ;
    /**
     * The name of the property specifying the created SoapUI schema directory.
     */
    private static final String PROPERTY_ESB_SCHEMA_DIRECTORY = "jboss.esb.soapui.schema" ;

    /**
     * Public default constructor.
     */
    public SoapUIClientService() throws ConfigurationException {
        final ESBProperties properties = new ESBProperties("/soapui-client.sar.properties");

        int smooksLRUCacheSize = properties.getIntProperty("smooks.lru.cache.size", 30);
        smooksCache = new SmooksCache(smooksLRUCacheSize);
        final int wsdlLRUCacheSize = properties.getIntProperty("wsdl.lru.cache.size", 30);
        wsdlCache = new WsdlCache(wsdlLRUCacheSize);
    }

    protected void startService() throws Exception {
        super.startService();
       
        if (propertyFile != null) {
            File dataDir;
            if (serverDataDir != null) {
               
                dataDir = new File(serverDataDir);
            }
            else {
                final ServerConfig serverConfig = (ServerConfig) MBeanProxyExt.create(ServerConfig.class, ServerConfigImplMBean.OBJECT_NAME);
                dataDir = serverConfig.getServerDataDir() ;
            }
           
            if (schemas != null)
            {
                initialiseSchemas(dataDir) ;
            }
           
            final File soapUIPropertyFile = new File(dataDir, SOAP_UI_PROPERTY_FILE) ;
           
            final File baseFile = new File(propertyFile) ;
            final InputStream xmlPropertyIS = getInputStream(baseFile);

           
            try {
                final FileOutputStream fos = new FileOutputStream(soapUIPropertyFile) ;
                XMLHelper.replaceSystemProperties(XMLHelper.getXMLStreamReader(xmlPropertyIS),
                    XMLHelper.getXMLStreamWriter(fos)) ;
            } finally {
                xmlPropertyIS.close() ;
            }
           
            SoapUI.initSettings(soapUIPropertyFile.getAbsolutePath()) ;
        }
    }
   
    @Override
    protected void stopService() throws Exception
    {
        smooksCache.clean();
        if (propertyFile != null)
        {
            File dataDir;
            if (serverDataDir != null) {
                dataDir = new File(serverDataDir);
            }
            else
            {
                final ServerConfig serverConfig = (ServerConfig) MBeanProxyExt.create(ServerConfig.class, ServerConfigImplMBean.OBJECT_NAME);
                dataDir = serverConfig.getServerDataDir() ;
            }
            final File schemaDir = new File(dataDir, SOAP_UI_SCHEMA_DIRECTORY) ;
            if (schemaDir.exists())
            {
                deleteFiles(schemaDir) ;
            }
        }
       
        // TODO Auto-generated method stub
        super.stopService();
    }
   
    private void initialiseSchemas(final File dataDir)
        throws IOException
    {
        final String[] schemaResources = schemas.split("[, ]") ;
        if (schemaResources != null)
        {
            final File schemaDir = new File(dataDir, SOAP_UI_SCHEMA_DIRECTORY) ;
            schemaDir.mkdir();
           
            for(String schema: schemaResources)
            {
                final File schemaFile = new File(schema) ;
                final InputStream is = getInputStream(schemaFile) ;
                try
                {
                    writeToFile(is, schemaDir, schemaFile.getName()) ;
                }
                finally
                {
                    is.close() ;
                }
            }
            System.setProperty(PROPERTY_ESB_SCHEMA_DIRECTORY, schemaDir.getAbsolutePath()) ;
        }
    }
   
    private void deleteFiles(final File file)
    {
        if (file.isDirectory())
        {
            final File[] files = file.listFiles() ;
            for(File child: files)
            {
                deleteFiles(child) ;
            }
        }
        file.delete() ;
    }
   
    private void writeToFile(final InputStream is, final File dir, final String name)
        throws IOException
    {
        final File output = new File(dir, name) ;
        final byte[] buffer = new byte[256] ;
        final FileOutputStream fos = new FileOutputStream(output) ;
        try
        {
            for(;;)
            {
                final int count = is.read(buffer) ;
                if (count <= 0)
                {
                    break ;
                }
                fos.write(buffer, 0, count) ;
            }
        }
        finally
        {
            fos.close() ;
        }
    }
   
    private InputStream getInputStream(final File file)
        throws IOException
    {
        if (!file.isAbsolute()) {
            final URL resourceURL = Thread.currentThread().getContextClassLoader().getResource(file.getPath()) ;
            return  resourceURL.openStream() ;
        } else {
            return new FileInputStream(file) ;
        }
    }
   
    /**
     * Get the property file.
     * @return The name of the property file being used.
     */
    public String getPropertyFile()
    {
        return propertyFile ;
    }
    /**
     * Set the property file.
     * @param propertyFile The name of the property file being used.
     */
    public void setPropertyFile(final String propertyFile)
    {
        this.propertyFile = propertyFile ;
    }
   
    /**
     * Get the additional schema resources.
     * @return The additional schema resources.
     */
    public String getSchemas()
    {
        return schemas ;
    }
   
    /**
     * Set the additional schemes.
     * @param schemas The additional schema resources to setup for SoapUI.
     * This needs support through the soapui-settings.xml file
     * @see setPropertyFile
     */
    public void setSchemas(final String schemas)
    {
        this.schemas = schemas ;
    }

    /**
     * Build a SOAP request for the specified operation on the specified WSDL.
     *
     * @param wsdl            WSDL URL.
     * @param operation       Operation name.
     * @param serviceName     Service Name.
     * @param params          Message parameter map.
     * @param httpClientProps {@link org.apache.commons.httpclient.HttpClient} creation properties.
     * @param smooksResource  {@link org.milyn.Smooks} transformation configuration resource.  This is the actual
     *                        Smooks resource configuration XML, not a file name.
     *                        Null if no transformations are to be performed on the SOAP message before serializing it
     *                        for return.
     * @param soapNs       optional SOAP namespace
     * @return The SOAP Message.
     * @throws IOException Failed to load WSDL.
     */
    public String buildRequest(String wsdl, String operation, String serviceName, Map params, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
        final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
       
        try
        {
            final WsdlState state = wsdlEntry.getResource() ;
            final XMLEventReader reader = state.getRequest(operation, serviceName, true, wsdl, httpClientProps) ;
            return buildSOAPMessage(reader, params, smooksResource, soapNs, state.getNils());
        }
        finally
        {
            wsdlCache.release(wsdlEntry) ;
        }
    }
   
    /**
     * Use soapUI to build a SOAP response for the specified operation on the specified WSDL.
     *
     * @param wsdl            WSDL URL
     * @param operation       Operation name.
     * @param serviceName     Service Name.
     * @param params          Message parameter map.
     * @param httpClientProps {@link org.apache.commons.httpclient.HttpClient} creation properties.
     * @param smooksResource  {@link org.milyn.Smooks} transformation configuration resource file.
     *                        Null if no transformations are to be performed on the SOAP message before serializing it
     *                        for return.
     * @param soapNs       optional SOAP namespace
     * @return The SOAP Message.
     * @throws IOException                   Failed to load WSDL.
     * @throws UnsupportedOperationException Operation not supported on specified WSDL.
     * @throws SAXException                  Failed to parse the SOAP UI generated request message.
     */
    public String buildResponse(String wsdl, String operation, String serviceName, Map params, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
        final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
       
        try
        {
            final WsdlState state = wsdlEntry.getResource() ;
            final XMLEventReader reader = state.getResponse(operation, serviceName, true, wsdl, httpClientProps) ;
            return buildSOAPMessage(reader, params, smooksResource, soapNs, state.getNils());
        }
        finally
        {
            wsdlCache.release(wsdlEntry) ;
        }
    }
   
   
    public String buildFault(String wsdl, String operation, String serviceName, String faultName, Map params, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
        final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
        params.put("Fault.faultcode","soapenv:server");
       
        try
        {
            final WsdlState state = wsdlEntry.getResource() ;
            final XMLEventReader reader = state.getFault(operation, serviceName, faultName, true, wsdl, httpClientProps) ;
            return buildSOAPMessage(reader, params, smooksResource, soapNs, state.getNils());
        }
        finally
        {
            wsdlCache.release(wsdlEntry) ;
        }
    }

    /**
     * Get the 1st endpoint from the specified WSDL.
     *
     * @param wsdl            WSDL URL.
     * @param httpClientProps {@link org.apache.commons.httpclient.HttpClient} creation properties.
     * @return The operation endpoint URL.
     * @throws IOException Failed to load WSDL.
     */
    public String getEndpoint(String wsdl, String serviceName, Properties httpClientProps) throws IOException {
        final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
       
        try
        {
            final WsdlState state = wsdlEntry.getResource() ;
            if(serviceName != null)
            {
                return state.getEndpoint(serviceName, true, true, wsdl, httpClientProps);
            }
            else
            {
                return state.getDefaultEndpoint() ;
            }
        }
        finally
        {
            wsdlCache.release(wsdlEntry) ;
        }
    }

    /**
     * Get the Content Type for the appropriate SOAP version of the 1st interface from the specified WSDL.
     *
     * @param wsdl            WSDL URL.
     * @param httpClientProps {@link org.apache.commons.httpclient.HttpClient} creation properties.
     * @return The operation endpoint URL.
     * @throws IOException Failed to load WSDL.
     */
    public String getContentType(String wsdl, String serviceName, Properties httpClientProps) throws IOException {
        final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
       
        try
        {
            final WsdlState state = wsdlEntry.getResource() ;
            if(serviceName != null)
            {
                return state.getContentType(serviceName, true, true, wsdl, httpClientProps);
            }
            else
            {
                return state.getDefaultContentType() ;
            }
        }
        finally
        {
            wsdlCache.release(wsdlEntry) ;
        }
    }

    /**
     * Use soapUI to Merge a SOAP response for the specified operation on the specified WSDL with its template.
     *
     * @param wsdl            WSDL URL.
     * @param operation       Operation name.
     * @param serviceName     Service Name.
     * @param response        The actual response.
     * @param smooksResource  {@link org.milyn.Smooks} transformation configuration resource file.
     *                        Null if no transformations are to be performed on the SOAP message before serializing it
     *                        for return.
     * @param soapNs       optional SOAP namespace
     * @return The SOAP Message.
     * @throws IOException                   Failed to load WSDL.
     * @throws UnsupportedOperationException Operation not supported on specified WSDL.
     * @throws SAXException                  Failed to parse the SOAP UI generated request message.
     */
    public String mergeResponseTemplate(String wsdl, String operation, String serviceName, String response, Properties httpClientProps, String smooksResource, String soapNs) throws IOException, UnsupportedOperationException, SAXException {
        final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
       
        try
        {
            final WsdlState state = wsdlEntry.getResource() ;
            final XMLEventReader reader = state.getResponse(operation, serviceName, true, wsdl, httpClientProps) ;
            return (reader == null ? response : mergeSOAPMessage(reader, response, smooksResource, soapNs));
        }
        finally
        {
            wsdlCache.release(wsdlEntry) ;
        }
    }

    WsdlOperationInfo getOperationInfo(final String wsdl, final String operationName , final String serviceName,
        final Properties httpClientProps, final boolean refresh)
        throws IOException
    {
        final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> wsdlEntry = wsdlCache.get(wsdl, httpClientProps) ;
       
        try
        {
            final WsdlState state = wsdlEntry.getResource() ;
            final WsdlServiceInfo serviceInfo = state.getServiceInfo(serviceName, refresh, true, wsdl, httpClientProps) ;
            return serviceInfo.getOperation(operationName) ;
        }
        finally
        {
            wsdlCache.release(wsdlEntry) ;
        }
    }

    static Set<QName> extractNillableElements(final String wsdl, final EsbWsdlLoader loader)
        throws SchemaException, IOException
    {
        final Set<QName> nils = new HashSet<QName>() ;
        Map<String, XmlObject> schemas = SchemaUtils.getSchemas(wsdl, loader);
        Iterator keys = schemas.keySet().iterator();
        while (keys.hasNext()) {
            XmlObject schema = schemas.get(keys.next());
            String namespace = SchemaUtils.getTargetNamespace(schema);
            Document doc = getDocument(schema.toString());
            Element docRoot = doc.getDocumentElement();
            extractNillableElements(docRoot, nils, namespace);
        }
        return nils ;
    }
   
    static void extractNillableElements(Element element, Set<QName> nils, String namespace) {
        if (element != null
            && element.getLocalName()!= null
            && element.getLocalName().equals("element")
            && element.hasAttribute(NILLABLE_TAG_NAME)
            && element.getAttribute(NILLABLE_TAG_NAME).equals("true")) {
            nils.add(new QName(namespace, element.getAttribute("name")));
        }

        NodeList children = element.getChildNodes();
        int childCount = children.getLength();

        for(int i = 0; i < childCount; i++) {
            Node child = children.item(i);
            if(child.getNodeType() == Node.ELEMENT_NODE) {
                 extractNillableElements((Element) child, nils, namespace);
            }
        }
    }

    private String buildSOAPMessage(XMLEventReader reader, Map params, String smooksResource, String soapNs, Set<QName> nils) throws IOException, SAXException {
        Document messageDoc = getDocument(reader) ;

        Element docRoot = messageDoc.getDocumentElement();

        // Purposely not using log levels to output because I want to make
        // it as easy as possible for the developer to dump the SOAP during dev. They
        // just need to set "dumpSOAP" in the param Map....
        boolean dumpSOAP = params.containsKey("dumpSOAP");
        if(dumpSOAP) {
            dumpSOAP("SOAP Template (Unexpanded):", docRoot);
        }

        expandMessage(docRoot, params);

        if(dumpSOAP) {
            dumpSOAP("SOAP Template (Expanded):", docRoot);
        }

        injectParameters(docRoot, params, soapNs, nils);

        if(smooksResource != null) {
            applySmooksTransform(smooksResource, messageDoc);
            // reassign the docRoot variable after transform... in case it was replaced by a #document transform...
            docRoot = messageDoc.getDocumentElement();
        }

        if(dumpSOAP) {
            dumpSOAP("SOAP Message (Populated Template):", docRoot);
        }
       
        try
        {
            final StringWriter sw = new StringWriter() ;
            final XMLEventWriter writer = XMLHelper.getXMLEventWriter(sw) ;
            XMLHelper.readDomNode(docRoot, writer, true) ;
          return sw.toString();
        }
        catch (final XMLStreamException xmlse)
        {
            final IOException ioe = new IOException("Failed to serialize the output SOAP message") ;
            ioe.initCause(xmlse) ;
            throw ioe ;
        }
    }

    private String mergeSOAPMessage(XMLEventReader reader, String response, String smooksResource, String soapNs) throws IOException, SAXException {
        Document templateDoc = getDocument(reader);
        Element templateRoot = templateDoc.getDocumentElement();

        Document messageDoc = getDocument(response);
        Element messageRoot = messageDoc.getDocumentElement();

        debugDoc(messageRoot);
        debugDoc(templateRoot);

        mergeTemplate(templateRoot, messageRoot, 0);

        if(smooksResource != null) {
            applySmooksTransform(smooksResource, messageDoc);
        }

        debugDoc(messageRoot);

        try
        {
            final StringWriter sw = new StringWriter() ;
            final XMLEventWriter writer = XMLHelper.getXMLEventWriter(sw) ;
            XMLHelper.readDomNode(messageRoot, writer, true) ;
          return sw.toString();
        }
        catch (final XMLStreamException xmlse)
        {
            final IOException ioe = new IOException("Failed to serialize the output SOAP message") ;
            ioe.initCause(xmlse) ;
            throw ioe ;
        }
    }

    private void debugDoc(Element doc)
    {
        if(logger.isDebugEnabled()) {
            logger.debug("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
            try {
                final StringWriter sw = new StringWriter() ;
                final XMLEventWriter writer = XMLHelper.getXMLEventWriter(sw) ;
                XMLHelper.readDomNode(doc, writer, true) ;
                logger.debug(sw.toString());
            } catch (final XMLStreamException xmlse) {
                logger.debug("Failed to print the SOAP message") ;
            }
            logger.debug("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
        }
    }

    /**
     * Merge the template to accommodate data collections.
     * <p/>
     * It merges the soapUI cllection comment nodes to the message where appropriate.
     *
     * @param template The template element to be merged.
     * @param instance The element to be processed.
     * @param index    The template's element instance index.
     */
    private void mergeTemplate(Element template, Element instance, int index) {
        if (template != null && instance != null) {
            if (index == 0) {
                //Process only if this is the first element of its kind
                Comment comment = YADOMUtil.getCommentBefore(template);
                if (comment != null
                    && comment.getTextContent().endsWith(OGNLUtils.SOAPUI_CLONE_COMMENT)) {
                    Node parent = instance.getParentNode();
                    if (parent != null) {
                        Comment newComment = parent.getOwnerDocument().createComment(comment.getTextContent());
                        parent.insertBefore(newComment, instance);
                    }
                }
            }

            NodeList children = template.getChildNodes();
            int nodesCount = children.getLength();
            for (int i = 0; i < nodesCount; i++) {
                Node templateNode = children.item(i);
                if (templateNode.getNodeType() == Node.ELEMENT_NODE) {
                    //We may have many instances of this template
                    //and each could have a nested collection so run through them
                    NodeList instances = instance.getElementsByTagNameNS(templateNode.getNamespaceURI(), templateNode.getLocalName());
                    int instancesSize = instances.getLength();
                    for (int j = 0; j < instancesSize; j++) {
                        mergeTemplate((Element) templateNode, (Element) instances.item(j), j);
                    }
                }
            }
        }
    }

    private static Document getDocument(final XMLEventReader reader) throws IOException {
        try {
            return XMLHelper.createDocument(reader) ;
        } catch (final Exception ex) {
            final IOException ioe = new IOException("Failed to deserialize the SOAP message template") ;
            ioe.initCause(ex) ;
            throw ioe ;
        }
    }

    private static Document getDocument(String soapMessageTemplate) throws IOException {
        try {
            final XMLEventReader reader = XMLHelper.getXMLEventReader(new StringReader(soapMessageTemplate)) ;
            return XMLHelper.createDocument(reader) ;
        } catch (final Exception ex) {
            final IOException ioe = new IOException("Failed to deserialize the SOAP message template") ;
            ioe.initCause(ex) ;
            throw ioe ;
        }
    }

    private void dumpSOAP(String message, Element docRoot) {
        System.out.println("------------------------------------------------------------------------------------------------------------------------------------------");
        System.out.println(message + "\n");
        try {
            final XMLEventWriter writer = XMLHelper.getXMLEventWriter(new StreamResult(System.out)) ;
            XMLHelper.readDomNode(docRoot, writer, false) ;
        } catch (Exception e) {
            logger.error("Unable to dump SOAP.", e);
        }
        System.out.println("------------------------------------------------------------------------------------------------------------------------------------------");
    }

    private void applySmooksTransform(String smooksResource, Document messageDoc) throws IOException, SAXException {
        if(smooksResource != null) {
            LRUReferenceCountCacheEntry<Smooks, SmooksResource> smooksEntry = smooksCache.get(smooksResource);
            try {
                final Smooks smooks = smooksEntry.getResource();
                smooks.filterSource(new DOMSource(messageDoc), new DOMResult());
            }
            finally
            {
                smooksCache.release(smooksEntry);
            }
        }
    }

    /**
     * Expand the message to accommodate data collections.
     * <p/>
     * It basically just clones the message where appropriate.
     *
     * @param element The element to be processed.
     * @param params  The message params.  Uses the message params to
     *                decide whether or not cloning is required.
     */
    private void expandMessage(Element element, Map params) {
        boolean elementRemoved = false;
        // If this element is not a cloned element, check does it need to be cloned...
        if (!element.hasAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, IS_CLONE_ATTRIB)) {
            Element clonePoint = getClonePoint(element);

            if(clonePoint != null) {
                int collectionSize;
                String ognl = OGNLUtils.getOGNLExpression(element);
                //We don't need the index value when expanding the message
                if (ognl.endsWith("]")) {
                    ognl = ognl.substring(0, ognl.lastIndexOf("["));
                }

                collectionSize = calculateCollectionSize(ognl, params);

                if(collectionSize == -1) {
                    // It's a collection, but has no entries that match the OGNL expression for this element...
                    if(clonePoint == element) {
                        // If the clonePoint is the element itself, we remove it... we're done with it...
                        clonePoint.getParentNode().removeChild(clonePoint);
                        elementRemoved = true;
                    } else {
                        // If the clonePoint is not the element itself (it's a child element), leave it
                        // and check it again when we get to it...
                        resetClonePoint(clonePoint);
                    }
                } else if(collectionSize == 0) {
                    // It's a collection, but has no entries, remove it...
                    clonePoint.getParentNode().removeChild(clonePoint);
                    elementRemoved = true;
                } else if(collectionSize == 1) {
                    // It's a collection, but no need to clone coz we
                    // already have an entry for it...
                    clonePoint.setAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, OGNLUtils.JBOSSESB_SOAP_NS_PREFIX + OGNLUtils.OGNL_ATTRIB, ognl + "[0]");
                } else {
                    cloneCollectionTemplateElement(clonePoint, (collectionSize - 1), ognl, params);
                }
            }
        }

        if (!elementRemoved){
            // Now do the same for the child elements...
            expandChildren(element, params);
        }
    }

    private void expandChildren(Element element, Map params) {
        List<Node> children = YADOMUtil.copyNodeList(element.getChildNodes());
        for (Node node : children) {
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                expandMessage((Element) node, params);
            }
        }
    }

    private int calculateCollectionSize(String ognl, Map params) {
        // Try for an Object graph based collection...
        Object param = OGNLUtils.getParameter(ognl, params);
        if (param != null) {
            Class paramRuntime = param.getClass();
            if (paramRuntime.isArray()) {
                return ((Object[]) param).length;
            } else if (Collection.class.isAssignableFrom(paramRuntime)) {
                return ((Collection) param).size();
            }
        }

        // Try for <String, Object> collection based map entries...
        Set<Map.Entry> entries = params.entrySet();
        String collectionPrefix = ognl + "[";
        int maxIndex = -1;
        for (Map.Entry entry : entries) {
            Object keyObj = entry.getKey();
            if(keyObj instanceof String) {
                String key = (String)keyObj;
                if(key.startsWith(collectionPrefix)) {
                    int endIndex = key.indexOf(']', collectionPrefix.length());
                    String ognlIndexValString = key.substring(collectionPrefix.length(), endIndex);
                    try {
                        int ognlIndexVal = Integer.valueOf(ognlIndexValString);
                        maxIndex = Math.max(maxIndex, ognlIndexVal);
                    } catch(NumberFormatException e) {}
                }
            }
        }

        if(maxIndex != -1) {
            return maxIndex + 1;
        }

        // It's a collection, but nothing in this message for it collection...
        return -1;
    }

    private Element getClonePoint(Element element) {
        Comment comment;

        // Is it this element...
        comment = YADOMUtil.getCommentBefore(element);
        if(comment != null && comment.getTextContent().endsWith(OGNLUtils.SOAPUI_CLONE_COMMENT)) {
            comment.setTextContent(comment.getTextContent() + OGNLUtils.CLONED_POSTFIX);
            return element;
        }

        // Is it the first child element of this element...
        Element firstChildElement = YADOMUtil.getFirstChildElement(element);
        if(firstChildElement != null) {
            Element lastChildElement = YADOMUtil.getLastChildElement(element);
            comment = YADOMUtil.getCommentBefore(firstChildElement);
            if(comment != null && comment.getTextContent().endsWith(OGNLUtils.SOAPUI_CLONE_COMMENT)
                && lastChildElement != null && firstChildElement.getTagName().equals(lastChildElement.getTagName())) {
                comment.setTextContent(comment.getTextContent() + OGNLUtils.CLONED_POSTFIX);
                return firstChildElement;
            }
        }

        return null;
    }

    private void resetClonePoint(Element clonePoint) {
        Comment comment = YADOMUtil.getCommentBefore(clonePoint);

        if(comment == null) {
            throw new IllegalStateException("Call to reset a 'clonePoint' that doesn't have a comment before it.");
        }

        String commentText = comment.getTextContent();
        if(!commentText.endsWith(OGNLUtils.CLONED_POSTFIX)) {
            throw new IllegalStateException("Call to reset a 'clonePoint' that doesn't have a proper clone comment before it.");
        }

        comment.setTextContent(commentText.substring(0, commentText.length() - OGNLUtils.CLONED_POSTFIX.length()));
    }

    /**
     * Clone a collection node.
     * <p/>
     * Note we have to frig with the OGNL expressions for collections/arrays because the
     * collection entry is represented by [0], [1] etc in the OGNL expression, not the actual
     * element name on the DOM e.g. collection node "order/items/item" (where "item" is the
     * actual collection entry) maps to the OGNL expression "order.items[0]" etc.
     *
     * @param element    The collection/array "entry" sub-branch.
     * @param cloneCount The number of times it needs to be cloned.
     * @param ognl       The OGNL expression for the collection/array. Not including the
     *                   indexing part.
     * @param params     The message params.
     */
    private void cloneCollectionTemplateElement(Element element, int cloneCount, String ognl, Map params) {
        if (element == null) {
            return;
        }

        Node insertPoint = element.getNextSibling();
        Node parent = element.getParentNode();

        element.setAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, OGNLUtils.JBOSSESB_SOAP_NS_PREFIX + OGNLUtils.OGNL_ATTRIB, ognl + "[0]");
        for (int i = 0; i < cloneCount; i++) {
            Element clone = (Element) element.cloneNode(true);

            clone.setAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, OGNLUtils.JBOSSESB_SOAP_NS_PREFIX + IS_CLONE_ATTRIB, "true");
            clone.setAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, OGNLUtils.JBOSSESB_SOAP_NS_PREFIX + OGNLUtils.OGNL_ATTRIB, ognl + "[" + Integer.toString(i + 1) + "]");
            if (insertPoint == null) {
                parent.appendChild(clone);
            } else {
                parent.insertBefore(clone, insertPoint);
            }
            //The clones can have collections too, so we need to expand them here
            expandChildren(clone, params);
        }
    }

    private void injectParameters(Element element, Map params, String soapNs, Set<QName> nils) {
        NodeList children = element.getChildNodes();
        int childCount = children.getLength();

        for (int i = 0; i < childCount; i++) {
            Node node = children.item(i);

            if (childCount == 1 && node.getNodeType() == Node.TEXT_NODE) {
                if (isParameter(node)) {
                    String ognl = OGNLUtils.getOGNLExpression(element, soapNs);
                    Object param = OGNLUtils.getParameter(ognl, params);

                    if (param == null) {
                        Node parent = element.getParentNode();
                        String namespace = element.getNamespaceURI();
                        Node nsParent = parent;
                        while (nsParent != null && namespace == null) {
                            //Check the parents for the namespace
                            namespace = nsParent.getNamespaceURI();
                            nsParent = nsParent.getParentNode();
                        }
                        QName qname = new QName(namespace, element.getLocalName());

                        if (nils.contains(qname)) {
                            //If value is null and it is declared to be nillable set it as xsi:nil
                            element.getOwnerDocument().getDocumentElement().setAttributeNS(XMLNS_URI, XMLNS_XSI, XMLSCHEMA_INSTANCE_URI);
                            element.setAttributeNS(XMLSCHEMA_INSTANCE_URI, XSI_NIL, "true");
                            //Remove the soapUI's '?' text
                            element.removeChild(node);
                        } else {
                            Comment comment = YADOMUtil.getCommentBefore(element);
                            if(comment != null && comment.getTextContent().endsWith(SOAPUI_OPTIONAL_COMMENT)) {
                                //If it is optional do not generate the element
                                parent.removeChild(comment);
                                Comment clone = (Comment) comment.cloneNode(true);
                                clone.setTextContent(comment.getTextContent() + REMOVE_POSTFIX);
                                parent.insertBefore(clone, element);
                            } else {
                                //If it is required generate empty element
                                //Remove the soapUI's '?' text
                                element.removeChild(node);
                            }
                        }
                    } else {
                        element.removeChild(node);
                        element.appendChild(element.getOwnerDocument().createTextNode(param.toString()));
                    }
                }
            } else if (node != null && node.getNodeType() == Node.ELEMENT_NODE) {
                NamedNodeMap attributes = node.getAttributes();
                injectAttributeParameters(params, soapNs, node, attributes);
                injectParameters((Element) node, params, soapNs, nils);
                Comment comment = YADOMUtil.getCommentBefore((Element) node);
                if(comment != null && comment.getTextContent().endsWith(SOAPUI_OPTIONAL_COMMENT + REMOVE_POSTFIX)) {
                    Node parent = node.getParentNode();
                    parent.removeChild(node);
                    parent.removeChild(comment);
                    childCount -= 2;
                    i -= 2;
                }
            }
        }

        element.removeAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, IS_CLONE_ATTRIB);
        element.removeAttributeNS(OGNLUtils.JBOSSESB_SOAP_NS, OGNLUtils.OGNL_ATTRIB);
    }
   
    private void injectAttributeParameters(Map params, String soapNs, Node node, NamedNodeMap attributes) {
        for (Node attribute : getNodes(attributes)) {
            if (isParameter(attribute)) {
                String localName = attribute.getLocalName();
                String ognl = OGNLUtils.getOGNLExpression((Element)node, soapNs) + "." + localName;
     
                Object param = OGNLUtils.getParameter(ognl, params);
                if (param != null && param.toString().length() > 0) {
                    attribute.setTextContent(param.toString());
                } else {
                    attributes.removeNamedItem(attribute.getNodeName());
                }
            }
        }
    }

    private boolean isParameter(Node node) {
        return node.getTextContent().equals("?");
    }

    private List<Node> getNodes(NamedNodeMap attributes) {
        int len = attributes.getLength();
        List<Node> list = new ArrayList<Node>(len);
        for ( int a = 0 ; a < len ; a++)
        {
            list.add(attributes.item(a));
        }
        return list;
    }


    private static WsdlOperationInfo getWsdlOperationInfo(final Operation operation)
        throws XMLStreamException
    {
        final WsdlOperation wsdlOperation = (WsdlOperation)operation ;
       
        final String requestTemplate = wsdlOperation.createRequest(true);
        final XMLEventReader requestReader = XMLHelper.getXMLEventReader(new StringReader(requestTemplate)) ;
        final List<XMLEvent> requestEvents = ESBStaxXMLEvent.cloneStream(requestReader) ;
       
        final String responseTemplate = wsdlOperation.createResponse(true);
        final List<XMLEvent> responseEvents ;
        if (responseTemplate != null)
        {
            final XMLEventReader responseReader = XMLHelper.getXMLEventReader(new StringReader(responseTemplate)) ;
            responseEvents = ESBStaxXMLEvent.cloneStream(responseReader) ;
        }
        else
        {
            responseEvents = Collections.emptyList() ;
        }

        final MessagePart[] faultParts = wsdlOperation.getFaultParts();
        final Map<String, List<XMLEvent>> faultEventsMap = new HashMap<String, List<XMLEvent>>() ;
       
        final SoapMessageBuilder soapMessageBuilder = wsdlOperation.getInterface().getMessageBuilder();
        final XmlObject detail = XmlObject.Factory.newInstance();
        for(MessagePart messagePart: faultParts)
        {
            final MessagePart.FaultPart faultPart = (MessagePart.FaultPart)messagePart ;
            final String faultName = faultPart.getName() ;
            final SampleXmlUtil generator = new SampleXmlUtil(false) ;
            generator.setExampleContent(false) ;
            generator.setTypeComment(false) ;
            final XmlCursor cursor = detail.newCursor();
            cursor.toFirstContentToken() ;
            generator.setTypeComment(true) ;
            generator.setIgnoreOptional(wsdlOperation.getInterface().getSettings().getBoolean( WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS ) );
            for(Part part: faultPart.getWsdlParts())
            {
                try
                {
                    soapMessageBuilder.createElementForPart(part, cursor, generator);
                }
                catch (final Exception ex)
                {
                    throw new XMLStreamException("Unexpected exception creating fault template", ex) ;
                }
            }
            final String faultTemplate = FAULT_PREFIX + detail.xmlText( new XmlOptions().setSaveAggressiveNamespaces().setSavePrettyPrint()) + FAULT_SUFFIX ;
            final XMLEventReader faultReader = XMLHelper.getXMLEventReader(new StringReader(faultTemplate)) ;
            final List<XMLEvent> faultEvents = ESBStaxXMLEvent.cloneStream(faultReader) ;
            faultEventsMap.put(faultName, faultEvents) ;
        }
        return new WsdlOperationInfo(requestEvents, responseEvents,faultEventsMap) ;
    }

    private static Map<String, WsdlServiceInfo> getServiceInfoMap(final WsdlInterface[] wsdlInterfaces,
        final Map<QName, Map<String, WsdlOperationInfo>> bindingToOperationInfo)
        throws Exception
    {
        final Map<String, WsdlServiceInfo> serviceInfoMap = new HashMap<String, WsdlServiceInfo> () ;

        final Set<String> processed = new HashSet<String>() ;
       
        final Map<QName, WsdlInterface> bindingsToInterface = new HashMap<QName, WsdlInterface>() ;
        for(WsdlInterface wsdlInterface: wsdlInterfaces)
        {
            bindingsToInterface.put(wsdlInterface.getBindingName(), wsdlInterface) ;
        }

        for(WsdlInterface wsdlInterface: wsdlInterfaces)
        {
            final Definition definition = wsdlInterface.getWsdlContext().getDefinition() ;
            processDefinition(definition, processed, bindingToOperationInfo, bindingsToInterface, serviceInfoMap) ;
        }
        return serviceInfoMap ;
    }

    private static void processDefinition(final Definition definition, final Set<String> processed,
        final Map<QName, Map<String, WsdlOperationInfo>> bindingToOperationInfo,
        final Map<QName, WsdlInterface> bindingsToInterface,
        final Map<String, WsdlServiceInfo> serviceInfoMap)
    {
        final String definitionLocation = definition.getDocumentBaseURI() ;
        if (processed.add(definitionLocation))
        {
            final Map<?, Service> services = definition.getServices() ;
            if (services != null)
            {
                for(Service service: services.values())
                {
                    final Map<?, Port> ports = service.getPorts() ;
                    if (ports != null)
                    {
                        String endpoint = null ;
                        String contentType = null ;
                        boolean first = true ;
                        final Map<String, WsdlOperationInfo> operationInfoMap = new HashMap<String, WsdlOperationInfo>() ;
                       
                        for(Port port: ports.values())
                        {
                            final QName bindingName = port.getBinding().getQName() ;
                            if (first)
                            {
                                first = false ;
                                final WsdlInterface bindingWsdlInterface = bindingsToInterface.get(bindingName) ;
                                endpoint = bindingWsdlInterface.getEndpoints()[0] ;
                                contentType = bindingWsdlInterface.getSoapVersion().getContentType() ;
                            }
                           
                            final Map<String, WsdlOperationInfo> bindingOperationInfoMap = bindingToOperationInfo.get(bindingName) ;
                            for(Map.Entry<String, WsdlOperationInfo> entry: bindingOperationInfoMap.entrySet())
                            {
                                final String operationName = entry.getKey() ;
                                final WsdlOperationInfo operationInfo = entry.getValue() ;
                                final WsdlOperationInfo current = operationInfoMap.put(operationName, operationInfo) ;
                                if (current != null)
                                {
                                    operationInfoMap.put(operationName, current) ;
                                }
                            }
                        }
                        final WsdlServiceInfo serviceInfo = new WsdlServiceInfo(endpoint, contentType, operationInfoMap) ;
                        final String serviceName = service.getQName().toString() ;
                        serviceInfoMap.put(serviceName, serviceInfo) ;
                    }
                }
            }
            final Map<?, List<Import>> allImports = definition.getImports() ;
            if (allImports != null)
            {
                for(List<Import> imports: allImports.values())
                {
                    for(Import current: imports)
                    {
                        processDefinition(current.getDefinition(), processed,
                            bindingToOperationInfo, bindingsToInterface, serviceInfoMap) ;
                    }
                }
            }
        }
    }

    public void setServerDataDir(final String datadir)
    {
        this.serverDataDir = datadir;
    }
   
    public String getServerDataDir()
    {
        return serverDataDir;
    }

    /**
     * Wrapper class for smooks resource.
     */
    static class SmooksResource extends LRUReferenceCountCacheResource<Smooks>
    {
        SmooksResource(final Smooks smooks)
        {
            super(smooks) ;
        }

        public void close()
        {
            getInstance().close() ;
        }
    }

    /**
     * Smooks cache implementation.
     */
    static class SmooksCache extends LRUReferenceCountCache<Smooks, SmooksResource>
    {
        SmooksCache(final int lruCacheSize)
        {
            super(lruCacheSize);
        }

        public LRUReferenceCountCacheEntry<Smooks, SmooksResource> get(final String resourceLocation)
            throws UnsupportedEncodingException, SAXException, IOException
        {
            final LRUReferenceCountCacheEntry<Smooks, SmooksResource> entry = internalGet(resourceLocation) ;
            if (entry != null)
            {
                return entry ;
            }
            else
            {
                return create(resourceLocation, createResource(resourceLocation)) ;
            }
        }

        protected SmooksResource createResource(final String resourceLocation)
            throws UnsupportedEncodingException, SAXException, IOException
        {
            final Smooks smooks = new Smooks();
            smooks.addConfigurations("smooks-resource", new ByteArrayInputStream(resourceLocation.getBytes("UTF-8")));
            return new SmooksResource(smooks) ;
        }
    }

    /**
     * Cached operation information.
     */
    static class WsdlOperationInfo
    {
        /**
         * request event stream.
         */
        private final List<XMLEvent> requestEvents ;
        /**
         * response event stream.
         */
        private final List<XMLEvent> responseEvents ;
        /**
         * fault event streams.
         */
        private final Map<String, List<XMLEvent>> faultEventsMap ;

        WsdlOperationInfo(final List<XMLEvent> requestEvents, final List<XMLEvent> responseEvents,
            final Map<String, List<XMLEvent>> faultEventsMap)
        {
            this.requestEvents = requestEvents ;
            this.responseEvents = responseEvents ;
            this.faultEventsMap = faultEventsMap ;
        }

        public List<XMLEvent> getRequestEvents()
        {
            return requestEvents ;
        }

        public List<XMLEvent> getResponseEvents()
        {
            return responseEvents ;
        }

        public List<XMLEvent> getFaultEvents(final String faultName)
        {
            return faultEventsMap.get(faultName) ;
        }
    }

    /**
     * Cached service info.
     */
    static class WsdlServiceInfo
    {
        /**
         * First endpoint.
         */
        private final String endpoint ;
        /**
         * Content type for service.
         */
        private final String contentType ;
        /**
         * Cached operation information.
         */
        private final Map<String, WsdlOperationInfo> operationInfoMap ;

        WsdlServiceInfo(final String endpoint, final String contentType, final Map<String, WsdlOperationInfo> operationInfoMap)
        {
            this.endpoint = endpoint ;
            this.contentType = contentType ;
            this.operationInfoMap = operationInfoMap ;
        }

        public String getEndpoint()
        {
            return endpoint ;
        }

        public String getContentType()
        {
            return contentType ;
        }

        public WsdlOperationInfo getOperation(final String operation)
        {
            return operationInfoMap.get(operation) ;
        }
    }

    /**
     * Internal WSDL state class to allow atomic swapping out during refresh operations.
     */
    static class WsdlInternalState
    {
        private final Set<QName> nils ;
        private final Map<String, WsdlServiceInfo> serviceInfoMap ;
        private final Map<String, WsdlOperationInfo> operationInfoMap = new HashMap<String, WsdlOperationInfo>() ;
        private final String defaultContentType ;
        private final String defaultEndpoint ;

        public WsdlInternalState(final String wsdl, final Properties httpClientProps)
            throws IOException
        {
            try {
                final WsdlProject wsdlProject = new WsdlProject();
                final HttpClient httpClient = HttpClientFactory.createHttpClient(httpClientProps);
                try {
                    EsbWsdlLoader loader = new EsbWsdlLoader(wsdl, httpClient);
                    WsdlLoaderAspect.set(loader); // JBESB-3276
                    final WsdlInterface[] wsdlInterfaces = wsdlProject.importWsdl(wsdl, true, loader);
                    nils = extractNillableElements(wsdl, loader) ;

                    defaultContentType = wsdlInterfaces[0].getSoapVersion().getContentType() ;
                    defaultEndpoint = wsdlInterfaces[0].getEndpoints()[0] ;
                   
                    final Map<QName, Map<String, WsdlOperationInfo>> bindingToOperationInfo = new HashMap<QName, Map<String, WsdlOperationInfo>>() ;
                    for(WsdlInterface wsdlInterface: wsdlInterfaces)
                    {
                        final Map<String, WsdlOperationInfo> bindingOperationInfoMap = new HashMap<String, WsdlOperationInfo>() ;
                        for (Operation operation: wsdlInterface.getOperations())
                        {
                            final String name = operation.getName() ;
                            // we cannot disambiguate further than name, so ignore subsequent ones
                            if (!bindingOperationInfoMap.containsKey(name))
                            {
                                final WsdlOperationInfo info = getWsdlOperationInfo(operation) ;
                                bindingOperationInfoMap.put(name, info) ;
                                final WsdlOperationInfo current = operationInfoMap.put(name, info) ;
                                // Restore first operation detail if already set
                                if (current != null)
                                {
                                    operationInfoMap.put(name, current) ;
                                }
                            }
                        }
                        bindingToOperationInfo.put(wsdlInterface.getBindingName(), bindingOperationInfoMap) ;
                    }
                   
                    serviceInfoMap = getServiceInfoMap(wsdlInterfaces, bindingToOperationInfo) ;
                } finally {
                    WsdlLoaderAspect.unset(); // JBESB-3276
                    HttpClientFactory.shutdown(httpClient);
                }
            } catch (Exception e) {
                IOException ioException = new IOException("Failed to create WSDL state.");
                ioException.initCause(e);
                throw ioException;
            }
        }

        public XMLEventReader getRequest(final String operation, final String serviceName)
        {
            final WsdlOperationInfo operationInfo = getOperationInfo(serviceName, operation) ;
            if (operationInfo != null)
            {
                return new ESBXMLEventStreamReader(operationInfo.getRequestEvents()) ;
            }
            return null ;
        }

        public XMLEventReader getResponse(final String operation, final String serviceName)
        {
            final WsdlOperationInfo operationInfo = getOperationInfo(serviceName, operation) ;
            if (operationInfo != null)
            {
                return new ESBXMLEventStreamReader(operationInfo.getResponseEvents()) ;
            }
            return null ;
        }

        public XMLEventReader getFault(final String faultName, final String operation, final String serviceName)
        {
            final WsdlOperationInfo operationInfo = getOperationInfo(serviceName, operation) ;
            if (operationInfo != null)
            {
                final List<XMLEvent> events = operationInfo.getFaultEvents(faultName) ;
                if (events != null)
                {
                    return new ESBXMLEventStreamReader(events) ;
                }
            }
            return null ;
        }

        public String getDefaultContentType()
        {
            return defaultContentType ;
        }

        public String getDefaultEndpoint()
        {
            return defaultEndpoint ;
        }

        public WsdlOperationInfo getOperationInfo(final String serviceName, final String operation)
        {
            if (serviceName != null)
            {
                final WsdlServiceInfo serviceInfo = getServiceInfo(serviceName) ;
                if (serviceInfo != null)
                {
                    return serviceInfo.getOperation(operation) ;
                }
                return null ;
            }
            else
            {
                return operationInfoMap.get(operation) ;
            }
        }

        public WsdlServiceInfo getServiceInfo(final String serviceName)
        {
            return  serviceInfoMap.get(serviceName) ;
        }

        public Set<QName> getNils()
        {
            return nils ;
        }
    }

    /**
     * WSDL state class supporting refresh of internal state.
     */
    static class WsdlState
    {
        private volatile WsdlInternalState state ;

        WsdlState(final String wsdl, final Properties httpClientProps)
            throws IOException
        {
            state = new WsdlInternalState(wsdl, httpClientProps) ;
        }

        public XMLEventReader getRequest(final String operation, final String serviceName,
            final boolean refresh, final String wsdl, final Properties httpClientProps)
            throws IOException
        {
            final XMLEventReader reader = state.getRequest(operation, serviceName) ;
            if (reader != null)
            {
                return reader ;
            }
            else if (refresh)
            {
                state = new WsdlInternalState(wsdl, httpClientProps) ;
                return getRequest(operation, serviceName, false, null, null) ;
            }
            else
            {
                throw new UnsupportedOperationException("Operation '" + operation + "' not found in service '" + serviceName + "' defined in WSDL '" + wsdl + "'.");
            }
        }

        public XMLEventReader getResponse(final String operation, final String serviceName,
            final boolean refresh, final String wsdl, final Properties httpClientProps)
            throws IOException
        {
            final XMLEventReader reader = state.getResponse(operation, serviceName) ;
            if (reader != null)
            {
                return (reader.hasNext() ? reader : null) ;
            }
            else if (refresh)
            {
                state = new WsdlInternalState(wsdl, httpClientProps) ;
                return getResponse(operation, serviceName, false, null, null) ;
            }
            else
            {
                throw new UnsupportedOperationException("Operation '" + operation + "' not found in service '" + serviceName + "' defined in WSDL '" + wsdl + "'.");
            }
        }

        public XMLEventReader getFault(final String operation, final String serviceName,
            final String faultName, final boolean refresh, final String wsdl, final Properties httpClientProps)
            throws IOException
        {
            final XMLEventReader reader = state.getFault(faultName, operation, serviceName) ;
            if (reader != null)
            {
                return reader ;
            }
            else if (refresh)
            {
                state = new WsdlInternalState(wsdl, httpClientProps) ;
                return getFault(operation, serviceName, faultName, false, null, null) ;
            }
            else
            {
                throw new UnsupportedOperationException("Fault '" + faultName + "' not found in operation '" + operation + "' from service '" + serviceName + "' defined in WSDL '" + wsdl + "'.");
            }
        }

        public String getDefaultContentType()
        {
            return state.getDefaultContentType() ;
        }

        public String getContentType(final String serviceName, final boolean refresh, final boolean fail,
            final String wsdl, final Properties httpClientProps)
            throws IOException
        {
            final WsdlServiceInfo serviceInfo = getServiceInfo(serviceName, refresh, fail, wsdl, httpClientProps) ;
            if (serviceInfo != null)
            {
                return serviceInfo.getContentType() ;
            }
            else
            {
                return null ;
            }
        }

        public String getDefaultEndpoint()
        {
            return state.getDefaultEndpoint() ;
        }

        public String getEndpoint(final String serviceName, final boolean refresh, final boolean fail,
            final String wsdl, final Properties httpClientProps)
            throws IOException
        {
            final WsdlServiceInfo serviceInfo = getServiceInfo(serviceName, refresh, fail, wsdl, httpClientProps) ;
            if (serviceInfo != null)
            {
                return serviceInfo.getEndpoint()  ;
            }
            else
            {
                return null ;
            }
        }

        public WsdlServiceInfo getServiceInfo(final String serviceName, final boolean refresh, final boolean fail, final String wsdl, final Properties httpClientProps)
            throws IOException
        {
            final WsdlServiceInfo serviceInfo = state.getServiceInfo(serviceName) ;
            if (serviceInfo != null)
            {
                return serviceInfo ;
            }
            else if (refresh)
            {
                state = new WsdlInternalState(wsdl, httpClientProps) ;
                return getServiceInfo(serviceName, false, fail, wsdl, httpClientProps) ;
            }
            else if (fail)
            {
                throw new UnsupportedOperationException("Service '" + serviceName + "' not defined in WSDL '" + wsdl + "'.");
            }
            else
            {
                return null ;
            }
        }

        public Set<QName> getNils()
        {
            return state.getNils() ;
        }
    }

    /**
     * Wrapper class for WSDL state resource.
     */
    static class WsdlResource extends LRUReferenceCountCacheResource<WsdlState>
    {
        WsdlResource(final WsdlState state)
        {
            super(state) ;
        }
    }

    /**
     * WSDL cache implementation.
     */
    static class WsdlCache extends LRUReferenceCountCache<WsdlState, WsdlResource>
    {
        WsdlCache(final int lruCacheSize)
        {
            super(lruCacheSize);
        }

        public LRUReferenceCountCacheEntry<WsdlState, WsdlResource> get(final String wsdl, final Properties httpProperties)
            throws IOException
        {
            final LRUReferenceCountCacheEntry<WsdlState, WsdlResource> entry = internalGet(wsdl) ;
            if (entry != null)
            {
                return entry ;
            }
            else
            {
                return create(wsdl, createResource(wsdl, httpProperties)) ;
            }
        }

        protected WsdlResource createResource(final String wsdl, final Properties httpProperties)
            throws IOException
        {
            return new WsdlResource(new WsdlState(wsdl, httpProperties)) ;
        }
    }
}
TOP

Related Classes of org.jboss.soa.esb.services.soapui.SoapUIClientService$SmooksCache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.