/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2008-2009 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.ws.axis2.http;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.jws.WebService;
import javax.wsdl.Binding;
import javax.wsdl.Definition;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.wsdl.WSDLException;
import javax.wsdl.extensions.http.HTTPBinding;
import javax.wsdl.extensions.soap.SOAPBinding;
import javax.wsdl.extensions.soap12.SOAP12Binding;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.xml.namespace.QName;
import javax.xml.ws.WebServiceException;

import org.apache.axis2.Constants;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.java2wsdl.Java2WSDLConstants;
import org.apache.axis2.engine.MessageReceiver;
import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.description.DescriptionFactory;
import org.apache.axis2.jaxws.description.EndpointDescription;
import org.apache.axis2.jaxws.description.ServiceDescription;
import org.apache.axis2.jaxws.description.builder.DescriptionBuilderComposite;
import org.apache.axis2.jaxws.description.builder.MethodDescriptionComposite;
import org.apache.axis2.jaxws.description.builder.WebServiceAnnot;
import org.apache.axis2.jaxws.description.builder.WebServiceProviderAnnot;
import org.apache.axis2.jaxws.description.builder.WsdlComposite;
import org.apache.axis2.jaxws.description.builder.WsdlGenerator;
import org.apache.axis2.jaxws.description.builder.converter.JavaClassToDBCConverter;
import org.apache.axis2.jaxws.server.JAXWSMessageReceiver;
import org.apache.axis2.wsdl.WSDLUtil;
import org.apache.ws.commons.schema.utils.NamespaceMap;
import org.ow2.jonas.ws.axis2.util.JAXWSUtils;
import org.ow2.jonas.ws.axis2.util.SimpleWSDLLocator;
import org.ow2.jonas.ws.jaxws.PortMetaData;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;
/**
 * Get service description from class or wsdl If the service impl is ejb, use
 * Axis2MessageReceiver, if it is pojo, use its own JAXWSMessageReceiver
 * @author youchao
 * @author xiaoda
 */
public class AxisServiceGenerator {
    private static final Log log = LogFactory.getLog(AxisServiceGenerator.class);

    /**
     * Corresponding MessageReceiver for pojo or ejb
     */
    private MessageReceiver messageReceiver;

    public AxisServiceGenerator() {
        this.messageReceiver = new JAXWSMessageReceiver();
    }

    /**
     * Set method
     * @param messageReceiver Corresponding MessageReceiver for pojo or ejb
     */
    public void setMessageReceiver(final MessageReceiver messageReceiver) {
        this.messageReceiver = messageReceiver;
    }

    /**
     * This method will be used to determine if a given DBC represents a Web service
     * implementation.
     *
     * @param dbc - <code>DescriptionBuilderComposite</code>
     * @return - <code>boolean</code>
     */
    private static boolean isImpl(final DescriptionBuilderComposite dbc) {
        if (!dbc.isInterface()
                && (dbc.getWebServiceAnnot() != null || dbc
                .getWebServiceProviderAnnot() != null)) {
            return true;
        }
        return false;
    }

