/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.axis2.description;

import com.ibm.wsdl.util.xml.DOM2Writer;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.AddressingConstants;
import org.apache.axis2.addressing.AddressingHelper;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.addressing.EndpointReferenceHelper;
import org.apache.axis2.addressing.wsdl.WSDL11ActionHelper;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.util.LoggingControl;
import org.apache.axis2.util.PolicyUtil;
import org.apache.axis2.util.XMLUtils;
import org.apache.axis2.wsdl.SOAPHeaderMessage;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.axis2.wsdl.WSDLUtil;
import org.apache.axis2.wsdl.util.WSDLDefinitionWrapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.neethi.Constants;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyReference;
import org.apache.ws.commons.schema.utils.NamespaceMap;
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 javax.wsdl.Binding;
import javax.wsdl.BindingFault;
import javax.wsdl.BindingInput;
import javax.wsdl.BindingOperation;
import javax.wsdl.BindingOutput;
import javax.wsdl.Definition;
import javax.wsdl.Fault;
import javax.wsdl.Import;
import javax.wsdl.Input;
import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.OperationType;
import javax.wsdl.Output;
import javax.wsdl.Part;
import javax.wsdl.Port;
import javax.wsdl.PortType;
import javax.wsdl.Service;
import javax.wsdl.Types;
import javax.wsdl.WSDLException;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.UnknownExtensibilityElement;
import javax.wsdl.extensions.http.HTTPAddress;
import javax.wsdl.extensions.http.HTTPBinding;
import javax.wsdl.extensions.http.HTTPOperation;
import javax.wsdl.extensions.mime.MIMEMultipartRelated;
import javax.wsdl.extensions.mime.MIMEPart;
import javax.wsdl.extensions.schema.Schema;
import javax.wsdl.extensions.soap.SOAPAddress;
import javax.wsdl.extensions.soap.SOAPBinding;
import javax.wsdl.extensions.soap.SOAPBody;
import javax.wsdl.extensions.soap.SOAPHeader;
import javax.wsdl.extensions.soap.SOAPOperation;
import javax.wsdl.extensions.soap12.SOAP12Address;
import javax.wsdl.extensions.soap12.SOAP12Binding;
import javax.wsdl.extensions.soap12.SOAP12Body;
import javax.wsdl.extensions.soap12.SOAP12Header;
import javax.wsdl.extensions.soap12.SOAP12Operation;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLLocator;
import javax.wsdl.xml.WSDLReader;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Vector;

public class WSDL11ToAxisServiceBuilder extends WSDLToAxisServiceBuilder {

    public static final int COMPONENT_PORT_TYPE = 1;
    public static final int COMPONENT_MESSAGE = 2;
    public static final int COMPONENT_BINDING = 3;

    protected static final Log log = LogFactory
            .getLog(WSDL11ToAxisServiceBuilder.class);
    private static final boolean isTraceEnabled = log.isTraceEnabled();

    protected String portName;

    private static final String BINDING = "Binding";

    private static final String SERVICE = "Service";

    private static final String PORT = "Port";

    private static final String PORT_TYPE = "PortType";

    private static final String PORT_TYPE_OPERATION = "PortType.Operation";

    private static final String PORT_TYPE_OPERATION_INPUT = "PortType.Operation.Input";

    private static final String PORT_TYPE_OPERATION_OUTPUT = "PortType.Operation.Output";

    private static final String PORT_TYPE_OPERATION_FAULT = "PortType.Operation.Fault";

    private static final String BINDING_OPERATION = "Binding.Operation";

    private static final String BINDING_OPERATION_INPUT = "Binding.Operation.Input";

    private static final String BINDING_OPERATION_OUTPUT = "Binding.Operation.Output";

    protected Definition wsdl4jDefinition = null;
    protected String     wsdlBaseDocumentURI = null;

    private WSDLLocator customWSDLResolver;

    public static final String RPC_STYLE = "rpc";

    public static final String DOCUMENT_STYLE = "document";

    public static final String ENCODED_USE = "encoded";

    /**
     * List of BindingOperationEntry objects.
     * Each object in the list may require a wrapped schema element for 
     * the input/output or both.
     */
    private List wrappableBOEs = new ArrayList();
    // used to keep the binding type of the selected binding
    private String bindingType;

    public static final String WRAPPED_OUTPUTNAME_SUFFIX = "Response";

    public static final String XML_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";

    public static final String NAMESPACE_DECLARATION_PREFIX = "xmlns:";

    private static int prefixCounter = 0;

    public static final String NAMESPACE_URI = "namespace";

    public static final String TRAGET_NAMESPACE = "targetNamespace";

    public static final String BINDING_TYPE_SOAP = "soap";
    public static final String BINDING_TYPE_HTTP = "http";

    /**
     * keep track of whether setup code related to the entire wsdl is complete.
     * Note that WSDL11ToAllAxisServices will call setup multiple times, so this
     * field is used to make subsequent calls no-ops.
     */
    private boolean setupComplete = false;

    private Map schemaMap = null;

    private static final String JAVAX_WSDL_VERBOSE_MODE_KEY = "javax.wsdl.verbose";

    // As bindings are processed add it to this array so that we dont process the same binding twice
    private Map processedBindings;

    private boolean isAllPorts;

    /**
     * constructor taking in the service name and the port name
     *
     * @param in - InputStream for the WSDL
     * @param serviceName - The service Name
     * @param portName - The port name
     */
    public WSDL11ToAxisServiceBuilder(InputStream in, QName serviceName,
                                      String portName) {
        super(in, serviceName);
        this.portName = portName;
    }

    /**
     * @param def - The WSDL4J Definition object
     * @param serviceName - The service Name
     * @param portName - The port name
     */
    public WSDL11ToAxisServiceBuilder(Definition def, QName serviceName,
                                      String portName) {
        super(null, serviceName);
        this.wsdl4jDefinition = def;
        this.portName = portName;
        this.isAllPorts = false;
    }

    /**
     * @param def - The WSDL4J Definition object
     * @param serviceName - The service Name
     * @param portName - The port name
     * @param isAllPorts - boolean representing whether to generate code for all ports or not
     */
    public WSDL11ToAxisServiceBuilder(Definition def,
                                      QName serviceName,
                                      String portName,
                                      boolean isAllPorts) {
        this(def, serviceName, portName);
        this.isAllPorts = isAllPorts;
    }


    /**
     * @param in
     * @param service
     */
    public WSDL11ToAxisServiceBuilder(InputStream in, AxisService service) {
        super(in, service);
    }

    /**
     * @param in
     */
    public WSDL11ToAxisServiceBuilder(InputStream in) {
        this(in, null, null);
    }

    /**
     * @deprecated
     * @see setCustomWSDLResolver
     */
    public void setCustomWSLD4JResolver(WSDLLocator customResolver) {
        setCustomWSDLResolver(customResolver);
    }


    /**
     * sets a custom WSDL locator
     *
     * @param customResolver
     */
    public void setCustomWSDLResolver(WSDLLocator customResolver) {
        this.customWSDLResolver = customResolver;
        setDocumentBaseUri(this.customWSDLResolver.getBaseURI());
    }


    /**
     * Sets the URI to the base document associated with the WSDL definition.
     * This identifies the origin of the Definition and allows the
     * Definition to be reloaded.  Note that this is the URI of the base
     * document, not the imports.
     *
     * @param baseUri
     */
    public void setDocumentBaseUri(String baseUri) {
        if (wsdl4jDefinition != null) {
            wsdl4jDefinition.setDocumentBaseURI(baseUri);
        }
        wsdlBaseDocumentURI = baseUri;
    }

    /**
     * Gets the URI to the base document associated with the WSDL definition.
     * This identifies the origin of the Definition and allows the
     * Definition to be reloaded.  Note that this is the URI of the base
     * document, not the imports.
     *
     */
    public String getDocumentBaseUri() {
        return wsdlBaseDocumentURI;
    }




    /**
     * Populates a given service.
     *
     * @throws AxisFault
     */
    public AxisService populateService() throws AxisFault {
        try {
            setup();

            // NOTE: set the axisService with the Parameter for the WSDL
            // Definition after the rest of the work

            if (wsdl4jDefinition == null) {
                return null;
            }

            // setting target name space
            axisService.setTargetNamespace(wsdl4jDefinition.getTargetNamespace());
            axisService.setNamespaceMap(new NamespaceMap(wsdl4jDefinition.getNamespaces()));
            
            Map importsMap = wsdl4jDefinition.getImports();
            
            if (importsMap != null) {
                List imports = new ArrayList(importsMap.keySet());
                axisService.setImportedNamespaces(imports);
            }
            
            //TODO : find the service also in imported wsdls
            Service wsdl4jService = findService(wsdl4jDefinition);

            Binding binding = findBinding(wsdl4jDefinition, wsdl4jService);
            Definition bindingWSDL = getParentDefinition(wsdl4jDefinition,
                    binding.getQName(), COMPONENT_BINDING, new HashSet());
            Definition portTypeWSDL = getParentDefinition(bindingWSDL,
                    binding.getPortType().getQName(), COMPONENT_PORT_TYPE, new HashSet());
            PortType portType = portTypeWSDL.getPortType(binding.getPortType().getQName());


            if (portType == null) {
                throw new AxisFault("There is no port type associated with the binding");
            }

            // create new Schema extensions element for wrapping
            // (if its present)
            Element[] schemaElements = generateWrapperSchema(schemaMap, binding, portType);

            processTypes(wsdl4jDefinition, axisService);

            // add the newly created schemas
            if (schemaElements != null && schemaElements.length > 0) {
                for (int i = 0; i < schemaElements.length; i++) {
                    Element schemaElement = schemaElements[i];
                    if (schemaElement != null) {
                        axisService.addSchema(getXMLSchema(schemaElement, null));
                    }
                }
            }
            // copy the documentation element content to the description
            Element documentationElement = wsdl4jDefinition.getDocumentationElement();
            addDocumentation(axisService, documentationElement);

            axisService.setName(wsdl4jService.getQName().getLocalPart());
            populateEndpoints(binding, bindingWSDL,wsdl4jService, portType, portTypeWSDL);
            processPoliciesInDefintion(wsdl4jDefinition);
            axisService.getPolicyInclude().setPolicyRegistry(registry);


            // Setting wsdl4jdefintion to the axisService parameter include list,
            // so if someone needs to use the definition directly,
            // he can do that by getting the parameter
            Parameter wsdlDefinitionParameter = new Parameter();
            wsdlDefinitionParameter.setName(WSDLConstants.WSDL_4_J_DEFINITION);

            if (!(wsdl4jDefinition instanceof WSDLDefinitionWrapper)) {
                AxisConfiguration ac = axisService.getAxisConfiguration();
                if (ac == null) {
                    ac = this.axisConfig;
                }
                WSDLDefinitionWrapper wrapper = new WSDLDefinitionWrapper(wsdl4jDefinition, ac);
                wsdlDefinitionParameter.setValue(wrapper);
            } else {
                wsdlDefinitionParameter.setValue(wsdl4jDefinition);
            }

            axisService.addParameter(wsdlDefinitionParameter);
            axisService.setWsdlFound(true);
            axisService.setCustomWsdl(true);


            return axisService;

        } catch (WSDLException e) {
            log.error(e.getMessage(), e);
            throw AxisFault.makeFault(e);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw AxisFault.makeFault(e);
        }
    }

    private void processTypes(Definition wsdlDefinition, AxisService axisService)
            throws AxisFault {
        processTypes(wsdlDefinition, axisService, new HashSet());
    }

    private void processTypes(Definition wsdlDefinition,
                              AxisService axisService,
                              Set visitedWSDLs)
            throws AxisFault {
        visitedWSDLs.add(wsdlDefinition.getDocumentBaseURI());
        // process all the types in all the wsdls
        Types types = wsdlDefinition.getTypes();
        if (types != null) {
            copyExtensibleElements(types.getExtensibilityElements(),
                                   wsdlDefinition,
                                   axisService,
                                   TYPES);
        }

        // process the types in other wsdls
        Iterator iter = wsdlDefinition.getImports().values().iterator();
        Vector values = null;
        Import wsdlImport = null;
        for (; iter.hasNext();) {
            values = (Vector) iter.next();
            for (Iterator valuesIter = values.iterator(); valuesIter.hasNext();) {
                wsdlImport = (Import) valuesIter.next();
                // process the types recuresiveilt
                Definition innerDefinition = wsdlImport.getDefinition();
                if(!visitedWSDLs.contains(innerDefinition.getDocumentBaseURI())){
                    processTypes(innerDefinition, axisService, visitedWSDLs);
                }
            }
        }
    }

    private void addDocumentation(AxisDescription axisDescription, Element documentationElement) {
        if ((documentationElement != null) && (documentationElement.getFirstChild() != null)) {
            Node firstChild = documentationElement.getFirstChild();
            String documentation = DOM2Writer.nodeToString(firstChild);
            if (!"".equals(documentation)) {
                axisDescription.setDocumentation(documentation);
            }
        }
    }