    /** @throws MalformedURLException
     * @see org.apache.axis2.jaxws.description.DescriptionFactory#createServiceDescription(Class) */
    public static ServiceDescription createServiceDescription(final Class<?> serviceImplClass, final ConfigurationContext configurationContext, final PortMetaData pmd) throws MalformedURLException {
        ServiceDescription serviceDesc = null;

        if (serviceImplClass != null) {
            JavaClassToDBCConverter converter = new JavaClassToDBCConverter(serviceImplClass);
            HashMap<String, DescriptionBuilderComposite> dbcMap = converter.produceDBC();


            List<ServiceDescription> serviceDescriptionList = new ArrayList<ServiceDescription>();

            DescriptionBuilderComposite serviceImplComposite = null;
            for (Iterator<DescriptionBuilderComposite> nameIter = dbcMap.values()
                    .iterator(); nameIter.hasNext();) {
                DescriptionBuilderComposite tmpComposite = nameIter.next();
                if (isImpl(tmpComposite)) {
                    serviceImplComposite = tmpComposite;
                }
            }

            dbcMap.remove(serviceImplComposite.getClassName());
            URL wsdlURL = null;
            WebService ws = serviceImplClass.getAnnotation(WebService.class);

            if(pmd.getWSDLLocation()!=null) {
                wsdlURL = serviceImplClass.getClassLoader().getResource(pmd.getWSDLLocation());
            }

            List<ServiceDescription> serviceDescList = new ArrayList<ServiceDescription>();
            if (ws != null && wsdlURL == null && ws.wsdlLocation() != null && !"".equals(ws.wsdlLocation())) {
                wsdlURL = new URL(ws.wsdlLocation());
                serviceImplComposite.setwsdlURL(wsdlURL);
                dbcMap.put(serviceImplComposite.getClassName(), serviceImplComposite);
                serviceDescList = org.ow2.jonas.ws.axis2.jaxws.description.impl.DescriptionFactoryImpl
                        .createServiceDescriptionFromDBCMap(dbcMap,configurationContext);
            } else if (wsdlURL != null) {
                serviceImplComposite.setwsdlURL(wsdlURL);
                dbcMap.put(serviceImplComposite.getClassName(), serviceImplComposite);
                serviceDescList = org.ow2.jonas.ws.axis2.jaxws.description.impl.DescriptionFactoryImpl
                        .createServiceDescriptionFromDBCMap(dbcMap,configurationContext);
            } else {
                serviceDescList.add(org.ow2.jonas.ws.axis2.jaxws.description.impl.DescriptionFactoryImpl
                        .createServiceDescription(serviceImplClass));
            }




            if (serviceDescList != null && serviceDescList.size() > 0) {
                serviceDesc = serviceDescList.get(0);

                log.debug("ServiceDescription created with class: {0}", serviceImplClass);
                log.debug(serviceDesc);

            } else {
                if (log.isDebugEnabled()) {
                    log.debug("ServiceDesciption was not created for class: " + serviceImplClass);
                }
                // TODO: NLS & RAS
                throw ExceptionFactory.makeWebServiceException(
                        "A ServiceDescription was not created for " + serviceImplClass);
            }
        }
        return serviceDesc;
    }

    /*
    // @see org.apache.axis2.jaxws.description.DescriptionFactory#createServiceDescriptionFromDBCMap(HashMap)
    public static List<ServiceDescription> createServiceDescriptionFromDBCMap(
            final HashMap<String, DescriptionBuilderComposite> dbcMap, final ConfigurationContext configContext) {
        if (log.isDebugEnabled()) {
            log.debug("createServiceDescriptionFromDBCMap(Hashmap<String,DescriptionBuilderComposite>,ConfigurationContext " );
        }

        List<ServiceDescription> serviceDescriptionList = new ArrayList<ServiceDescription>();
        for (Iterator<DescriptionBuilderComposite> nameIter = dbcMap.values()
                .iterator(); nameIter.hasNext();) {
            DescriptionBuilderComposite serviceImplComposite = nameIter.next();
            if (isImpl(serviceImplComposite)) {
                // process this impl class

                org.ow2.jonas.ws.axis2.jaxws.description.impl.ServiceDescriptionImpl serviceDescription = new org.ow2.jonas.ws.axis2.jaxws.description.impl.ServiceDescriptionImpl(
                        dbcMap, serviceImplComposite, configContext);
                ServiceDescriptionValidator validator = new ServiceDescriptionValidator(serviceDescription);
                if (validator.validate()) {
                    serviceDescriptionList.add(serviceDescription);
                    if (log.isDebugEnabled()) {
                        log.debug("Service Description created from DescriptionComposite: " +
                                serviceDescription);
                    }
                }
//                } else {
//
//                    String msg = Messages.getMessage("createSrvcDescrDBCMapErr",
//                                                     validator.toString(),
//                                                     serviceImplComposite.toString(),
//                                                     serviceDescription.toString());
//                    throw ExceptionFactory.makeWebServiceException(msg);
//                }
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("DBC is not a service impl: " + serviceImplComposite.toString());
                }
            }
        }

        // TODO: Process all composites that are WebFaults...current thinking is
        // that
        // since WebFault annotations only exist on exception classes, then they
        // should be processed by themselves, and at this level

        return serviceDescriptionList;
    }
*/
    /**
     * Make AxisService from the service impl class
     * @param endpointClass
     * @return
     * @throws Exception
     */
    public AxisService getServiceFromClass(final Class endpointClass,final ConfigurationContext configurationContext,final PortMetaData pmd) throws Exception {
        ServiceDescription serviceDescription = createServiceDescription(endpointClass,configurationContext, pmd);//DescriptionFactory.createServiceDescription(endpointClass);
        EndpointDescription[] edArray = serviceDescription.getEndpointDescriptions();
        AxisService service = edArray[0].getAxisService();

        if (service.getNameSpacesMap() == null) {
            NamespaceMap map = new NamespaceMap();
            map.put(Java2WSDLConstants.AXIS2_NAMESPACE_PREFIX, Java2WSDLConstants.AXIS2_XSD);
            map.put(Java2WSDLConstants.DEFAULT_SCHEMA_NAMESPACE_PREFIX, Java2WSDLConstants.URI_2001_SCHEMA_XSD);
            service.setNameSpacesMap(map);
        }

        String endpointClassName = endpointClass.getName();
        ClassLoader classLoader = endpointClass.getClassLoader();

        service.addParameter(new Parameter(Constants.SERVICE_CLASS, endpointClassName));
        service.setClassLoader(classLoader);

        for (Iterator<AxisOperation> opIterator = service.getOperations(); opIterator.hasNext();) {
            AxisOperation operation = opIterator.next();
            operation.setMessageReceiver(this.messageReceiver);
        }

        Parameter serviceDescriptionParam = new Parameter(EndpointDescription.AXIS_SERVICE_PARAMETER, edArray[0]);
        service.addParameter(serviceDescriptionParam);

        return service;
    }

    /**
     * Make AxisService from wsdl file
     * @param portInfo
     * @param endpointClass
     * @param configurationBaseUrl
     * @return
     * @throws Exception
     */
    // public AxisService getServiceFromWSDL(final PortInfo portInfo, final
    // Class endpointClass, final URL configurationBaseUrl)
    // throws Exception {
    // String wsdlFile = portInfo.getWsdlFile();
    // if (wsdlFile == null || wsdlFile.equals("")) {
    // throw new Exception("WSDL file is required.");
    // }
    //
    // String endpointClassName = endpointClass.getName();
    // ClassLoader classLoader = endpointClass.getClassLoader();
    //
    // QName serviceQName = portInfo.getWsdlService();
    // if (serviceQName == null) {
    // serviceQName = JAXWSUtils.getServiceQName(endpointClass);
    // }
    //
    // QName portQName = portInfo.getWsdlPort();
    // if (portQName == null) {
    // portQName = JAXWSUtils.getPortQName(endpointClass);
    // }
    //
    // Definition wsdlDefinition = readWSDL(wsdlFile, configurationBaseUrl,
    // classLoader);
    //
    // Service wsdlService = wsdlDefinition.getService(serviceQName);
    // if (wsdlService == null) {
    // throw new Exception("Service '" + serviceQName + "' not found in WSDL");
    // }
    //
    // Port port = wsdlService.getPort(portQName.getLocalPart());
    // if (port == null) {
    // throw new Exception("Port '" + portQName.getLocalPart() + "' not found in
    // WSDL");
    // }
    //
    // Binding binding = port.getBinding();
    // List extElements = binding.getExtensibilityElements();
    // Iterator extElementsIterator = extElements.iterator();
    // String bindingS = javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING; //
    // // this is the default.
    // while (extElementsIterator.hasNext()) {
    // Object o = extElementsIterator.next();
    // if (o instanceof SOAPBinding) {
    // SOAPBinding sp = (SOAPBinding) o;
    // if
    // (sp.getElementType().getNamespaceURI().equals("http://schemas.xmlsoap.org/wsdl/soap/"))
    // {
    // // todo: how to we tell if it is MTOM or not.
    // bindingS = javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING;
    // }
    // } else if (o instanceof SOAP12Binding) {
    // SOAP12Binding sp = (SOAP12Binding) o;
    // if
    // (sp.getElementType().getNamespaceURI().equals("http://schemas.xmlsoap.org/wsdl/soap12/"))
    // {
    // // todo: how to we tell if it is MTOM or not.
    // bindingS = javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING;
    // }
    // } else if (o instanceof HTTPBinding) {
    // HTTPBinding sp = (HTTPBinding) o;
    // if
    // (sp.getElementType().getNamespaceURI().equals("http://www.w3.org/2004/08/wsdl/http"))
    // {
    // bindingS = javax.xml.ws.http.HTTPBinding.HTTP_BINDING;
    // }
    // }
    // }
    //
    // Class endPointClass = classLoader.loadClass(endpointClassName);
    // JavaClassToDBCConverter converter = new
    // JavaClassToDBCConverter(endPointClass);
    // HashMap<String, DescriptionBuilderComposite> dbcMap =
    // converter.produceDBC();
    //
    // DescriptionBuilderComposite dbc = dbcMap.get(endpointClassName);
    // dbc.setClassLoader(classLoader);
    // dbc.setWsdlDefinition(wsdlDefinition);
    // dbc.setClassName(endpointClassName);
    // dbc.setCustomWsdlGenerator(new WSDLGeneratorImpl(wsdlDefinition));
    //
    // if (dbc.getWebServiceAnnot() != null) { // information specified in
    // // .wsdl should overwrite
    // // annotation.
    // WebServiceAnnot serviceAnnot = dbc.getWebServiceAnnot();
    // serviceAnnot.setPortName(portQName.getLocalPart());
    // serviceAnnot.setServiceName(serviceQName.getLocalPart());
    // serviceAnnot.setTargetNamespace(serviceQName.getNamespaceURI());
    // if (dbc.getBindingTypeAnnot() != null && bindingS != null &&
    // !bindingS.equals("")) {
    // BindingTypeAnnot bindingAnnot = dbc.getBindingTypeAnnot();
    // bindingAnnot.setValue(bindingS);
    // }
    // } else if (dbc.getWebServiceProviderAnnot() != null) {
    // WebServiceProviderAnnot serviceProviderAnnot =
    // dbc.getWebServiceProviderAnnot();
    // serviceProviderAnnot.setPortName(portQName.getLocalPart());
    // serviceProviderAnnot.setServiceName(serviceQName.getLocalPart());
    // serviceProviderAnnot.setTargetNamespace(serviceQName.getNamespaceURI());
    // if (dbc.getBindingTypeAnnot() != null && bindingS != null &&
    // !bindingS.equals("")) {
    // BindingTypeAnnot bindingAnnot = dbc.getBindingTypeAnnot();
    // bindingAnnot.setValue(bindingS);
    // }
    // }
    //
    // AxisService service = getService(dbcMap);
    //
    // service.setName(serviceQName.getLocalPart());
    // service.setEndpointName(portQName.getLocalPart());
    //
    // for (Iterator<AxisOperation> opIterator = service.getOperations();
    // opIterator.hasNext();) {
    // AxisOperation operation = opIterator.next();
    // operation.setMessageReceiver(this.messageReceiver);
    // String MEP = operation.getMessageExchangePattern();
    // if (!WSDLUtil.isOutputPresentForMEP(MEP)) {
    // List<MethodDescriptionComposite> mdcList =
    // dbc.getMethodDescriptionComposite(operation.getName().toString());
    // for (Iterator<MethodDescriptionComposite> mIterator = mdcList.iterator();
    // mIterator.hasNext();) {
    // MethodDescriptionComposite mdc = mIterator.next();
    // // TODO: JAXWS spec says need to check Holder param exist
    // // before taking a method as OneWay
    // mdc.setOneWayAnnot(true);
    // }
    // }
    // }
    //
    // return service;
    // }
    //
    // private AxisService getService(HashMap<String,
    // DescriptionBuilderComposite> dbcMap) {
    // return getEndpointDescription(dbcMap).getAxisService();
    // }
    //
    // private EndpointDescription getEndpointDescription(HashMap<String,
    // DescriptionBuilderComposite> dbcMap) {
    // List<ServiceDescription> serviceDescList =
    // DescriptionFactory.createServiceDescriptionFromDBCMap(dbcMap);
    // if (serviceDescList == null || serviceDescList.isEmpty()) {
    // throw new RuntimeException("No service");
    // }
    // ServiceDescription serviceDescription = serviceDescList.get(0);
    // EndpointDescription[] edArray =
    // serviceDescription.getEndpointDescriptions();
    // if (edArray == null || edArray.length == 0) {
    // throw new RuntimeException("No endpoint");
    // }
    // return edArray[0];
    // }
    //
    // private static class WSDLGeneratorImpl implements WsdlGenerator {
    // private Definition def;
    //
    // public WSDLGeneratorImpl(Definition def) {
    // this.def = def;
    // }
    //
    // public WsdlComposite generateWsdl(final String implClass, final String
    // bindingType) throws WebServiceException {
    // // Need WSDL generation code
    // WsdlComposite composite = new WsdlComposite();
    // composite.setWsdlFileName(implClass);
    // HashMap<String, Definition> testMap = new HashMap<String, Definition>();
    // testMap.put(composite.getWsdlFileName(), def);
    // composite.setWsdlDefinition(testMap);
    // return composite;
    // }
    // }
    //
    // protected Definition readWSDL(final String wsdlLocation, final URL
    // configurationBaseUrl, final ClassLoader classLoader)
    // throws IOException, WSDLException {
    // Definition wsdlDefinition = null;
    // URL wsdlURL = getWsdlURL(wsdlLocation, configurationBaseUrl,
    // classLoader);
    // InputStream wsdlStream = null;
    // try {
    // wsdlStream = wsdlURL.openStream();
    // WSDLFactory factory = WSDLFactory.newInstance();
    // WSDLReader reader = factory.newWSDLReader();
    // reader.setFeature("javax.wsdl.importDocuments", true);
    // reader.setFeature("javax.wsdl.verbose", false);
    // SimpleWSDLLocator wsdlLocator = new
    // SimpleWSDLLocator(wsdlURL.toString());
    // wsdlDefinition = reader.readWSDL(wsdlLocator);
    // } finally {
    // if (wsdlStream != null) {
    // wsdlStream.close();
    // }
    // }
    // return wsdlDefinition;
    // }
    public static URL getWsdlURL(final String wsdlFile, final URL configurationBaseUrl, final ClassLoader classLoader) {
        URL wsdlURL = null;
        if (wsdlFile != null) {
            try {
                wsdlURL = new URL(wsdlFile);
            } catch (MalformedURLException e) {
                // Not a URL, try as a resource
                wsdlURL = classLoader.getResource(wsdlFile);

                if (wsdlURL == null && configurationBaseUrl != null) {
                    // Cannot get it as a resource, try with
                    // configurationBaseUrl
                    try {
                        wsdlURL = new URL(configurationBaseUrl, wsdlFile);
                    } catch (MalformedURLException ee) {
                        // ignore
                    }
                }
            }
        }
        return wsdlURL;
    }