    /**
     * @param binding
     * @param wsdl4jService must have atlease one port
     * @throws AxisFault
     */
    private void populateEndpoints(Binding binding,
                                   Definition bindingWSDL,
                                   Service wsdl4jService,
                                   PortType portType,
                                   Definition portTypeWSDL) throws AxisFault {

        Map wsdl4jPorts = wsdl4jService.getPorts();
        QName bindingName = binding.getQName();

        Port port;
        AxisEndpoint axisEndpoint = null;

        processedBindings = new HashMap();

        // process the port type for this binding
        // although we support multiports they must be belongs to same port type and should have the
        // same soap style
        populatePortType(portType, portTypeWSDL);

        Binding currentBinding;
        Definition currentBindingWSDL = null;

        for (Iterator iterator = wsdl4jPorts.values().iterator(); iterator.hasNext();) {
            port = (Port) iterator.next();
            // if the user has picked a port then we have to process only that port
            if ((this.portName == null) || (this.portName.equals(port.getName()))) {
                // we process the port only if it has the same port type as the selected binding
                currentBindingWSDL = getParentDefinition(wsdl4jDefinition,
                        port.getBinding().getQName(), COMPONENT_BINDING, new HashSet());
                currentBinding = currentBindingWSDL.getBinding(port.getBinding().getQName());

                if (currentBinding.getPortType().getQName().equals(binding.getPortType().getQName())) {
                    axisEndpoint = new AxisEndpoint();
                    axisEndpoint.setName(port.getName());

                    if (axisService.getEndpointName() == null &&
                            bindingName.equals(port.getBinding().getQName())) {
                        populateEndpoint(axisEndpoint, port, currentBinding,
                                bindingWSDL, portType, portTypeWSDL, true);
                        axisService.setEndpointName(axisEndpoint.getName());
                        axisService.setBindingName(axisEndpoint.getBinding().getName().getLocalPart());
                    } else {
                        populateEndpoint(axisEndpoint, port, currentBinding,
                                bindingWSDL, portType, portTypeWSDL, false);
                    }

                    axisEndpoint.setParent(axisService);
                    axisService.addEndpoint(port.getName(), axisEndpoint);
                }
            }
        }
    }

    /**
     * setting message qname is a binding dependent process for an example message element depends on the
     * soap style (rpc or document) and parts elememet of the soap body
     * On the otherhand we keep only one set of axis operations belongs to a selected port type in axis service
     * So setting qname refetences done only with the selected binding processing
     *
     * @param axisEndpoint
     * @param wsdl4jPort
     * @param isSetMessageQNames
     * @throws AxisFault
     */
    private void populateEndpoint(AxisEndpoint axisEndpoint,
                                  Port wsdl4jPort,
                                  Binding wsdl4jBinding,
                                  Definition bindingWSDL,
                                  PortType portType,
                                  Definition portTypeWSDL,
                                  boolean isSetMessageQNames)
            throws AxisFault {

        copyExtensibleElements(wsdl4jPort.getExtensibilityElements(), wsdl4jDefinition,
                               axisEndpoint, BINDING);
        processEmbeddedEPR(wsdl4jPort.getExtensibilityElements(), axisEndpoint);
        addDocumentation(axisEndpoint, wsdl4jPort.getDocumentationElement());
        if (processedBindings.containsKey(wsdl4jBinding.getQName())) {
            axisEndpoint.setBinding(
                    (AxisBinding) processedBindings.get(wsdl4jBinding.getQName()));
        } else {
            AxisBinding axisBinding = new AxisBinding();
            axisBinding.setName(wsdl4jBinding.getQName());
            axisBinding.setParent(axisEndpoint);
            axisEndpoint.setBinding(axisBinding);
            axisBinding.setParent(axisEndpoint);
            populateBinding(axisBinding,
                    wsdl4jBinding,
                    bindingWSDL,
                    portType,
                    portTypeWSDL,
                    isSetMessageQNames);
            processedBindings.put(wsdl4jBinding.getQName(), axisBinding);
        }
    }

    private void processEmbeddedEPR(List extensibilityElements, AxisEndpoint axisEndpoint) {
    	Iterator eelts = extensibilityElements.iterator();
    	while(eelts.hasNext()){
    		ExtensibilityElement ee = (ExtensibilityElement)eelts.next();
    		if(AddressingConstants.Final.WSA_ENDPOINT_REFERENCE.equals(ee.getElementType())){
    			try {
    				Element elt = ((UnknownExtensibilityElement)ee).getElement();
    				OMElement eprOMElement = XMLUtils.toOM(elt);
    				EndpointReference epr = EndpointReferenceHelper.fromOM(eprOMElement);
    				Map referenceParameters = epr.getAllReferenceParameters();
    				if(referenceParameters != null){
    					axisEndpoint.addParameter(AddressingConstants.REFERENCE_PARAMETER_PARAMETER, new ArrayList(referenceParameters.values()));
    				}
    			} catch (Exception e) {
    				if(log.isDebugEnabled()){
    					log.debug("Exception encountered processing embedded wsa:EndpointReference", e);
    				}
    			}
    		}
    	}
    }

	private void populatePortType(PortType wsdl4jPortType,
                                  Definition portTypeWSDL) throws AxisFault {
		copyExtensionAttributes(wsdl4jPortType.getExtensionAttributes(),
				axisService, PORT_TYPE);
        List wsdl4jOperations = wsdl4jPortType.getOperations();

        // Added to use in ?wsdl2 as the interface name
        axisService.addParameter(new Parameter(WSDL2Constants.INTERFACE_LOCAL_NAME,
                                               wsdl4jPortType.getQName().getLocalPart()));
        if (wsdl4jOperations.size() < 1) {
            throw new AxisFault("No operation found in the portType element");
        }

        AxisOperation axisOperation;
        List operationNames = new ArrayList();

        QName opName;
        Operation wsdl4jOperation;

        for (Iterator iterator = wsdl4jOperations.iterator(); iterator.hasNext();) {
            wsdl4jOperation = (Operation) iterator.next();

            axisOperation = populateOperations(wsdl4jOperation, wsdl4jPortType, portTypeWSDL);
            addDocumentation(axisOperation, wsdl4jOperation.getDocumentationElement());
            axisOperation.setParent(axisService);
            axisService.addChild(axisOperation);
            operationNames.add(axisOperation.getName());
        }

        // this is used only in codegen to preserve operation order
        if (isCodegen) {
            axisService.setOperationsNameList(operationNames);
        }

    }

    private void populateBinding(AxisBinding axisBinding,
                                 Binding wsdl4jBinding,
                                 Definition bindingWSDL,
                                 PortType portType,
                                 Definition portTypeWSDL,
                                 boolean isSetMessageQNames)
            throws AxisFault {

        copyExtensibleElements(wsdl4jBinding.getExtensibilityElements(), bindingWSDL,
                               axisBinding, BINDING);

        List wsdl4jBidingOperations = wsdl4jBinding.getBindingOperations();

        if (wsdl4jBidingOperations.size() < 1) {
            throw new AxisFault("No operation found for the binding");
        }

        addDocumentation(axisBinding, wsdl4jBinding.getDocumentationElement());

        AxisOperation axisOperation;
        Operation wsdl4jOperation;

        AxisBindingOperation axisBindingOperation;
        BindingOperation wsdl4jBindingOperation;

        Map httpLocationMap = new TreeMap();
        String httpLocation = null;

        for (Iterator iterator = wsdl4jBidingOperations.iterator(); iterator.hasNext();) {

            axisBindingOperation = new AxisBindingOperation();
            wsdl4jBindingOperation = (BindingOperation) iterator.next();
            wsdl4jOperation = findOperation(portType, wsdl4jBindingOperation);

            axisBindingOperation.setName(new QName(bindingWSDL.getTargetNamespace(), wsdl4jBindingOperation.getName()));
            addDocumentation(axisBindingOperation, wsdl4jBindingOperation.getDocumentationElement());

            axisOperation = axisService.getOperation(new QName(portTypeWSDL.getTargetNamespace(), wsdl4jOperation.getName()));
            axisBindingOperation.setAxisOperation(axisOperation);

            // process ExtensibilityElements of the wsdl4jBinding
            copyExtensibleElements(wsdl4jBindingOperation.getExtensibilityElements(),
                                   wsdl4jDefinition, axisBindingOperation, BINDING_OPERATION);

            httpLocation =
                    (String) axisBindingOperation.getProperty(WSDL2Constants.ATTR_WHTTP_LOCATION);
            String httpMethod =
                    (String) axisBindingOperation.getProperty(WSDL2Constants.ATTR_WHTTP_METHOD);
            if (httpMethod == null || "".equals(httpMethod)) {
                httpMethod = HTTPConstants.HEADER_POST;
            }
            if (httpLocation != null) {
                httpLocationMap.put(WSDLUtil.getConstantFromHTTPLocation(httpLocation, httpMethod),
                                    axisBindingOperation.getAxisOperation());
            }

            BindingInput wsdl4jBindingInput = wsdl4jBindingOperation.getBindingInput();

            if (wsdl4jBindingInput != null &&
                WSDLUtil.isInputPresentForMEP(axisOperation.getMessageExchangePattern())) {
                AxisBindingMessage axisBindingInMessage = new AxisBindingMessage();
                addDocumentation(axisBindingInMessage, wsdl4jBindingInput.getDocumentationElement());
                copyExtensibleElements(wsdl4jBindingInput.getExtensibilityElements(),
                                       wsdl4jDefinition,
                                       axisBindingInMessage, BINDING_OPERATION_INPUT);

                AxisMessage axisInMessage =
                        axisOperation.getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
                //This is a hack to get AXIS2-2771 working , I had to copy soap headers
                //  from binding message to AxisMessage
                List soapHeaders = (List) axisBindingInMessage.getProperty(
                        WSDL2Constants.ATTR_WSOAP_HEADER);
                if (soapHeaders != null) {
                    for (int i = 0; i < soapHeaders.size(); i++) {
                        SOAPHeaderMessage headerMessage = (SOAPHeaderMessage) soapHeaders.get(i);
                        axisInMessage.addSoapHeader(headerMessage);
                    }
                }

                if (isSetMessageQNames) {
                    BindingOperationEntry boe = find(wrappableBOEs, wsdl4jBindingOperation);
                    boolean isWrapped = (boe == null) ? false : boe.isWrappedInput();
                    axisInMessage.setWrapped(isWrapped);
                    addQNameReference(axisInMessage, wsdl4jOperation,
                                      wsdl4jBindingInput,
                                      isWrapped);
                }

                axisBindingInMessage.setAxisMessage(axisInMessage);
                axisBindingInMessage.setName(axisInMessage.getName());
                axisBindingInMessage.setDirection(axisInMessage.getDirection());

                axisBindingInMessage.setParent(axisBindingOperation);
                axisBindingOperation
                        .addChild(WSDLConstants.MESSAGE_LABEL_IN_VALUE, axisBindingInMessage);
            }

            BindingOutput wsdl4jBindingOutput = wsdl4jBindingOperation.getBindingOutput();

            if (wsdl4jBindingOutput != null &&
                WSDLUtil.isOutputPresentForMEP(axisOperation.getMessageExchangePattern())) {
                AxisBindingMessage axisBindingOutMessage = new AxisBindingMessage();
                addDocumentation(axisBindingOutMessage, wsdl4jBindingOutput.getDocumentationElement());
                AxisMessage axisOutMessage =
                        axisOperation.getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);

                copyExtensibleElements(wsdl4jBindingOutput.getExtensibilityElements(),
                                       wsdl4jDefinition,
                                       axisBindingOutMessage, BINDING_OPERATION_OUTPUT);

                //This is a hack to get AXIS2-2771 working , I had to copy soap headers
                //  from binding message to AxisMessage
                List soapHeaders =
                        (List) axisBindingOutMessage.getProperty(WSDL2Constants.ATTR_WSOAP_HEADER);
                if (soapHeaders != null) {
                    for (int i = 0; i < soapHeaders.size(); i++) {
                        SOAPHeaderMessage headerMessage = (SOAPHeaderMessage) soapHeaders.get(i);
                        axisOutMessage.addSoapHeader(headerMessage);
                    }
                }

                if (isSetMessageQNames) {
                    BindingOperationEntry boe = find(wrappableBOEs, wsdl4jBindingOperation);
                    boolean isWrapped = (boe == null) ? false : boe.isWrappedOutput();
                    axisOutMessage.setWrapped(isWrapped);
                    addQNameReference(axisOutMessage, wsdl4jOperation,
                                      wsdl4jBindingOutput,
                                      isWrapped);
                }


                axisBindingOutMessage.setAxisMessage(axisOutMessage);
                axisBindingOutMessage.setName(axisOutMessage.getName());
                axisBindingOutMessage.setDirection(axisOutMessage.getDirection());

                axisBindingOutMessage.setParent(axisBindingOperation);
                axisBindingOperation
                        .addChild(WSDLConstants.MESSAGE_LABEL_OUT_VALUE, axisBindingOutMessage);
            }

            Map bindingFaultsMap = wsdl4jBindingOperation.getBindingFaults();

            /* process the binding faults */
            for (Iterator bindingFaults = bindingFaultsMap.values().iterator();
                 bindingFaults.hasNext();) {

                BindingFault bindingFault = (BindingFault) bindingFaults.next();
                if (bindingFault.getName() == null) {
                    throw new AxisFault("Binding name is null for the binding fault in " +
                            " binding operation ==> " + wsdl4jBindingOperation.getName());
                } else {
                    Fault wsdl4jFault = wsdl4jOperation.getFault(bindingFault.getName());
                    if (wsdl4jFault == null){
                        throw new AxisFault("Can not find the corresponding fault element in " +
                                "wsdl operation " + wsdl4jOperation.getName() + " for the fault" +
                                " name " + bindingFault.getName());
                    } else {
                        Message wsdl4jFaultMessge = wsdl4jFault.getMessage();

                        AxisMessage faultMessage = findFaultMessage(
                                wsdl4jFaultMessge.getQName().getLocalPart(),
                                axisOperation.getFaultMessages());

                        AxisBindingMessage axisBindingFaultMessage = new AxisBindingMessage();
                        addDocumentation(axisBindingFaultMessage, wsdl4jFaultMessge.getDocumentationElement());
                        axisBindingFaultMessage.setFault(true);
                        axisBindingFaultMessage.setAxisMessage(faultMessage);
                        axisBindingFaultMessage.setName(faultMessage.getName());
                        axisBindingFaultMessage.setParent(axisBindingOperation);

                        axisBindingOperation.addFault(axisBindingFaultMessage);
                        if (isSetMessageQNames) {
                            addQNameReference(faultMessage, wsdl4jFault.getMessage());
                        }
                    }
                }
            }

            axisBindingOperation.setParent(axisBinding);
            axisBinding.addChild(axisBindingOperation.getName(), axisBindingOperation);
        }
        axisBinding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationMap);
    }

    /**
     * contains all code which gathers non-service specific information from the
     * wsdl. <p/> After all the setup completes successfully, the setupComplete
     * field is set so that any subsequent calls to setup() will result in a
     * no-op. Note that subclass WSDL11ToAllAxisServicesBuilder will call
     * populateService for each port in the WSDL. Separating the non-service
     * specific information here allows WSDL11ToAllAxisServicesBuilder to only
     * do this work 1 time per WSDL, instead of for each port on each service.
     *
     * @throws WSDLException if readInTheWSDLFile fails
     */
    protected void setup() throws WSDLException {
        if (setupComplete) { // already setup, just do nothing and return
            return;
        }
        if (wsdl4jDefinition == null) {
            wsdl4jDefinition = readInTheWSDLFile(in);
        }
        if (wsdl4jDefinition == null) {
            return; // can't continue without wsdl
        }


        // setup the schemaMap
        this.schemaMap = new HashMap();
        populateSchemaMap(wsdl4jDefinition, new HashSet());

        setPolicyRegistryFromService(axisService);

        setupComplete = true; // if any part of setup fails, don't mark
        // setupComplete
    }


    /**
     * Populate a map of targetNamespace vs DOM schema element This is used to
     * grab the correct schema element when adding a new element
     *
     * @param definition
     */

    private void populateSchemaMap(Definition definition, Set visitedWSDLs) {
        visitedWSDLs.add(definition.getDocumentBaseURI());
        // first process the types in the given wsdl
        Types types = definition.getTypes();
        Object extensibilityElement;
        if (types != null) {
            for (Iterator iterator = types.getExtensibilityElements().iterator(); iterator.hasNext();)
            {
                extensibilityElement = iterator.next();
                if (extensibilityElement instanceof Schema) {
                    Element schemaElement = ((Schema) extensibilityElement).getElement();
                    schemaMap.put(schemaElement.getAttribute(XSD_TARGETNAMESPACE), schemaElement);
                }
            }
        }

        // popualte the imports as well
        Iterator iter = definition.getImports().values().iterator();
        Vector values = null;
        Import wsdlImport = null;
        for (; iter.hasNext();) {
            values = (Vector) iter.next();
            for (Iterator valuesIter = values.iterator(); valuesIter.hasNext();) {
                wsdlImport = (Import) valuesIter.next();
                Definition innerDefinition = wsdlImport.getDefinition();
                if(!visitedWSDLs.contains(innerDefinition.getDocumentBaseURI())) {
                    populateSchemaMap(innerDefinition, visitedWSDLs);
                }
            }
        }
    }


    /**
     * return the service to process
     * if user has specified we check whether it exists
     * else pick a random service and throws an exception if not found any thing
     *
     * @param definition
     * @return service to process
     * @throws AxisFault
     */

    private Service findService(Definition definition) throws AxisFault {
        Map services = definition.getServices();
        Service service = null;
        if (serviceName != null) {
            // i.e if a user has specified a pirticular port
            service = (Service) services.get(serviceName);
            if (service == null) {
                throw new AxisFault("Service " + serviceName
                                    + " was not found in the WSDL");
            }
        } else {
            if (services.size() > 0) {
                for (Iterator iter = services.values().iterator(); iter.hasNext();) {
                    service = (Service) iter.next();
                    if (service.getPorts().size() > 0) {
                        //i.e we have found a service with ports
                        break;
                    }
                }
                if ((service == null) || (service.getPorts().size() == 0)) {
                    throw new AxisFault("there is no service with ports to pick");
                }

            } else {
                throw new AxisFault("No service was not found in the WSDL at " +
                                    definition.getDocumentBaseURI()
                                    + " with targetnamespace "
                                    + definition.getTargetNamespace());
            }
        }
        return service;
    }

    /**
     * Look for the relevant binding!
     * if user has spcifed a port get it
     * otherwise find first soap port or pick random one if there is no soap port
     *
     * @param dif
     * @param service service can not be null
     * @throws AxisFault
     */
    private Binding findBinding(Definition dif, Service service) throws AxisFault {

        Binding binding = null;
        Port port = null;
        copyExtensibleElements(service.getExtensibilityElements(), dif, axisService, SERVICE);
        if (portName != null) {
            // i.e if user has specified a service
            port = service.getPort(portName);
            if (port == null) {
                throw new AxisFault("No port found for the given name :" + portName);
            }
        } else {
            Map ports = service.getPorts();
            if (ports != null && ports.size() > 0) {
                // pick the port with the SOAP address as the default port
                port = findPort(ports);
                if (port == null) {
                    // a SOAP port was not found - log a warning
                    // and use the first port in the list
                    log.info("A SOAP port was not found - "
                             + "picking a random port!");
                    port = (Port) ports.values().toArray()[0];
                }

                if (port != null) {
                    // i.e we have find a correct port
                    // this is only use full in codegen time.
                    if (this.isCodegen && !this.isAllPorts) {
                        // if user has not set all option
                        // we have to generate code only for that option.
                        this.portName = port.getName();
                    }
                }
            }
        }

        axisService.setName(service.getQName().getLocalPart());

        if (port != null) {
            copyExtensibleElements(port.getExtensibilityElements(), dif,
                                   axisService, PORT);
            Definition parentDefinition = getParentDefinition(dif,
                    port.getBinding().getQName(), COMPONENT_BINDING, new HashSet());
            binding = parentDefinition.getBinding(port.getBinding().getQName());
            if (binding == null) {
                binding = port.getBinding();
            }
        }

        return binding;
    }

    /**
     * Finds a SOAP port given the port map
     */
    private Port findPort(Map ports) {
        Port port;
        Port returnPort = null;
        for (Iterator portsIterator = ports.values().iterator(); portsIterator.hasNext();) {
            port = (Port) portsIterator.next();
            List extensibilityElements = port.getExtensibilityElements();
            for (int i = 0; i < extensibilityElements.size(); i++) {
                Object extElement = extensibilityElements.get(i);
                if (extElement instanceof SOAP12Address) {
                    // SOAP 1.2 address found - keep this and loop until http address is found
                    returnPort = port;
                    String location = ((SOAP12Address)extElement).getLocationURI().trim();
                    if ((location != null) && location.startsWith("http:")){
                        // i.e we have found an http port so return from here
                       break;
                    }
                }
            }
        }

        if (returnPort != null){
            return returnPort;
        }

        for (Iterator portsIterator = ports.values().iterator(); portsIterator
                .hasNext();) {
            port = (Port) portsIterator.next();
            List extensibilityElements = port.getExtensibilityElements();
            for (int i = 0; i < extensibilityElements.size(); i++) {
                Object extElement = extensibilityElements.get(i);
                if (extElement instanceof SOAPAddress) {
                    // SOAP 1.1 address found - keep this and loop until http address is found
                    returnPort = port;
                    String location = ((SOAPAddress)extElement).getLocationURI().trim();
                    if ((location != null) && location.startsWith("http:")){
                        // i.e we have found an http port so return from here
                       break;
                    }
                }
            }
        }

        if (returnPort != null){
            return returnPort;
        }

        for (Iterator portsIterator = ports.values().iterator(); portsIterator
                .hasNext();) {
            port = (Port) portsIterator.next();
            List extensibilityElements = port.getExtensibilityElements();
            for (int i = 0; i < extensibilityElements.size(); i++) {
                Object extElement = extensibilityElements.get(i);
                if (extElement instanceof HTTPAddress) {
                    // HTTP address found - keep this and loop until http address is found
                    returnPort = port;
                    String location = ((HTTPAddress)extElement).getLocationURI().trim();
                    if ((location != null) && location.startsWith("http:")){
                        // i.e we have found an http port so return from here
                       break;
                    }
                }
            }
        }
        return returnPort;
    }

    private Operation findOperation(PortType portType,
                                    BindingOperation wsdl4jBindingOperation) {
        Operation op = wsdl4jBindingOperation.getOperation();
        String input = null;
        if (op != null && op.getInput() != null) {
            input = op.getInput().getName();
            if (":none".equals(input)) {
                input = null;
            }
        }
        String output = null;
        if (op != null && op.getOutput() != null) {
            output = op.getOutput().getName();
            if (":none".equals(output)) {
                output = null;
            }
        }
        Operation op2 = portType.getOperation(op.getName(), input, output);
        return ((op2 == null) ? op : op2);
    }

    /**
     * Find the fault message relevant to a given name from the fault message
     * list
     *
     * @param name
     * @param faultMessages
     */
    private AxisMessage findFaultMessage(String name, ArrayList faultMessages) {
        AxisMessage tempMessage;
        for (int i = 0; i < faultMessages.size(); i++) {
            tempMessage = (AxisMessage) faultMessages.get(i);
            if (name.equals(tempMessage.getName())) {
                return tempMessage;
            }

        }
        return null;
    }

    /**
     * Add the QName for the binding input
     *
     * @param inMessage
     * @param wsdl4jOperation
     * @param bindingInput
     * @param isWrapped       - basically whether the operation is soap/rpc or not
     */
    private void addQNameReference(AxisMessage inMessage,
                                   Operation wsdl4jOperation, BindingInput bindingInput,
                                   boolean isWrapped) {

        List extensibilityElements = bindingInput.getExtensibilityElements();
        Message wsdl4jMessage = wsdl4jOperation.getInput().getMessage();

        addQNameReference(inMessage,
                          wsdl4jOperation,
                          isWrapped,
                          extensibilityElements,
                          wsdl4jMessage,
                          wsdl4jOperation.getName());
    }

    /**
     * Add the QName for the binding output
     *
     * @param outMessage
     * @param wsdl4jOperation
     * @param isWrapped
     */
    private void addQNameReference(AxisMessage outMessage,
                                   Operation wsdl4jOperation, BindingOutput bindingOutput,
                                   boolean isWrapped) {

        if (bindingOutput != null) {
            List extensibilityElements = bindingOutput.getExtensibilityElements();
            if (wsdl4jOperation.getOutput() == null) {
                return;
            }
            Message wsdl4jMessage = wsdl4jOperation.getOutput().getMessage();

            addQNameReference(outMessage,
                              wsdl4jOperation,
                              isWrapped,
                              extensibilityElements,
                              wsdl4jMessage,
                              wsdl4jOperation.getName() + WRAPPED_OUTPUTNAME_SUFFIX);
        }
    }

    private void addQNameReference(AxisMessage message,
                                   Operation wsdl4jOperation,
                                   boolean isWrapped,
                                   List extensibilityElements,
                                   Message wsdl4jMessage,
                                   String rpcOperationName) {
        if (isWrapped) {
            // we have already validated and process the qname references
            // so set it here
            // The schema for this should be already made ! Find the
            // QName from
            // the list and add it - the name for this is just the
            message.setElementQName((QName) resolvedRpcWrappedElementMap
                    .get(rpcOperationName));
            message.getAxisOperation().getAxisService().addMessageElementQNameToOperationMapping(
                    (QName) resolvedRpcWrappedElementMap.get(rpcOperationName),
                    message.getAxisOperation());
        } else {
            // now we are sure this is an document literal type element
            List bindingPartsList = getPartsListFromSoapBody(extensibilityElements);
            if (bindingPartsList == null) {
                // i.e user has not given any part list so we go to message and pick the firest part if
                // available
                if ((wsdl4jMessage.getParts() != null) && (wsdl4jMessage.getParts().size() > 0)) {
                    if (wsdl4jMessage.getParts().size() == 1) {
                        Part part = (Part) wsdl4jMessage.getParts().values().iterator().next();
                        QName elementName = part.getElementName();
                        if (elementName != null) {
                            message.setElementQName(elementName);
                            message.setMessagePartName(part.getName());
                            AxisOperation operation = message.getAxisOperation();
                            AxisService service = operation.getAxisService();
                            service.addMessageElementQNameToOperationMapping(elementName,
                                                                             operation);
                        } else {
                            throw new WSDLProcessingException(
                                    "No element type is defined for message " +
                                    wsdl4jMessage.getQName().getLocalPart());
                        }
                    } else {
                        // user has specified more than one parts with out specifing a part in
                        // soap body
                        throw new WSDLProcessingException("More than one part for message " +
                                                          wsdl4jMessage.getQName().getLocalPart());
                    }
                } else {
                    // this is allowed in the spec in this case element qname is null and nothing is send
                    // in the soap body
                    message.setElementQName(null);
                }
            } else {
                if (bindingPartsList.size() == 0) {
                    // we donot have to set the element qname
                    message.setElementQName(null);
                } else if (bindingPartsList.size() == 1) {
                    Part part = wsdl4jMessage.getPart((String) bindingPartsList.get(0));
                    if (part != null) {
                        QName elementName = part.getElementName();
                        if (elementName != null) {
                            message.setElementQName(elementName);
                            message.setMessagePartName(part.getName());
                            AxisOperation operation = message.getAxisOperation();
                            AxisService service = operation.getAxisService();
                            service.addMessageElementQNameToOperationMapping(elementName,
                                                                             operation);
                        } else {
                            throw new WSDLProcessingException(
                                    "No element type is defined for message" +
                                    wsdl4jMessage.getQName().getLocalPart());
                        }
                    } else {
                        throw new WSDLProcessingException("Missing part named "
                                                          + bindingPartsList.get(0) + " ");
                    }

                } else {
                    // i.e more than one part specified in this case we have
                    // to send an exception
                    throw new WSDLProcessingException(
                            "More than one element part is not allwed in document literal " +
                            " type binding operation " + wsdl4jOperation.getName());
                }
            }

        }

    }

    /**
     * Add the QName for the binding output
     */
    private void addQNameReference(AxisMessage faultMessage,
                                   Message wsdl4jMessage) throws AxisFault {

        // for a fault this is trivial - All faults are related directly to a
        // message by the name and are supposed to have a single part. So it is
        // a matter of copying the right QName from the message part

        // get the part
        Map parts = wsdl4jMessage.getParts();
        if (parts == null || parts.size() == 0) {
            String message = "There are no parts"
                             + " for fault message : "
                             + wsdl4jMessage.getQName();
            log.error(message);
            throw new WSDLProcessingException(message);
        }
        Part wsdl4jMessagePart = (Part) parts.values()
                .toArray()[0];
        if (wsdl4jMessagePart == null) {
            throw new WSDLProcessingException();
        }
        QName name = wsdl4jMessagePart.getElementName();
        if (name == null) {
            String message = "Part '"
                             + wsdl4jMessagePart.getName()
                             + "' of fault message '"
                             + wsdl4jMessage.getQName()
                             + "' must be defined with 'element=QName' and not 'type=QName'";
            log.error(message);
            throw new AxisFault(message);
        }

        faultMessage.setMessagePartName(wsdl4jMessagePart.getName());
        faultMessage.setElementQName(name);
    }

    /**
     * A util method that returns the SOAP style included in the binding
     * operation
     *
     * @param bindingOp
     */
    private String getSOAPStyle(BindingOperation bindingOp) {
        List extensibilityElements = bindingOp.getExtensibilityElements();
        for (int i = 0; i < extensibilityElements.size(); i++) {
            Object extElement = extensibilityElements.get(i);
            if (extElement instanceof SOAPOperation) {
                return ((SOAPOperation) extElement).getStyle();
            } else if (extElement instanceof SOAP12Operation) {
                return ((SOAP12Operation) extElement).getStyle();
            }

        }
        return null;
    }

    /**
     * Copy the component from the operation
     *
     * @param wsdl4jOperation
     * @param dif
     * @throws AxisFault
     */
    private AxisOperation populateOperations(Operation wsdl4jOperation,
                                             PortType wsdl4jPortType, Definition dif)
            throws AxisFault {
        QName opName = new QName(dif.getTargetNamespace(), wsdl4jOperation.getName());
        // Copy Name Attribute
        AxisOperation axisOperation = axisService.getOperation(opName);
        if (axisOperation == null) {
            String MEP = getMEP(wsdl4jOperation);
            axisOperation = AxisOperationFactory.getOperationDescription(MEP);
            axisOperation.setName(opName);

            // setting the PolicyInclude property of the AxisOperation
            PolicyInclude policyInclude = new PolicyInclude(axisOperation);
            axisOperation.setPolicyInclude(policyInclude);
        }

        copyExtensionAttributes(wsdl4jOperation.getExtensionAttributes(), 
                               axisOperation, PORT_TYPE_OPERATION);

        Input wsdl4jInputMessage = wsdl4jOperation.getInput();

        if (isServerSide) {
            if (null != wsdl4jInputMessage) {
                AxisMessage inMessage = axisOperation
                        .getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
                Message message = wsdl4jInputMessage.getMessage();
                if (null != message) {
                    inMessage.setName(message.getQName().getLocalPart());
                    copyExtensionAttributes(wsdl4jInputMessage.getExtensionAttributes(),
                                           inMessage, PORT_TYPE_OPERATION_INPUT);

                }
                // Check if the action is already set as we don't want to
                // override it
                // with the Default Action Pattern
                ArrayList inputActions = axisOperation.getWSAMappingList();
                String action = null;
                if (inputActions == null || inputActions.size() == 0) {
                    action = WSDL11ActionHelper
                            .getActionFromInputElement(dif, wsdl4jPortType,
                                                       wsdl4jOperation, wsdl4jInputMessage);
                }
                if (action != null) {
                    if (inputActions == null) {
                        inputActions = new ArrayList();
                        axisOperation.setWsamappingList(inputActions);
                    }
                    inputActions.add(action);
                    axisService.mapActionToOperation(action, axisOperation);
                }
            }
            // Create an output message and add
            Output wsdl4jOutputMessage = wsdl4jOperation.getOutput();
            if (null != wsdl4jOutputMessage) {
                AxisMessage outMessage = axisOperation
                        .getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
                Message message = wsdl4jOutputMessage.getMessage();
                if (null != message) {

                    outMessage.setName(message.getQName().getLocalPart());
                    copyExtensionAttributes(wsdl4jInputMessage.getExtensionAttributes(),
                                           outMessage, PORT_TYPE_OPERATION_OUTPUT);

                    // wsdl:portType -> wsdl:operation -> wsdl:output
                }
                // Check if the action is already set as we don't want to
                // override it
                // with the Default Action Pattern
                String action = axisOperation.getOutputAction();
                if (action == null) {
                    action = WSDL11ActionHelper.getActionFromOutputElement(dif,
                                                                           wsdl4jPortType,
                                                                           wsdl4jOperation,
                                                                           wsdl4jOutputMessage);
                }
                if (action != null) {
                    axisOperation.setOutputAction(action);
                }
            }
        } else {

            // for the client side we have to do something that is a bit
            // weird. The in message is actually taken from the output
            // and the output is taken from the in

            if (null != wsdl4jInputMessage) {
                AxisMessage inMessage = axisOperation
                        .getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
                Message message = wsdl4jInputMessage.getMessage();
                if (null != message) {

                    inMessage.setName(message.getQName().getLocalPart());
                    copyExtensionAttributes(wsdl4jInputMessage.getExtensionAttributes(),
                                           inMessage, PORT_TYPE_OPERATION_OUTPUT);

                }
                // Check if the action is already set as we don't want to
                // override it
                // with the Default Action Pattern
                String action = axisOperation.getOutputAction();
                if (action == null) {
                    action = WSDL11ActionHelper
                            .getActionFromInputElement(dif, wsdl4jPortType,
                                                       wsdl4jOperation, wsdl4jInputMessage);
                }
                if (action != null) {
                    axisOperation.setOutputAction(action);
                }
            }
            // Create an output message and add
            Output wsdl4jOutputMessage = wsdl4jOperation.getOutput();
            if (null != wsdl4jOutputMessage) {
                AxisMessage outMessage = axisOperation
                        .getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
                Message message = wsdl4jOutputMessage.getMessage();
                if (null != message) {

                    outMessage.setName(message.getQName().getLocalPart());
                    copyExtensionAttributes(wsdl4jInputMessage.getExtensionAttributes(),
                                           outMessage, PORT_TYPE_OPERATION_INPUT);

                    // wsdl:portType -> wsdl:operation -> wsdl:output
                }
                // Check if the action is already set as we don't want to
                // override it
                // with the Default Action Pattern
                ArrayList inputActions = axisOperation.getWSAMappingList();
                String action = null;
                if (inputActions == null || inputActions.size() == 0) {
                    action = WSDL11ActionHelper.getActionFromOutputElement(dif,
                                                                           wsdl4jPortType,
                                                                           wsdl4jOperation,
                                                                           wsdl4jOutputMessage);
                }
                if (action != null) {
                    if (inputActions == null) {
                        inputActions = new ArrayList();
                        axisOperation.setWsamappingList(inputActions);
                    }
                    inputActions.add(action);
                }
            }
        }

        Map faults = wsdl4jOperation.getFaults();
        Iterator faultKeyIterator = faults.keySet().iterator();

        while (faultKeyIterator.hasNext()) {
            Fault fault = (Fault) faults.get(faultKeyIterator.next());
            AxisMessage axisFaultMessage = new AxisMessage();
            addDocumentation(axisFaultMessage,fault.getDocumentationElement());
            Message faultMessage = fault.getMessage();
            if (null != faultMessage) {
                axisFaultMessage
                        .setName(faultMessage.getQName().getLocalPart());

                copyExtensibleElements(faultMessage.getExtensibilityElements(),
                                       dif, axisFaultMessage, PORT_TYPE_OPERATION_FAULT);

            }

            // Check if the action is already set as we don't want to override
            // it
            // with the Default Action Pattern
            String action = axisOperation.getFaultAction(fault.getName());
            if (action == null) {
                action = WSDL11ActionHelper.getActionFromFaultElement(dif,
                                                                      wsdl4jPortType,
                                                                      wsdl4jOperation, fault);
            }
            if (action != null) {
                axisOperation.addFaultAction(fault.getName(), action);
            }
            axisOperation.setFaultMessages(axisFaultMessage);
        }
        return axisOperation;
    }

    /**
     * Generates a list of wrapper schemas
     *
     * @param wsdl4jBinding
     */
    private Element[] generateWrapperSchema(Map schemaMap,
                                            Binding wsdl4jBinding,
                                            PortType portType) {

        List schemaElementList = new ArrayList();
        // target namespace for this should be the namespace URI for
        // the porttype
        String porttypeNamespaceURI = portType.getQName().getNamespaceURI();

        // //////////////////////////////////////////////////////////////////////
        // if there are any bindings present then we have to process them. we
        // have to generate a schema per wsdl4jBinding (that is the safest
        // option).
        // if not we just resolve to
        // the good old port type
        // list, in which case we'll generate a schema per porttype
        // //////////////////////////////////////////////////////////////////////

        // findwrappable operations return either the rpc soap operations or
        // Http binding operations

        List wrappableBOEList = findWrappableBindingOperations(wsdl4jBinding);

        // this method returns all the new schemas created when processing the rpc messages
        Map newSchemaMap = createSchemaForPorttype(porttypeNamespaceURI,
                                                   wrappableBOEList,
                                                   schemaMap);

        schemaElementList.addAll(newSchemaMap.values());
        return (Element[]) schemaElementList
                .toArray(new Element[schemaElementList.size()]);
    }

    /**
     * Create a schema by looking at the port type
     *
     * @param namespaceURI - namespace of the porttype uri.
     *  we use this only if a user has not specified a namespace in soap:body
     * @param boeListToProcess - List of BindingOperationEntry objects which require wrappering
     *                     
     * @return null if there is no element
     */
    private Map createSchemaForPorttype(String namespaceURI,
                                        List boeListToProcess,
                                        Map existingSchemaMap) {

        // this map is used to keep the newly added schemas
        Map newSchemaMap = new HashMap();
        // first of all look at the operations list
        // we can return immediately if we get the operations list
        // as empty
        if (boeListToProcess.isEmpty()) {
            return newSchemaMap;
        }

        // loop through the messages. We'll populate thins map with the relevant
        // messages
        // from the operations
        Map messageQnameToMessageMap = new HashMap();
        Map boeToInputMessageMap = new HashMap();
        Map boeToOutputMessageMap = new HashMap();

        // this contains the required namespace imports. the key in this
        // map would be the namaspace URI
        Map namespaceImportsMap = null;
        // list namespace prefix map. This map will include uri -> prefix
        Map namespacePrefixMap = null;

        // //////////////////////////////////////////////////////////////////////////////////////////////////
        // First thing is to populate the message map with the messages to
        // process.
        // //////////////////////////////////////////////////////////////////////////////////////////////////

        // we really need to do this for a single porttype!
        BindingOperationEntry boe;
        for (int k = 0; k < boeListToProcess.size(); k++) {
            boe = (BindingOperationEntry) boeListToProcess.get(k);
            Input input = boe.getBindingOperation().getOperation().getInput();
            Message message;
            if (input != null) {
                message = input.getMessage();
                messageQnameToMessageMap.put(message.getQName(), message);
                boeToInputMessageMap.put(boe, message);
            }

            Output output = boe.getBindingOperation().getOperation().getOutput();
            if (output != null) {
                message = output.getMessage();
                messageQnameToMessageMap.put(message.getQName(), message);
                boeToOutputMessageMap.put(boe, message);
            }

            // we do not want to process fault messages since they can only be used as document type
            // see basic profile 4.4.2
        }

        // find the xsd prefix
        String xsdPrefix = findSchemaPrefix();
        // DOM document that will be the ultimate creator
        Document document = getDOMDocumentBuilder().newDocument();

        Element elementDeclaration;

        //loop through the input op map and generate the elements
        BindingOperationEntry boEntry;
        for (Iterator boeIter = boeToInputMessageMap.keySet().iterator();
             boeIter.hasNext();) {

            boEntry = (BindingOperationEntry) boeIter.next();
            elementDeclaration = document.createElementNS(
                    XMLSCHEMA_NAMESPACE_URI, xsdPrefix + ":"
                                             + XML_SCHEMA_ELEMENT_LOCAL_NAME);
            elementDeclaration.setAttribute(XSD_NAME, boEntry.getBindingOperation().getName());

            //when creating the inner complex type we have to find the parts list from the binding input
            BindingInput bindingInput = boEntry.getBindingOperation().getBindingInput();
            Message message = (Message) boeToInputMessageMap.get(boEntry);

            if (bindingInput != null) {

                Collection partsCollection = null;
                if (BINDING_TYPE_SOAP.equals(this.bindingType)) {
                    // first see the body parts list
                    List bodyPartsList =
                        getPartsListFromSoapBody(bindingInput.getExtensibilityElements());
                    partsCollection = message.getOrderedParts(bodyPartsList);
                } else {
                    // i.e http binding
                    partsCollection = message.getParts().values();
                }

                List parameterOrder = 
                   boEntry.getBindingOperation().getOperation().getParameterOrdering();
                namespaceImportsMap = new HashMap();
                namespacePrefixMap = new HashMap();

                Node newComplexType = getNewComplextType(document,
                                                         xsdPrefix,
                                                         partsCollection,
                                                         parameterOrder,
                                                         false,
                                                         namespaceImportsMap,
                                                         namespacePrefixMap, 
                                                         boEntry);

                elementDeclaration.appendChild(newComplexType);
                String namespaceToUse = namespaceURI;

                if (BINDING_TYPE_SOAP.equals(this.bindingType)) {
                    String bodyNamespace =
                            getNamespaceFromSoapBody(bindingInput.getExtensibilityElements());
                    namespaceToUse = bodyNamespace != null ? bodyNamespace : namespaceURI;
                }

                if (existingSchemaMap.containsKey(namespaceToUse)) {
                    // i.e this namespace is already exists with the original wsdl schemas
                    addElementToAnExistingSchema((Element) existingSchemaMap.get(namespaceToUse),
                                                 elementDeclaration,
                                                 namespacePrefixMap,
                                                 namespaceImportsMap,
                                                 namespaceToUse);
                } else if (newSchemaMap.containsKey(namespaceToUse)) {
                    // i.e this namespace is with a newly created schema
                    addElementToAnExistingSchema((Element) newSchemaMap.get(namespaceToUse),
                                                 elementDeclaration,
                                                 namespacePrefixMap,
                                                 namespaceImportsMap,
                                                 namespaceToUse);
                } else {
                    // i.e this element namespace has not found yet so
                    // we have to create new schema for it
                    Element newSchema = createNewSchemaWithElement(elementDeclaration,
                                                                   namespacePrefixMap,
                                                                   namespaceImportsMap,
                                                                   namespaceToUse,
                                                                   document,
                                                                   xsdPrefix);
                    newSchemaMap.put(namespaceToUse, newSchema);
                }
                resolvedRpcWrappedElementMap.put(boEntry.getBindingOperation().getName(), new QName(
                        namespaceToUse, boEntry.getBindingOperation().getName(), AXIS2WRAPPED));

            } else {
                throw new WSDLProcessingException(
                        "No binding input is defiend for binding operation ==> "
                        + boEntry.getBindingOperation().getName());
            }

        }

        // loop through the output to map and generate the elements
        for (Iterator boeIterator = boeToOutputMessageMap.keySet().iterator();
             boeIterator.hasNext();) {
            boEntry = (BindingOperationEntry) boeIterator.next();
            String baseoutputOpName = boEntry.getBindingOperation().getName();
            // see basic profile 4.7.19
            String outputOpName = baseoutputOpName + WRAPPED_OUTPUTNAME_SUFFIX;
            elementDeclaration = document.createElementNS(
                    XMLSCHEMA_NAMESPACE_URI, xsdPrefix + ":"
                                             + XML_SCHEMA_ELEMENT_LOCAL_NAME);
            elementDeclaration.setAttribute(XSD_NAME, outputOpName);

            BindingOutput bindingOutput = boEntry.getBindingOperation().getBindingOutput();
            Message message = (Message) boeToOutputMessageMap.get(boEntry);

            if (bindingOutput != null) {
                Collection partsCollection = null;
                if (BINDING_TYPE_SOAP.equals(this.bindingType)) {
                    // first see the body parts list
                    List bodyPartsList =
                        getPartsListFromSoapBody(bindingOutput.getExtensibilityElements());
                    partsCollection = message.getOrderedParts(bodyPartsList);

                } else {
                    // i.e if http binding
                    partsCollection = message.getParts().values();
                }

                List parameterOrder = 
                    boEntry.getBindingOperation().getOperation().getParameterOrdering();

                // we have to initialize the hash maps always since we add the elements onece we
                // generate it
                namespacePrefixMap = new HashMap();
                namespaceImportsMap = new HashMap();

                Node newComplexType = getNewComplextType(document,
                                                         xsdPrefix,
                                                         partsCollection,
                                                         parameterOrder,
                                                         true,
                                                         namespaceImportsMap,
                                                         namespacePrefixMap,
                                                         boEntry);
                elementDeclaration.appendChild(newComplexType);

                String namespaceToUse = namespaceURI;

                if (BINDING_TYPE_SOAP.equals(this.bindingType)) {
                    String bodyNamespace =
                            getNamespaceFromSoapBody(bindingOutput.getExtensibilityElements());
                    namespaceToUse = bodyNamespace != null ? bodyNamespace : namespaceURI;
                }

                if (existingSchemaMap.containsKey(namespaceToUse)) {
                    // i.e this namespace is already exists with the original wsdl schemas
                    addElementToAnExistingSchema((Element) existingSchemaMap.get(namespaceToUse),
                                                 elementDeclaration,
                                                 namespacePrefixMap,
                                                 namespaceImportsMap,
                                                 namespaceToUse);
                } else if (newSchemaMap.containsKey(namespaceToUse)) {
                    // i.e this namespace is with a newly created schema
                    addElementToAnExistingSchema((Element) newSchemaMap.get(namespaceToUse),
                                                 elementDeclaration,
                                                 namespacePrefixMap,
                                                 namespaceImportsMap,
                                                 namespaceToUse);
                } else {
                    // i.e this element namespace has not found yet so
                    // we have to create new schema for it
                    Element newSchema = createNewSchemaWithElement(elementDeclaration,
                                                                   namespacePrefixMap,
                                                                   namespaceImportsMap,
                                                                   namespaceToUse,
                                                                   document,
                                                                   xsdPrefix);
                    newSchemaMap.put(namespaceToUse, newSchema);
                }
                resolvedRpcWrappedElementMap.put(outputOpName, new QName(
                        namespaceToUse, outputOpName, AXIS2WRAPPED));

            } else {
                throw new WSDLProcessingException(
                        "No binding out put is defined for binding operation ==>" +
                        boEntry.getBindingOperation().getName());
            }
        }

        return newSchemaMap;
    }

    private void addElementToAnExistingSchema(Element schemaElement,
                                              Element newElement,
                                              Map namespacePrefixMap,
                                              Map namespaceImportsMap,
                                              String targetNamespace) {

        Document ownerDocument = schemaElement.getOwnerDocument();

        // loop through the namespace declarations first and add them
        String[] nameSpaceDeclarationArray = (String[]) namespacePrefixMap
                .keySet().toArray(new String[namespacePrefixMap.size()]);
        for (int i = 0; i < nameSpaceDeclarationArray.length; i++) {
            String s = nameSpaceDeclarationArray[i];
            checkAndAddNamespaceDeclarations(s, namespacePrefixMap,
                                             schemaElement);
        }

        // add imports - check whether it is the targetnamespace before
        // adding
        Element[] namespaceImports = (Element[]) namespaceImportsMap
                .values().toArray(new Element[namespaceImportsMap.size()]);
        for (int i = 0; i < namespaceImports.length; i++) {
            if (!targetNamespace.equals(namespaceImports[i]
                    .getAttribute(NAMESPACE_URI))) {
                schemaElement.appendChild(ownerDocument.importNode(
                        namespaceImports[i], true));
            }
        }

        schemaElement.appendChild(ownerDocument.importNode(newElement, true));

    }

    private Element createNewSchemaWithElement(Element newElement,
                                               Map namespacePrefixMap,
                                               Map namespaceImportsMap,
                                               String targetNamespace,
                                               Document document,
                                               String xsdPrefix) {

        Element schemaElement = document.createElementNS(
                XMLSCHEMA_NAMESPACE_URI, xsdPrefix + ":"
                                         + XML_SCHEMA_LOCAL_NAME);

        // loop through the namespace declarations first
        String[] nameSpaceDeclarationArray = (String[]) namespacePrefixMap
                .keySet().toArray(new String[namespacePrefixMap.size()]);
        for (int i = 0; i < nameSpaceDeclarationArray.length; i++) {
            String s = nameSpaceDeclarationArray[i];
            schemaElement.setAttributeNS(XML_NAMESPACE_URI,
                                         NAMESPACE_DECLARATION_PREFIX
                                         + namespacePrefixMap.get(s).toString(), s);
        }

        if (schemaElement.getAttributeNS(XML_NAMESPACE_URI, xsdPrefix).length() == 0) {
            schemaElement.setAttributeNS(XML_NAMESPACE_URI,
                                         NAMESPACE_DECLARATION_PREFIX + xsdPrefix,
                                         XMLSCHEMA_NAMESPACE_URI);
        }

        // add the targetNamespace
        schemaElement.setAttributeNS(XML_NAMESPACE_URI, XMLNS_AXIS2WRAPPED, targetNamespace);
        schemaElement.setAttribute(XSD_TARGETNAMESPACE, targetNamespace);
        schemaElement.setAttribute(XSD_ELEMENT_FORM_DEFAULT, XSD_UNQUALIFIED);

        // add imports
        Element[] namespaceImports = (Element[]) namespaceImportsMap
                .values().toArray(new Element[namespaceImportsMap.size()]);
        for (int i = 0; i < namespaceImports.length; i++) {
            schemaElement.appendChild(namespaceImports[i]);

        }

        schemaElement.appendChild(newElement);
        return schemaElement;
    }

    private List getPartsListFromSoapBody(List extensibilityElements) {
        List partsList = null;
        ExtensibilityElement extElement;
        for (Iterator iter = extensibilityElements.iterator(); iter.hasNext();) {
            
            
            extElement = (ExtensibilityElement) iter.next();
            
            if (log.isDebugEnabled()) {
                log.debug("Extensibility Element type is:" + extElement.getElementType());
                log.debug("Extensibility Element class is:" + extElement.getClass().getName());
            }
            // SOAP 1.1 body element found!
            if (extElement instanceof SOAPBody) {
                SOAPBody soapBody = (SOAPBody) extElement;
                partsList = soapBody.getParts();
            } else if (extElement instanceof SOAP12Body) {
                SOAP12Body soapBody = (SOAP12Body) extElement;
                partsList = soapBody.getParts();
            } else if (extElement instanceof MIMEMultipartRelated) {
                MIMEMultipartRelated minMimeMultipartRelated = (MIMEMultipartRelated) extElement;
                List mimePartsList = minMimeMultipartRelated.getMIMEParts();
                MIMEPart mimePart = null;
                Object object;
                List mimePartElements;
                ExtensibilityElement mimePartExtensibilityElement;
                for (Iterator mimePartsIter = mimePartsList.iterator(); mimePartsIter.hasNext();) {
                    object = mimePartsIter.next();
                    if (object instanceof MIMEPart) {
                        mimePart = (MIMEPart) object;
                        mimePartElements = mimePart.getExtensibilityElements();
                        for (Iterator mimePartElementsIter = mimePartElements.iterator(); mimePartElementsIter.hasNext();)
                        {
                            mimePartExtensibilityElement = (ExtensibilityElement) mimePartElementsIter.next();
                            if (mimePartExtensibilityElement instanceof SOAPBody) {
                                SOAPBody soapBody = (SOAPBody) mimePartExtensibilityElement;
                                partsList = soapBody.getParts();
                            } else if (mimePartExtensibilityElement instanceof SOAP12Body) {
                                SOAP12Body soapBody = (SOAP12Body) mimePartExtensibilityElement;
                                partsList = soapBody.getParts();
                            }
                        }
                    }
                }
            } 
        }
        if (partsList == null) {
            log.debug("SOAP body parts have not been set. All the parts in the message were added to the message.");
        }
        return partsList;
    }

    private String getNamespaceFromSoapBody(List extensibilityElements) {

        ExtensibilityElement extElement;
        String namespace = null;
        for (Iterator iter = extensibilityElements.iterator(); iter.hasNext();) {
            extElement = (ExtensibilityElement) iter.next();
            // SOAP 1.1 body element found!
            if (extElement instanceof SOAPBody) {
                SOAPBody soapBody = (SOAPBody) extElement;
                namespace = soapBody.getNamespaceURI();
            } else if (extElement instanceof SOAP12Body) {
                SOAP12Body soapBody = (SOAP12Body) extElement;
                namespace = soapBody.getNamespaceURI();
            }
        }
        return namespace;
    }

    /**
     * creates a new shema complex element according to the elements sequence difined
     * this parts list is always for a message refering from the
     * soap rpc type operation
     *
     * @param document
     * @param xsdPrefix
     * @param partsCollection     - parts to be added
     * @param parameterOrder      - param Order list if it is given
     * @param isOutMessage
     * @param namespaceImportsMap
     * @param namespacePrefixMap
     * @param boe BindingOperationEntry for this partCollection
     * @return new element
     */
    private Element getNewComplextType(Document document,
                                       String xsdPrefix,
                                       Collection partsCollection,
                                       List parameterOrder,
                                       boolean isOutMessage,
                                       Map namespaceImportsMap,
                                       Map namespacePrefixMap,
                                       BindingOperationEntry boe) {
        // add the complex type
        Element newComplexType = document.createElementNS(
                XMLSCHEMA_NAMESPACE_URI, xsdPrefix + ":"
                                         + XML_SCHEMA_COMPLEX_TYPE_LOCAL_NAME);

        Element cmplxTypeSequence = document.createElementNS(
                XMLSCHEMA_NAMESPACE_URI, xsdPrefix + ":"
                                         + XML_SCHEMA_SEQUENCE_LOCAL_NAME);

        Part part;
        if ((parameterOrder == null) || (parameterOrder.size() == 0)) {
            // no parameter order then just add the elements in the parts collection
            for (Iterator partsIter = partsCollection.iterator(); partsIter.hasNext();) {
                part = (Part) partsIter.next();
                // the part name
                addPartToElement(part,
                                 document,
                                 xsdPrefix,
                                 namespaceImportsMap,
                                 namespacePrefixMap,
                                 cmplxTypeSequence,
                                 isOutMessage,
                                 boe);

            }
        } else {
            // i.e an parts order is given
            // first populate all the parts to a map
            Map partsMap = new HashMap();
            for (Iterator partsIter = partsCollection.iterator(); partsIter.hasNext();) {
                part = (Part) partsIter.next();
                partsMap.put(part.getName(), part);
            }

            String partName;
            for (Iterator paramOrderIter = parameterOrder.iterator(); paramOrderIter.hasNext();) {
                partName = (String) paramOrderIter.next();
                part = (Part) partsMap.get(partName);
                if (part != null) {
                    addPartToElement(part,
                                     document,
                                     xsdPrefix,
                                     namespaceImportsMap,
                                     namespacePrefixMap,
                                     cmplxTypeSequence, 
                                     isOutMessage,
                                     boe);
                    partsMap.remove(partName);
                }
            }
            // if this is an output message then we have to set the
            // return type if exists
            if (isOutMessage) {
                if (partsMap.size() > 0) {
                    if (partsMap.size() == 1) {
                        part = (Part) partsMap.values().iterator().next();
                        // change the name of this part
                        // this is the return type and its name should be result
                        // part.setName("result");
                        addPartToElement(part,
                                         document,
                                         xsdPrefix,
                                         namespaceImportsMap,
                                         namespacePrefixMap,
                                         cmplxTypeSequence,
                                         isOutMessage,
                                         boe);
                    } else {
                        throw new WSDLProcessingException("the parameter order can left atmost" +
                                                          " one part");
                    }
                }
            }
        }

        newComplexType.appendChild(cmplxTypeSequence);
        return newComplexType;
    }

    /**
     * @param part
     * @param document
     * @param xsdPrefix
     * @param namespaceImportsMap
     * @param namespacePrefixMap
     * @param cmplxTypeSequence
     * @param isOutMessage (true is part is referenced by the output clause)
     * @param boe BindingOperationEntry that caused the creation of this part.
     */
    private void addPartToElement(Part part,
                                  Document document,
                                  String xsdPrefix,
                                  Map namespaceImportsMap,
                                  Map namespacePrefixMap,
                                  Element cmplxTypeSequence,
                                  boolean isOutMessage,
                                  BindingOperationEntry boe) {
        Element child;
        String elementName = part.getName();

        // the type name
        QName schemaTypeName = part.getTypeName();

        if (schemaTypeName != null) {

            child = document.createElementNS(XMLSCHEMA_NAMESPACE_URI,
                                             xsdPrefix + ":" + XML_SCHEMA_ELEMENT_LOCAL_NAME);
            // always child attribute should be in no namespace
            child.setAttribute("form", "unqualified");

            String prefix;
            if (XMLSCHEMA_NAMESPACE_URI.equals(schemaTypeName.getNamespaceURI())) {
                prefix = xsdPrefix;
            } else {
                // this schema is a third party one. So we need to have
                // an import statement in our generated schema
                String uri = schemaTypeName.getNamespaceURI();
                if (!namespaceImportsMap.containsKey(uri)) {
                    // create Element for namespace import
                    Element namespaceImport = document.createElementNS(
                            XMLSCHEMA_NAMESPACE_URI, xsdPrefix + ":"
                                                     + XML_SCHEMA_IMPORT_LOCAL_NAME);
                    namespaceImport.setAttribute(NAMESPACE_URI, uri);
                    // add this to the map
                    namespaceImportsMap.put(uri, namespaceImport);
                    // we also need to associate this uri with a prefix
                    // and include that prefix
                    // in the schema's namspace declarations. So add
                    // theis particular namespace to the
                    // prefix map as well
                    prefix = getTemporaryNamespacePrefix();
                    namespacePrefixMap.put(uri, prefix);
                } else {
                    // this URI should be already in the namspace prefix
                    // map
                    prefix = (String) namespacePrefixMap.get(uri);
                }

            }

            child.setAttribute(XSD_NAME, elementName);
            child.setAttribute(XSD_TYPE, prefix + ":" + schemaTypeName.getLocalPart());
            cmplxTypeSequence.appendChild(child);

        } else {
            String bindingOperationName = boe.getBindingOperation().getName();
            String partName = part.getName();
            if (boe.isRPC()) {
                // see the basic profile 4.4.1 for rpc-literal.
                // messages parts can have only types
                throw new WSDLProcessingException(
                   "The binding operation " + bindingOperationName + " is RPC/literal. " +
                   "The message parts for this operation must use the type " +
                   "attribute as specificed by " +
                   "WS-I Basic Profile specification (4.4.1).  Message part, " + 
                   partName + ", violates" +
                   "this rule.  Please remove the element attribute " +
                   "and use the type attribute.");
            } else {
                // The presense of an element means that a wrapper xsd element is not needed.
                boe.setWrappedOutput(false);
                if (log.isDebugEnabled()) {
                    log.debug("The binding operation " + bindingOperationName + 
                              " references message part " +
                              partName + ".  This part does not use the " +
                              "type attribute, so a wrappering element is not added.");
                }
            }
            
        }
    }

    /**
     * @param prefixMap
     */
    private void checkAndAddNamespaceDeclarations(String namespace,
                                                  Map prefixMap, Element schemaElement) {
        // get the attribute for the current namespace
        String prefix = (String) prefixMap.get(namespace);
        // A prefix must be found at this point!
        String existingURL = schemaElement.getAttributeNS(XML_NAMESPACE_URI,
                                                          NAMESPACE_DECLARATION_PREFIX + prefix);
        if (existingURL == null || existingURL.length() == 0) {
            // there is no existing URL by that prefix - declare a new namespace
            schemaElement.setAttributeNS(XML_NAMESPACE_URI,
                                         NAMESPACE_DECLARATION_PREFIX + prefix, namespace);
        } else if (existingURL.equals(namespace)) {
            // this namespace declaration is already there with the same prefix
            // ignore it
        } else {
            // there is a different namespace declared in the given prefix
            // change the prefix in the prefix map to a new one and declare it

            // create a prefix
            String generatedPrefix = "ns" + prefixCounter++;
            while (prefixMap.containsKey(generatedPrefix)) {
                generatedPrefix = "ns" + prefixCounter++;
            }
            schemaElement.setAttributeNS(XML_NAMESPACE_URI,
                                         NAMESPACE_DECLARATION_PREFIX + generatedPrefix, namespace);
            // add to the map
            prefixMap.put(namespace, generatedPrefix);
        }

    }

    /**
     * Read the WSDL file given the inputstream for the WSDL source
     *
     * @param in
     * @throws WSDLException
     */
    private Definition readInTheWSDLFile(InputStream in) throws WSDLException {

        WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();

        // switch off the verbose mode for all usecases
        reader.setFeature(JAVAX_WSDL_VERBOSE_MODE_KEY, false);
        reader.setFeature("javax.wsdl.importDocuments", true);

        Definition def;
        // if the custem resolver is present then use it
        if (customWSDLResolver != null) {
            // make sure the wsdl definition has the URI for the base document set
            def = reader.readWSDL(customWSDLResolver);
            def.setDocumentBaseURI(customWSDLResolver.getBaseURI());
            return def;
        } else {
            Document doc;
            try {
                doc = XMLUtils.newDocument(in);
            } catch (ParserConfigurationException e) {
                throw new WSDLException(WSDLException.PARSER_ERROR,
                                        "Parser Configuration Error", e);
            } catch (SAXException e) {
                throw new WSDLException(WSDLException.PARSER_ERROR,
                                        "Parser SAX Error", e);

            } catch (IOException e) {
                throw new WSDLException(WSDLException.INVALID_WSDL, "IO Error",
                                        e);
            }

            // Log when and from where the WSDL is loaded.
            if (log.isDebugEnabled()) {
                log.debug("Reading 1.1 WSDL with base uri = " + getBaseUri());
                log.debug("  the document base uri = " + getDocumentBaseUri());
                log.trace("  the stack at this point is: " + stackToString());
            }
            def = reader.readWSDL(getBaseUri(), doc);
            def.setDocumentBaseURI(getDocumentBaseUri());
            return def;
        }
    }

    /**
     * Get the Extensible elements form wsdl4jExtensibleElements
     * <code>Vector</code> if any and copy them to <code>Component</code>
     * <p/> Note - SOAP body extensible element will be processed differently
     *
     * @param wsdl4jExtensibleElements
     * @param description                   where is the ext element (port , portype , biding)
     * @param wsdl4jDefinition
     * @param originOfExtensibilityElements -
     *                                      this will indicate the place this extensibility element came
     *                                      from.
     */
    private void copyExtensibleElements(List wsdl4jExtensibleElements,
                                        Definition wsdl4jDefinition, AxisDescription description,
                                        String originOfExtensibilityElements) throws AxisFault {

        ExtensibilityElement wsdl4jExtensibilityElement;

        for (Iterator iterator = wsdl4jExtensibleElements.iterator(); iterator.hasNext();) {

            wsdl4jExtensibilityElement = (ExtensibilityElement) iterator.next();

            if (wsdl4jExtensibilityElement instanceof UnknownExtensibilityElement) {

                UnknownExtensibilityElement unknown =
                        (UnknownExtensibilityElement) (wsdl4jExtensibilityElement);
                QName type = unknown.getElementType();
                
                // <wsp:Policy>
                if (WSDLConstants.WSDL11Constants.POLICY.equals(type)) {
                    if (isTraceEnabled) {
                        log.trace("copyExtensibleElements:: PolicyElement found " + unknown);
                    }
                    Policy policy = (Policy) PolicyUtil.getPolicyComponent(unknown.getElement());
                    description.getPolicySubject().attachPolicy(policy);
                    
//                    int attachmentScope =
//                            getPolicyAttachmentPoint(description, originOfExtensibilityElements);
//                    if (attachmentScope > -1) {
//                        description.getPolicyInclude().addPolicyElement(
//                                attachmentScope, policy);
//                    }
                    // <wsp:PolicyReference>
                } else if (WSDLConstants.WSDL11Constants.POLICY_REFERENCE
                        .equals(type)) {
                    if (isTraceEnabled) {
                        log.trace("copyExtensibleElements:: PolicyReference found " + unknown);
                    }
                    PolicyReference policyReference = (PolicyReference) PolicyUtil
                            .getPolicyComponent(unknown.getElement());
                    description.getPolicySubject().attachPolicyReference(policyReference);
                    
//                    int attachmentScope =
//                            getPolicyAttachmentPoint(description, originOfExtensibilityElements);
//                    if (attachmentScope > -1) {
//                        description.getPolicyInclude().addPolicyRefElement(
//                                attachmentScope, policyReference);
//                    }
                } else if (AddressingConstants.Final.WSAW_USING_ADDRESSING
                        .equals(type)
                           || AddressingConstants.Submission.WSAW_USING_ADDRESSING
                        .equals(unknown.getElementType())) {
                    if (isTraceEnabled) {
                        log.trace("copyExtensibleElements:: wsaw:UsingAddressing found " + unknown);
                    }
                    // FIXME We need to set this the appropriate Axis Description AxisEndpoint or
                    // AxisBinding .
                    if (originOfExtensibilityElements.equals(PORT)
                        || originOfExtensibilityElements.equals(BINDING)) {
                        if (Boolean.TRUE.equals(unknown.getRequired())) {
                        	AddressingHelper.setAddressingRequirementParemeterValue(axisService, AddressingConstants.ADDRESSING_REQUIRED);
                        } else {
                        	AddressingHelper.setAddressingRequirementParemeterValue(axisService, AddressingConstants.ADDRESSING_OPTIONAL);
                        }
                    }

                }    else if (wsdl4jExtensibilityElement.getElementType() != null &&
                        wsdl4jExtensibilityElement.getElementType().getNamespaceURI().equals(
                                org.apache.axis2.namespace.Constants.FORMAT_BINDING)) {
                    Element typeMapping = unknown.getElement();
                    NodeList typeMaps = typeMapping.getElementsByTagNameNS(
                            org.apache.axis2.namespace.Constants.FORMAT_BINDING,
                            "typeMap");
                    int count = typeMaps.getLength();
                    HashMap typeMapper = new HashMap();
                    for (int index = 0; index < count; index++) {
                        Node node = typeMaps.item(index);
                        NamedNodeMap attributes = node.getAttributes();
                        Node typeName = attributes.getNamedItem("typeName");

                        if (typeName != null) {
                            String prefix = getPrefix(typeName.getNodeValue());

                            if (prefix != null) {
                                String ns = (String) wsdl4jDefinition.getNamespaces().get(prefix);
                                if (ns != null) {
                                    Node formatType = attributes.getNamedItem("formatType");
                                    typeMapper.put(new QName(ns, getTypeName(
                                            typeName.getNodeValue())), formatType.getNodeValue());
                                }

                            }
                        }
                    }
                } else if (wsdl4jExtensibilityElement.getElementType() != null &&
                        wsdl4jExtensibilityElement.getElementType().getNamespaceURI().equals(
                                org.apache.axis2.namespace.Constants.JAVA_NS)) {
                    Element unknowJavaElement = unknown.getElement();
                    if (unknowJavaElement.getLocalName().equals("address") ) {
                        NamedNodeMap nameAttributes = unknowJavaElement.getAttributes();
                        Node node = nameAttributes.getNamedItem("className");
                        Parameter serviceClass = new Parameter();
                        serviceClass.setName("className");
                        serviceClass.setValue(node.getNodeValue());
                        axisService.addParameter(serviceClass);
                        Parameter transportName = new Parameter();
                        transportName.setName("TRANSPORT_NAME");
                        transportName.setValue("java");
                        axisService.addParameter(transportName);
                    }
                }  else {
                    // Ignore this element - it is a totally unknown element
                    if (isTraceEnabled) {
                        log.trace("copyExtensibleElements:: Unknown Extensibility Element found " +
                                  unknown);
                    }
                }

            } else if (wsdl4jExtensibilityElement instanceof SOAP12Address) {
                SOAP12Address soapAddress = (SOAP12Address) wsdl4jExtensibilityElement;
                if (description instanceof AxisEndpoint) {
                	setEndpointURL((AxisEndpoint) description, soapAddress.getLocationURI());
                }

            } else if (wsdl4jExtensibilityElement instanceof SOAPAddress) {
                SOAPAddress soapAddress = (SOAPAddress) wsdl4jExtensibilityElement;
                if (description instanceof AxisEndpoint) {
                	setEndpointURL((AxisEndpoint) description, soapAddress.getLocationURI());
                }
            } else if (wsdl4jExtensibilityElement instanceof HTTPAddress) {
                HTTPAddress httpAddress = (HTTPAddress) wsdl4jExtensibilityElement;
                if (description instanceof AxisEndpoint) {
                	setEndpointURL((AxisEndpoint) description, httpAddress.getLocationURI());
                }

            } else if (wsdl4jExtensibilityElement instanceof Schema) {
                Schema schema = (Schema) wsdl4jExtensibilityElement;
                // just add this schema - no need to worry about the imported
                // ones
                axisService.addSchema(getXMLSchema(schema.getElement(), schema
                        .getDocumentBaseURI()));

            } else if (wsdl4jExtensibilityElement instanceof SOAP12Operation) {
                SOAP12Operation soapOperation = (SOAP12Operation) wsdl4jExtensibilityElement;
                AxisBindingOperation axisBindingOperation = (AxisBindingOperation) description;

                String style = soapOperation.getStyle();
                if (style != null) {
                    axisBindingOperation.setProperty(WSDLConstants.WSDL_1_1_STYLE, style);
                }

                String soapActionURI = soapOperation.getSoapActionURI();
                
                if (this.isCodegen && ((soapActionURI == null) || (soapActionURI.equals("")))) {
                    soapActionURI = axisBindingOperation.getAxisOperation().getInputAction();
                }
                
                if (LoggingControl.debugLoggingAllowed && log.isDebugEnabled())
                    log.debug("WSDL Binding Operation: " + axisBindingOperation.getName() +
                            ", SOAPAction: " + soapActionURI);
                
                if (soapActionURI != null && !soapActionURI.equals("")) {
                    axisBindingOperation
                            .setProperty(WSDL2Constants.ATTR_WSOAP_ACTION, soapActionURI);
                    axisBindingOperation.getAxisOperation().setSoapAction(soapActionURI);
                    if (!isServerSide) {
                        axisBindingOperation.getAxisOperation().setOutputAction(soapActionURI);
                    }

                    axisService.mapActionToOperation(soapActionURI,
                                                     axisBindingOperation.getAxisOperation());
                }

            } else if (wsdl4jExtensibilityElement instanceof SOAPOperation) {
                SOAPOperation soapOperation = (SOAPOperation) wsdl4jExtensibilityElement;
                AxisBindingOperation axisBindingOperation = (AxisBindingOperation) description;

                String style = soapOperation.getStyle();
                if (style != null) {
                    axisBindingOperation.setProperty(WSDLConstants.WSDL_1_1_STYLE, style);
                }

                String soapAction = soapOperation.getSoapActionURI();
                if (this.isCodegen && ((soapAction == null) || (soapAction.equals("")))) {
                    soapAction = axisBindingOperation.getAxisOperation().getInputAction();
                }
                
                if (LoggingControl.debugLoggingAllowed && log.isDebugEnabled())
                    log.debug("WSDL Binding Operation: " + axisBindingOperation.getName() +
                            ", SOAPAction: " + soapAction);
                
                if (soapAction != null && !soapAction.equals("")) {
                    axisBindingOperation.setProperty(WSDL2Constants.ATTR_WSOAP_ACTION, soapAction);
                    axisBindingOperation.getAxisOperation().setSoapAction(soapAction);
                    if (!isServerSide) {
                        axisBindingOperation.getAxisOperation().setOutputAction(soapAction);
                    }

                    axisService.mapActionToOperation(soapAction,
                                                     axisBindingOperation.getAxisOperation());
                }
            } else if (wsdl4jExtensibilityElement instanceof HTTPOperation) {
                HTTPOperation httpOperation = (HTTPOperation) wsdl4jExtensibilityElement;
                AxisBindingOperation axisBindingOperation = (AxisBindingOperation) description;

                String httpLocation = httpOperation.getLocationURI();
                if (httpLocation != null) {
                    // change the template to make it same as WSDL 2 template
                    httpLocation = httpLocation.replaceAll("\\(", "{");
                    httpLocation = httpLocation.replaceAll("\\)", "}");
                    axisBindingOperation
                            .setProperty(WSDL2Constants.ATTR_WHTTP_LOCATION, httpLocation);

                }
                axisBindingOperation.setProperty(WSDL2Constants.ATTR_WHTTP_INPUT_SERIALIZATION,
                                                 HTTPConstants.MEDIA_TYPE_X_WWW_FORM);


            } else if (wsdl4jExtensibilityElement instanceof SOAP12Header) {

                SOAP12Header soapHeader = (SOAP12Header) wsdl4jExtensibilityElement;
                SOAPHeaderMessage headerMessage = new SOAPHeaderMessage();

                headerMessage.setNamespaceURI(soapHeader.getNamespaceURI());
                headerMessage.setUse(soapHeader.getUse());

                Boolean required = soapHeader.getRequired();

                if (required != null) {
                    headerMessage.setRequired(required.booleanValue());
                }

                if (wsdl4jDefinition != null) {
                    // find the relevant schema part from the messages
                    Message msg = wsdl4jDefinition.getMessage(soapHeader
                            .getMessage());

                    if (msg == null) {
                        // TODO i18n this
                        throw new AxisFault("message "
                                            + soapHeader.getMessage()
                                            + " not found in the WSDL ");
                    }
                    Part msgPart = msg.getPart(soapHeader.getPart());

                    if (msgPart == null) {
                        // TODO i18n this
                        throw new AxisFault("message part "
                                            + soapHeader.getPart()
                                            + " not found in the WSDL ");
                    }
                    // see basic profile 4.4.2 Bindings and Faults header, fault and headerfaults
                    // can only have elements
                    headerMessage.setElement(msgPart.getElementName());
                }

                headerMessage.setMessage(soapHeader.getMessage());
                headerMessage.setPart(soapHeader.getPart());

                if (description instanceof AxisBindingMessage) {
                    AxisBindingMessage bindingMessage = (AxisBindingMessage) description;
                    List soapHeaders =
                            (List) bindingMessage.getProperty(WSDL2Constants.ATTR_WSOAP_HEADER);
                    if (soapHeaders == null) {
                        soapHeaders = new ArrayList();
                        bindingMessage.setProperty(WSDL2Constants.ATTR_WSOAP_HEADER, soapHeaders);
                    }
                    soapHeaders.add(headerMessage);
                }

            } else if (wsdl4jExtensibilityElement instanceof SOAPHeader) {

                SOAPHeader soapHeader = (SOAPHeader) wsdl4jExtensibilityElement;
                SOAPHeaderMessage headerMessage = new SOAPHeaderMessage();
                headerMessage.setNamespaceURI(soapHeader.getNamespaceURI());
                headerMessage.setUse(soapHeader.getUse());
                Boolean required = soapHeader.getRequired();
                if (null != required) {
                    headerMessage.setRequired(required.booleanValue());
                }
                if (null != wsdl4jDefinition) {
                    // find the relevant schema part from the messages
                    Message msg = wsdl4jDefinition.getMessage(soapHeader
                            .getMessage());
                    if (msg == null) {
                        // todo i18n this
                        throw new AxisFault("message "
                                            + soapHeader.getMessage()
                                            + " not found in the WSDL ");
                    }
                    Part msgPart = msg.getPart(soapHeader.getPart());
                    if (msgPart == null) {
                        // todo i18n this
                        throw new AxisFault("message part "
                                            + soapHeader.getPart()
                                            + " not found in the WSDL ");
                    }
                    headerMessage.setElement(msgPart.getElementName());
                }
                headerMessage.setMessage(soapHeader.getMessage());

                headerMessage.setPart(soapHeader.getPart());

                if (description instanceof AxisBindingMessage) {
                    AxisBindingMessage bindingMessage = (AxisBindingMessage) description;
                    List soapHeaders =
                            (List) bindingMessage.getProperty(WSDL2Constants.ATTR_WSOAP_HEADER);
                    if (soapHeaders == null) {
                        soapHeaders = new ArrayList();
                        bindingMessage.setProperty(WSDL2Constants.ATTR_WSOAP_HEADER, soapHeaders);
                    }
                    soapHeaders.add(headerMessage);
                }
            } else if (wsdl4jExtensibilityElement instanceof SOAPBinding) {

                SOAPBinding soapBinding = (SOAPBinding) wsdl4jExtensibilityElement;
                AxisBinding axisBinding = (AxisBinding) description;

                axisBinding.setType(soapBinding.getTransportURI());

                axisBinding.setProperty(WSDL2Constants.ATTR_WSOAP_VERSION,
                                        SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI);

                String style = soapBinding.getStyle();
                if (style != null) {
                    axisBinding.setProperty(WSDLConstants.WSDL_1_1_STYLE, style);
                }

            } else if (wsdl4jExtensibilityElement instanceof SOAP12Binding) {

                SOAP12Binding soapBinding = (SOAP12Binding) wsdl4jExtensibilityElement;
                AxisBinding axisBinding = (AxisBinding) description;

                axisBinding.setProperty(WSDL2Constants.ATTR_WSOAP_VERSION,
                                        SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);

                String style = soapBinding.getStyle();
                if (style != null) {
                    axisBinding.setProperty(WSDLConstants.WSDL_1_1_STYLE, style);
                }

                String transportURI = soapBinding.getTransportURI();
                axisBinding.setType(transportURI);

            } else if (wsdl4jExtensibilityElement instanceof HTTPBinding) {
                HTTPBinding httpBinding = (HTTPBinding) wsdl4jExtensibilityElement;
                AxisBinding axisBinding = (AxisBinding) description;
                // set the binding style same as the wsd2 to process smoothly
                axisBinding.setType(WSDL2Constants.URI_WSDL2_HTTP);
                axisBinding.setProperty(WSDL2Constants.ATTR_WHTTP_METHOD, httpBinding.getVerb());
            }
        }
    }

    private int getPolicyAttachmentPoint(AxisDescription description,
                                         String originOfExtensibilityElements) {
        int result = -1; // Attachment Point Not Identified

        if (SERVICE.equals(originOfExtensibilityElements)) {
            result = PolicyInclude.SERVICE_POLICY;
        } else if (PORT.equals(originOfExtensibilityElements)) {
            result = PolicyInclude.PORT_POLICY;
        } else if (BINDING.equals(originOfExtensibilityElements)) {
            result = PolicyInclude.BINDING_POLICY;
        } else if (BINDING_OPERATION.equals(originOfExtensibilityElements)) {
            result = PolicyInclude.BINDING_OPERATION_POLICY;
        } else if (BINDING_OPERATION_INPUT.equals(originOfExtensibilityElements)) {
            result = PolicyInclude.BINDING_INPUT_POLICY;
        } else if (BINDING_OPERATION_OUTPUT.equals(originOfExtensibilityElements)) {
            result = PolicyInclude.BINDING_OUTPUT_POLICY;
        } else if (PORT_TYPE.equals(originOfExtensibilityElements)) {
            result = PolicyInclude.PORT_TYPE_POLICY;
        } else if (PORT_TYPE_OPERATION.equals(originOfExtensibilityElements)) {
            result = PolicyInclude.OPERATION_POLICY;
        } else if (PORT_TYPE_OPERATION_INPUT.equals(originOfExtensibilityElements)) {
            result = PolicyInclude.INPUT_POLICY;
        } else if (PORT_TYPE_OPERATION_OUTPUT.equals(originOfExtensibilityElements)) {
            result = PolicyInclude.OUTPUT_POLICY;
        }

        if (isTraceEnabled) {
            log.trace("getPolicyAttachmentPoint:: axisDescription=" + description +
                      " extensibilityPoint=" + originOfExtensibilityElements + " result=" + result);
        }

        return result;
    }

    /**
     * Look for the wrappable operations depending on the style
     *
     * @param binding
     * @return List of BindingOperationEntry objects
     */
    private List findWrappableBindingOperations(Binding binding) {
        // first find the global style declaration.
        // for a SOAP binding this can be only rpc or document
        // as per the WSDL spec (section 3.4) the default style is document

        // now we have to handle the http bindings case as well
        //

        boolean isRPC = false;
        boolean isSOAPBinding = false;
        boolean isHttpBinding = false;

        List extElements = binding.getExtensibilityElements();
        for (int i = 0; i < extElements.size(); i++) {
            if (extElements.get(i) instanceof SOAPBinding) {
                // we have a global SOAP binding!
                isSOAPBinding = true;
                SOAPBinding soapBinding = (SOAPBinding) extElements.get(i);
                if (RPC_STYLE.equals(soapBinding.getStyle())) {
                    // set the global style to rpc
                    isRPC = true;
                }
                this.bindingType = BINDING_TYPE_SOAP;
                break;
            } else if (extElements.get(i) instanceof SOAP12Binding) {
                // we have a global SOAP binding!
                isSOAPBinding = true;
                SOAP12Binding soapBinding = (SOAP12Binding) extElements.get(i);
                if (RPC_STYLE.equals(soapBinding.getStyle())) {
                    // set the global style to rpc
                    isRPC = true;
                }
                this.bindingType = BINDING_TYPE_SOAP;
                break;
            } else if (extElements.get(i) instanceof HTTPBinding) {
                isHttpBinding = true;
                this.bindingType = BINDING_TYPE_HTTP;
            }
        }
        
        if (log.isDebugEnabled()) {
            log.debug("Binding Name    =" + binding.getQName());
            log.debug("  isSOAPBinding =" + isSOAPBinding );
            log.debug("  isHttpBinding =" + isHttpBinding );
            log.debug("  isRPC         =" + isRPC );
        }

        // go through every operation and get their styles.
        // each one can have a style override from the global
        // styles. Depending on the style add the relevant operations
        // to the return list
        List returnList = new ArrayList();

        if (isHttpBinding || isSOAPBinding) {
            BindingOperation bindingOp;
            for (Iterator bindingOperationsIterator =
                    binding.getBindingOperations().iterator(); bindingOperationsIterator.hasNext();)
            {
                bindingOp = (BindingOperation) bindingOperationsIterator.next();
                
                if (log.isDebugEnabled()) {
                    log.debug("  Binding Operation  =" + bindingOp.getName());
                }
                if (isSOAPBinding) {
                    String style = getSOAPStyle(bindingOp);
                    if (log.isDebugEnabled()) {
                        log.debug("    SOAPStyle  =" + style);
                    }
                    if (style == null) {
                        // no style specified
                        // use the global style to determine whether to put this one or
                        // not
                        if (isRPC) {
                            if (log.isDebugEnabled()) {
                                log.debug("    schema wrappering required");
                            }
                            BindingOperationEntry boe = 
                                new BindingOperationEntry(bindingOp, 
                                                          true, 
                                                          false,
                                                          style,
                                                          true);
                            returnList.add(boe);
                        }
                    } else if (RPC_STYLE.equals(style)) {
                        // add to the list
                        if (log.isDebugEnabled()) {
                            log.debug("    schema wrappering required");
                        }
                        BindingOperationEntry boe = 
                            new BindingOperationEntry(bindingOp, 
                                                      true, 
                                                      false,
                                                      style,
                                                      true);
                        returnList.add(boe);
                    }
                    // if not RPC we just leave it - default is doc
                } else {
                    // i.e an http binding then we have to add the operation any way
                    if (log.isDebugEnabled()) {
                        log.debug("    schema wrappering required");
                    }
                    BindingOperationEntry boe = 
                        new BindingOperationEntry(bindingOp, 
                                                  false, 
                                                  true,
                                                  null,
                                                  false);
                    returnList.add(boe);
                }
            }
        }

        // if the binding is not either soap or http binding then we return and empty list

        // set this to the global list
        wrappableBOEs = returnList;
        return returnList;
    }

    /**
     * Guess the MEP based on the order of messages
     *
     * @param operation
     * @throws AxisFault
     */
    private String getMEP(Operation operation) throws AxisFault {
        OperationType operationType = operation.getStyle();
        if (isServerSide) {
            if (operationType != null) {
                if (operationType.equals(OperationType.REQUEST_RESPONSE)) {
                    return WSDL2Constants.MEP_URI_IN_OUT;
                }

                if (operationType.equals(OperationType.ONE_WAY)) {
                    if (operation.getFaults().size() > 0) {
                        return WSDL2Constants.MEP_URI_ROBUST_IN_ONLY;
                    }
                    return WSDL2Constants.MEP_URI_IN_ONLY;
                }

                if (operationType.equals(OperationType.NOTIFICATION)) {
                    return WSDL2Constants.MEP_URI_OUT_ONLY;
                }

                if (operationType.equals(OperationType.SOLICIT_RESPONSE)) {
                    return WSDL2Constants.MEP_URI_OUT_IN;
                }
                throw new AxisFault("Cannot Determine the MEP");
            }
        } else {
            if (operationType != null) {
                if (operationType.equals(OperationType.REQUEST_RESPONSE)) {
                    return WSDL2Constants.MEP_URI_OUT_IN;
                }

                if (operationType.equals(OperationType.ONE_WAY)) {
                    return WSDL2Constants.MEP_URI_OUT_ONLY;
                }

                if (operationType.equals(OperationType.NOTIFICATION)) {
                    return WSDL2Constants.MEP_URI_IN_ONLY;
                }

                if (operationType.equals(OperationType.SOLICIT_RESPONSE)) {
                    return WSDL2Constants.MEP_URI_IN_OUT;
                }
                throw new AxisFault("Cannot Determine the MEP");
            }
        }
        throw new AxisFault("Cannot Determine the MEP");
    }

    /**
     * Copies the extension attributes
     *
     * @param extAttributes
     * @param description
     * @param origin
     */
    private void copyExtensionAttributes(Map extAttributes,
			AxisDescription description, String origin) {

		QName key;
		QName value;

		for (Iterator iterator = extAttributes.keySet().iterator(); iterator
				.hasNext();) {
			key = (QName) iterator.next();

			if (Constants.URI_POLICY_NS.equals(key.getNamespaceURI())
					&& "PolicyURIs".equals(key.getLocalPart())) {

				value = (QName) extAttributes.get(key);
				String policyURIs = value.getLocalPart();

				if (policyURIs.length() != 0) {
					String[] uris = policyURIs.split(" ");

					PolicyReference ref;
					for (int i = 0; i < uris.length; i++) {
						ref = new PolicyReference();
						ref.setURI(uris[i]);

						if (PORT_TYPE.equals(origin)
						        || PORT_TYPE_OPERATION.equals(origin)
						        || PORT_TYPE_OPERATION_INPUT.equals(origin) 
						        || PORT_TYPE_OPERATION_OUTPUT.equals(origin)) {
                      
						    if (description != null) {
						        PolicySubject subject = description.getPolicySubject();
                             
						        if (subject != null) {
						            subject.attachPolicyReference(ref);
						        }
						    }
						}
					}
				}
			}
		}
	}

    /**
	 * Process the policy definitions
	 * 
	 * @param definition
	 */
    private void processPoliciesInDefintion(Definition definition) {
        processPoliciesInDefintion(definition, new HashSet());
    }

    /**
	 * Process the policy definitions
	 * 
	 * @param definition
	 */
    private void processPoliciesInDefintion(Definition definition, Set visitedWSDLs) {
        visitedWSDLs.add(definition.getDocumentBaseURI());
        List extElements = definition.getExtensibilityElements();
        ExtensibilityElement extElement;
        UnknownExtensibilityElement unknown = null;
        Policy policy = null;

        for (Iterator iterator = extElements.iterator(); iterator.hasNext();) {
            extElement = (ExtensibilityElement) iterator.next();

            if (extElement instanceof UnknownExtensibilityElement) {
                unknown = (UnknownExtensibilityElement) extElement;
                if (WSDLConstants.WSDL11Constants.POLICY.equals(unknown.getElementType())) {

                    policy = (Policy) PolicyUtil.getPolicyComponent(unknown.getElement());
                    String key;
                    if ((key = policy.getName()) != null || (key = policy.getId()) != null) {
                    	axisService.registerPolicy(key, policy);
//                        registry.register(key, policy);
//                        registry.register("#" + key, policy);
                    }

                }
            }
        }
        // include policices in other imported wsdls
        Iterator iter = definition.getImports().values().iterator();
        Vector values = null;
        Import wsdlImport = null;
        for (; iter.hasNext();) {
            values = (Vector) iter.next();
            for (Iterator valuesIter = values.iterator(); valuesIter.hasNext();) {
                wsdlImport = (Import) valuesIter.next();
                Definition innerDefinition = wsdlImport.getDefinition();
                // find the binding recursively
                if(!visitedWSDLs.contains(innerDefinition.getDocumentBaseURI())) {
                    processPoliciesInDefintion(innerDefinition, visitedWSDLs);
                }
            }
        }
    }
    
    private void setEndpointURL(AxisEndpoint axisEndpoint, String endpointURL) throws AxisFault {
    	axisEndpoint.setEndpointURL(endpointURL);
    	try {
    		URL url = new URL(endpointURL);
    		axisEndpoint.setTransportInDescription(url.getProtocol());
    	} catch (Exception e) {
    		log.debug(e.getMessage(),e);
		}    	
    }


    /**
     * Inner class declaration for the processing exceptions
     */
    public static class WSDLProcessingException extends RuntimeException {
        public WSDLProcessingException() {
        }

        public WSDLProcessingException(String message) {
            super(message);
        }

        public WSDLProcessingException(Throwable cause) {
            super(cause);
        }

        public WSDLProcessingException(String message, Throwable cause) {
            super(message, cause);
        }

    }

    public boolean isAllPorts() {
        return isAllPorts;
    }

    public void setAllPorts(boolean allPorts) {
        isAllPorts = allPorts;
    }