    public static EndpointDescription getEndpointDescription(final AxisService service) {
        Parameter param = service.getParameter(EndpointDescription.AXIS_SERVICE_PARAMETER);
        return (param == null) ? null : (EndpointDescription) param.getValue();
    }

    public static boolean isSOAP11(final AxisService service) {
        EndpointDescription desc = AxisServiceGenerator.getEndpointDescription(service);
        return javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING.equals(desc.getBindingType())
                || javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_MTOM_BINDING.equals(desc.getBindingType());
    }

    public AxisService getServiceFromWSDL(final String wsdlFile, final Class endpointClass, final URL configurationBaseUrl) throws Exception {
        //String wsdlFile = portInfo.getWsdlFile();
        if (wsdlFile == null || wsdlFile.equals("")) {
            throw new Exception("WSDL file is required.");
        }

        String endpointClassName = endpointClass.getName();
        ClassLoader classLoader = endpointClass.getClassLoader();

        QName serviceQName = null;//portInfo.getWsdlService();
        if (serviceQName == null) {
            serviceQName = JAXWSUtils.getServiceQName(endpointClass);
        }

        QName portQName = null;//portInfo.getWsdlPort();
        if (portQName == null) {
            portQName = JAXWSUtils.getPortQName(endpointClass);
        }

        Definition wsdlDefinition = readWSDL(wsdlFile, configurationBaseUrl, classLoader);

        Service wsdlService = wsdlDefinition.getService(serviceQName);
        if (wsdlService == null) {
            throw new Exception("Service '" + serviceQName + "' not found in WSDL");
        }

        Port port = wsdlService.getPort(portQName.getLocalPart());
        if (port == null) {
            throw new Exception("Port '" + portQName.getLocalPart() + "' not found in WSDL");
        }

        String protocolBinding = null;
        //if (portInfo.getProtocolBinding() != null) {
        //    protocolBinding = JAXWSUtils.getBindingURI(portInfo.getProtocolBinding());
        //} else {
            protocolBinding = getBindingFromWSDL(port);
        //}

        Class endPointClass = classLoader.loadClass(endpointClassName);
        JavaClassToDBCConverter converter = new JavaClassToDBCConverter(endPointClass);
        HashMap<String, DescriptionBuilderComposite> dbcMap = converter.produceDBC();

        DescriptionBuilderComposite dbc = dbcMap.get(endpointClassName);
        dbc.setClassLoader(classLoader);
        dbc.setWsdlDefinition(wsdlDefinition);
        dbc.setClassName(endpointClassName);
        dbc.setCustomWsdlGenerator(new WSDLGeneratorImpl(wsdlDefinition));

        if (dbc.getWebServiceAnnot() != null) { //information specified in .wsdl should overwrite annotation.
            WebServiceAnnot serviceAnnot = dbc.getWebServiceAnnot();
            serviceAnnot.setPortName(portQName.getLocalPart());
            serviceAnnot.setServiceName(serviceQName.getLocalPart());
            serviceAnnot.setTargetNamespace(serviceQName.getNamespaceURI());
            processServiceBinding(dbc, protocolBinding);
        } else if (dbc.getWebServiceProviderAnnot() != null) {
            WebServiceProviderAnnot serviceProviderAnnot = dbc.getWebServiceProviderAnnot();
            serviceProviderAnnot.setPortName(portQName.getLocalPart());
            serviceProviderAnnot.setServiceName(serviceQName.getLocalPart());
            serviceProviderAnnot.setTargetNamespace(serviceQName.getNamespaceURI());
            processServiceBinding(dbc, protocolBinding);
        }

        /*
        if (portInfo.isMTOMEnabled() != null) {
            dbc.setIsMTOMEnabled(portInfo.isMTOMEnabled().booleanValue());
        }
        */

        AxisService service = getService(dbcMap);

        service.setName(serviceQName.getLocalPart());
        service.setEndpointName(portQName.getLocalPart());

        for(Iterator<AxisOperation> opIterator = service.getOperations() ; opIterator.hasNext() ;){
            AxisOperation operation = opIterator.next();
            operation.setMessageReceiver(this.messageReceiver);
            String MEP = operation.getMessageExchangePattern();
            if (!WSDLUtil.isOutputPresentForMEP(MEP)) {
                List<MethodDescriptionComposite> mdcList = dbc.getMethodDescriptionComposite(operation.getName().toString());
                for(Iterator<MethodDescriptionComposite> mIterator = mdcList.iterator(); mIterator.hasNext();){
                    MethodDescriptionComposite mdc = mIterator.next();
                    //TODO: JAXWS spec says need to check Holder param exist before taking a method as OneWay
                    mdc.setOneWayAnnot(true);
                }
            }
        }

        return service;
    }

    protected Definition readWSDL(final String wsdlLocation,
                                  final URL configurationBaseUrl,
                                  final ClassLoader classLoader)
        throws IOException, WSDLException {
        Definition wsdlDefinition = null;
        URL wsdlURL = getWsdlURL(wsdlLocation, configurationBaseUrl, classLoader);
        InputStream wsdlStream = null;
        try {
            wsdlStream = wsdlURL.openStream();
            WSDLFactory factory = WSDLFactory.newInstance();
            WSDLReader reader = factory.newWSDLReader();
            reader.setFeature("javax.wsdl.importDocuments", true);
            reader.setFeature("javax.wsdl.verbose", false);
            SimpleWSDLLocator wsdlLocator = new SimpleWSDLLocator(wsdlURL.toString());
            wsdlDefinition = reader.readWSDL(wsdlLocator);
        } finally {
            if (wsdlStream != null) {
                wsdlStream.close();
            }
        }
        return wsdlDefinition;
    }
    private String getBindingFromWSDL(final Port port) {
        Binding binding = port.getBinding();
        List extElements = binding.getExtensibilityElements();
        Iterator extElementsIterator = extElements.iterator();
        String bindingS = javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING; //this is the default.
        while (extElementsIterator.hasNext()) {
            Object o = extElementsIterator.next();
            if (o instanceof SOAPBinding) {
                SOAPBinding sp = (SOAPBinding)o;
                if (sp.getElementType().getNamespaceURI().equals("http://schemas.xmlsoap.org/wsdl/soap/")) {
                    bindingS = javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING;
                }
            } else if (o instanceof SOAP12Binding) {
                SOAP12Binding sp = (SOAP12Binding)o;
                if (sp.getElementType().getNamespaceURI().equals("http://schemas.xmlsoap.org/wsdl/soap12/")) {
                    bindingS = javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING;
                }
            } else if (o instanceof HTTPBinding) {
                HTTPBinding sp = (HTTPBinding)o;
                if (sp.getElementType().getNamespaceURI().equals("http://schemas.xmlsoap.org/wsdl/http/")) {
                    bindingS = javax.xml.ws.http.HTTPBinding.HTTP_BINDING;
                }
            }
        }
        return bindingS;
    }
    private static class WSDLGeneratorImpl implements WsdlGenerator {
        private Definition def;