//    private void processPoliciesInDefinition() {
//
//        Object obj;
//        for (Iterator iterator = wsdl4jDefinition.getExtensibilityElements().iterator(); iterator.hasNext();) {
//            obj = iterator.next();
//
//            if (obj instanceof UnknownExtensibilityElement) {
//                Element e = ((UnknownExtensibilityElement) obj).getElement();
//                if (WSDLConstants.WSDL11Constants.POLICY.getNamespaceURI().equals(e.getNamespaceURI()) &&
//                        WSDLConstants.WSDL11Constants.POLICY.getLocalPart().equals(e.getLocalName())) {
//                    Policy p = (Policy) PolicyUtil.getPolicyComponent(e);
//                    reg.register(p.getId(), p);
//                }
//            }
//        }
//    }

    /**
     * This method is to split attribute like abc:cde and get the prefix part of it
     * so the method will retuen abc if the ":" is present in the the string else it
     * will return null
     *
     * @param attributeValue  : String
     * @return String
     */
    public static String getPrefix(String attributeValue) {
        if (attributeValue != null) {
            int splitIdex = attributeValue.indexOf(':');
            if (splitIdex > 0) {
                return attributeValue.substring(0, splitIdex);
            }
        }
        return null;
    }

    public static String getTypeName(String attributeValue) {
        if (attributeValue != null) {
            int splitIdex = attributeValue.indexOf(':');
            if (splitIdex > 0) {
                return attributeValue.substring(splitIdex + 1);
            } else {
                return attributeValue;
            }
        }
        return null;
    }

    /**
     * returns the wsld defintion for the given component.
     * @param definition
     * @param qname
     * @param componentType
     * @param visitedWSDLs
     * @return definition containing the component.
     */
    private Definition getParentDefinition(Definition definition,
                                           QName qname,
                                           int componentType,
                                           Set visitedWSDLs){
        visitedWSDLs.add(definition.getDocumentBaseURI());
        Definition newParentDefinition = null;
        // first find through imports
        Iterator iter = definition.getImports().values().iterator();
        Vector values = null;
        Import wsdlImport = null;
        for (; iter.hasNext();) {
            values = (Vector) iter.next();
            for (Iterator valuesIter = values.iterator(); valuesIter.hasNext();) {
                wsdlImport = (Import) valuesIter.next();
                Definition innerDefinition = wsdlImport.getDefinition();
                if (!visitedWSDLs.contains(innerDefinition.getDocumentBaseURI())){
                    newParentDefinition = getParentDefinition(innerDefinition,qname,componentType,visitedWSDLs);
                    if (newParentDefinition != null){
                        break;
                    }
                }
            }
            if (newParentDefinition != null) {
                break;
            }
        }

        // if it not available in imports we check for the current definition.
        if (newParentDefinition == null) {
            // this can be in a imported wsdl
            if (isComponetAvailable(definition, qname, componentType)) {
                newParentDefinition = definition;
            }
        }

        return newParentDefinition;
    }

    private boolean isComponetAvailable(Definition definition,
                                        QName qname,
                                        int componentType){
        boolean isAvailable = false;
        switch (componentType){
            case COMPONENT_BINDING : {
                isAvailable = (definition.getBinding(qname) != null) &&
                        (definition.getBinding(qname).getPortType() != null);
                break;
            }
            case COMPONENT_PORT_TYPE : {
                isAvailable = (definition.getPortType(qname) != null);
                break;
            }
            case COMPONENT_MESSAGE : {
                isAvailable = (definition.getMessage(qname) != null);
                break;
            }
        }
        return isAvailable;
    }
    
    /**
     * Find BindingOperationEntry
     * @param boes List of BindingOperationEntry
     * @param bo BindingOperation 
     * @return BindingOperation or null
     */
    private BindingOperationEntry find(List boes, BindingOperation bo) {
        for (int i=0; i < boes.size(); i++) {
            BindingOperationEntry boe = (BindingOperationEntry) boes.get(i);
            if (boe.getBindingOperation() == bo) {
                return boe;
            }
        }
        return null;
    }
    /**
     * BindingOperation plus state information
     */
    class BindingOperationEntry {
        
        private BindingOperation bindingOperation;
        private boolean isSOAPBinding;
        private boolean isHTTPBinding;
        private String soapStyle;
        private boolean isRPC;
        private boolean wrappedInput = true;
        private boolean wrappedOutput = true;
        
        public BindingOperationEntry(BindingOperation bindingOperation, boolean isSOAPBinding, boolean isHTTPBinding, String soapStyle, boolean isRPC) {
            super();
            this.bindingOperation = bindingOperation;
            this.isSOAPBinding = isSOAPBinding;
            this.isHTTPBinding = isHTTPBinding;
            this.soapStyle = soapStyle;
            this.isRPC = isRPC;
        }
        
        public boolean isHTTPBinding() {
            return isHTTPBinding;
        }
        public boolean isSOAPBinding() {
            return isSOAPBinding;
        }
        public String getSoapStyle() {
            return soapStyle;
        }
        
        public boolean isRPC() {
            return isRPC;
        }
        public BindingOperation getBindingOperation() {
            return bindingOperation;
        }

        /**
         * @return true if wrapper xsd is used
         */
        public boolean isWrappedInput() {
            return wrappedInput;
        }

        /**
         * @param wrappedInput indicate if wrapper xsd is needed
         */
        public void setWrappedInput(boolean wrappedInput) {
            this.wrappedInput = wrappedInput;
        }

        /**
         * @return true if wrapper xsd is needed for the output message
         */
        public boolean isWrappedOutput() {
            return wrappedOutput;
        }

        /**
         * @param wrappedOutput indicate if wrapper xsd is needed on the output message
         */
        public void setWrappedOutput(boolean wrappedOutput) {
            this.wrappedOutput = wrappedOutput;
        }
    }
}