        public WSDLGeneratorImpl(final Definition def) {
            this.def = def;
        }

        public WsdlComposite generateWsdl(final String implClass, final String bindingType) throws WebServiceException {
            // Need WSDL generation code
            WsdlComposite composite = new WsdlComposite();
            composite.setWsdlFileName(implClass);
            HashMap<String, Definition> testMap = new HashMap<String, Definition>();
            testMap.put(composite.getWsdlFileName(), def);
            composite.setWsdlDefinition(testMap);
            return composite;
        }

        public WsdlComposite generateWsdl(final String arg0, final EndpointDescription arg1) throws WebServiceException {
            // TODO Auto-generated method stub
            return null;
        }
    }
    private void processServiceBinding(final DescriptionBuilderComposite dbc, final String bindingFromWSDL) {
        if (dbc.getBindingTypeAnnot() == null || bindingFromWSDL == null || bindingFromWSDL.length() == 0) {
            return;
        }
        String bindingFromAnnotation = dbc.getBindingTypeAnnot().value();
        if (bindingFromAnnotation.equals(bindingFromWSDL)) {
            return;
        }
        if (bindingFromWSDL.equals(javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING)) {
            if (!bindingFromAnnotation.equals(javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_MTOM_BINDING)) {
                dbc.getBindingTypeAnnot().setValue(bindingFromWSDL);
            }
        } else if (bindingFromWSDL.equals(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)) {
            if (!bindingFromAnnotation.equals(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_MTOM_BINDING)) {
                dbc.getBindingTypeAnnot().setValue(bindingFromWSDL);
            }
        } else {
            dbc.getBindingTypeAnnot().setValue(bindingFromWSDL);
        }
    }
    private AxisService getService(final HashMap<String, DescriptionBuilderComposite> dbcMap) {
        return getEndpointDescription(dbcMap).getAxisService();
    }
    private EndpointDescription getEndpointDescription(final HashMap<String, DescriptionBuilderComposite> dbcMap) {
        List<ServiceDescription> serviceDescList = DescriptionFactory.createServiceDescriptionFromDBCMap(dbcMap);
        if (serviceDescList == null || serviceDescList.isEmpty()) {
            throw new RuntimeException("No service");
        }
        ServiceDescription serviceDescription = serviceDescList.get(0);
        EndpointDescription[] edArray = serviceDescription.getEndpointDescriptions();
        if (edArray == null || edArray.length == 0) {
            throw new RuntimeException("No endpoint");
        }
        return edArray[0];
    }

}
