001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.geronimo.axis2;
019    
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.net.MalformedURLException;
023    import java.net.URL;
024    import java.util.HashMap;
025    import java.util.Iterator;
026    import java.util.List;
027    
028    import javax.wsdl.Binding;
029    import javax.wsdl.Definition;
030    import javax.wsdl.Port;
031    import javax.wsdl.Service;
032    import javax.wsdl.WSDLException;
033    import javax.wsdl.extensions.http.HTTPBinding;
034    import javax.wsdl.extensions.soap.SOAPBinding;
035    import javax.wsdl.extensions.soap12.SOAP12Binding;
036    import javax.wsdl.factory.WSDLFactory;
037    import javax.wsdl.xml.WSDLReader;
038    import javax.xml.namespace.QName;
039    import javax.xml.ws.WebServiceException;
040    
041    import org.apache.axis2.Constants;
042    import org.apache.axis2.description.AxisOperation;
043    import org.apache.axis2.description.AxisService;
044    import org.apache.axis2.description.Parameter;
045    import org.apache.axis2.description.java2wsdl.Java2WSDLConstants;
046    import org.apache.axis2.engine.MessageReceiver;
047    import org.apache.axis2.jaxws.description.DescriptionFactory;
048    import org.apache.axis2.jaxws.description.EndpointDescription;
049    import org.apache.axis2.jaxws.description.ServiceDescription;
050    import org.apache.axis2.jaxws.description.builder.BindingTypeAnnot;
051    import org.apache.axis2.jaxws.description.builder.DescriptionBuilderComposite;
052    import org.apache.axis2.jaxws.description.builder.MethodDescriptionComposite;
053    import org.apache.axis2.jaxws.description.builder.WebServiceAnnot;
054    import org.apache.axis2.jaxws.description.builder.WebServiceProviderAnnot;
055    import org.apache.axis2.jaxws.description.builder.WsdlComposite;
056    import org.apache.axis2.jaxws.description.builder.WsdlGenerator;
057    import org.apache.axis2.jaxws.description.builder.converter.JavaClassToDBCConverter;
058    import org.apache.axis2.jaxws.server.JAXWSMessageReceiver;
059    import org.apache.axis2.wsdl.WSDLUtil;
060    import org.apache.commons.logging.Log;
061    import org.apache.commons.logging.LogFactory;
062    import org.apache.geronimo.axis2.util.SimpleWSDLLocator;
063    import org.apache.geronimo.jaxws.JAXWSUtils;
064    import org.apache.geronimo.jaxws.PortInfo;
065    import org.apache.ws.commons.schema.utils.NamespaceMap;
066    
067    /**
068     * @version $Rev$ $Date$
069     */
070    public class AxisServiceGenerator {
071        private static final Log log = LogFactory.getLog(AxisServiceGenerator.class);
072            
073        private MessageReceiver messageReceiver;
074        
075        public AxisServiceGenerator(){
076            this.messageReceiver = new JAXWSMessageReceiver();
077        }
078        
079        public void setMessageReceiver(MessageReceiver messageReceiver) {
080            this.messageReceiver = messageReceiver;
081        }
082       
083        public AxisService getServiceFromClass(Class endpointClass) throws Exception {
084            ServiceDescription serviceDescription = 
085                DescriptionFactory.createServiceDescription(endpointClass);        
086            EndpointDescription[] edArray = serviceDescription.getEndpointDescriptions();
087            AxisService service = edArray[0].getAxisService();
088                    
089            if (service.getNameSpacesMap() == null) {
090                NamespaceMap map = new NamespaceMap();
091                map.put(Java2WSDLConstants.AXIS2_NAMESPACE_PREFIX,
092                        Java2WSDLConstants.AXIS2_XSD);
093                map.put(Java2WSDLConstants.DEFAULT_SCHEMA_NAMESPACE_PREFIX,
094                        Java2WSDLConstants.URI_2001_SCHEMA_XSD);
095                service.setNameSpacesMap(map);
096            }
097            
098            String endpointClassName = endpointClass.getName();
099            ClassLoader classLoader = endpointClass.getClassLoader();
100            
101            service.addParameter(new Parameter(Constants.SERVICE_CLASS, endpointClassName));
102            service.setClassLoader(classLoader);
103            
104            for(Iterator<AxisOperation> opIterator = service.getOperations() ; opIterator.hasNext() ;){
105                AxisOperation operation = opIterator.next();
106                operation.setMessageReceiver(this.messageReceiver);
107            }
108            
109            Parameter serviceDescriptionParam = 
110                new Parameter(EndpointDescription.AXIS_SERVICE_PARAMETER, edArray[0]);
111            service.addParameter(serviceDescriptionParam);
112            
113            return service;
114        }
115        
116        public AxisService getServiceFromWSDL(PortInfo portInfo, Class endpointClass, URL configurationBaseUrl) throws Exception {
117            String wsdlFile = portInfo.getWsdlFile();
118            if (wsdlFile == null || wsdlFile.equals("")) {
119                throw new Exception("WSDL file is required.");
120            }
121            
122            String endpointClassName = endpointClass.getName();
123            ClassLoader classLoader = endpointClass.getClassLoader();
124                            
125            QName serviceQName = portInfo.getWsdlService();
126            if (serviceQName == null) {
127                serviceQName = JAXWSUtils.getServiceQName(endpointClass);
128            }
129            
130            QName portQName = portInfo.getWsdlPort();
131            if (portQName == null) {
132                portQName = JAXWSUtils.getPortQName(endpointClass);
133            }
134                    
135            Definition wsdlDefinition = readWSDL(wsdlFile, configurationBaseUrl, classLoader);
136            
137            Service wsdlService = wsdlDefinition.getService(serviceQName);
138            if (wsdlService == null) {
139                throw new Exception("Service '" + serviceQName + "' not found in WSDL");
140            }
141            
142            Port port = wsdlService.getPort(portQName.getLocalPart());
143            if (port == null) {
144                throw new Exception("Port '" + portQName.getLocalPart() + "' not found in WSDL");
145            }
146            
147            Binding binding = port.getBinding();
148            List extElements = binding.getExtensibilityElements();
149            Iterator extElementsIterator =extElements.iterator();
150            String  bindingS = javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING; //this is the default.
151            while (extElementsIterator.hasNext()) {
152                Object o = extElementsIterator.next();
153                if (o instanceof SOAPBinding) {
154                    SOAPBinding sp = (SOAPBinding)o;
155                    if (sp.getElementType().getNamespaceURI().equals("http://schemas.xmlsoap.org/wsdl/soap/")) {
156                        //todo:  how to we tell if it is MTOM or not.
157                        bindingS = javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING;
158                    } 
159                } else if (o instanceof SOAP12Binding) {
160                    SOAP12Binding sp = (SOAP12Binding)o;
161                    if (sp.getElementType().getNamespaceURI().equals("http://schemas.xmlsoap.org/wsdl/soap12/")) {
162                       //todo:  how to we tell if it is MTOM or not.
163                        bindingS = javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING;
164                    }
165                } else if (o instanceof HTTPBinding) {
166                    HTTPBinding sp = (HTTPBinding)o;
167                    if (sp.getElementType().getNamespaceURI().equals("http://www.w3.org/2004/08/wsdl/http")) {
168                        bindingS = javax.xml.ws.http.HTTPBinding.HTTP_BINDING;
169                    }               
170                }
171            }
172            
173            Class endPointClass = classLoader.loadClass(endpointClassName);
174            JavaClassToDBCConverter converter = new JavaClassToDBCConverter(endPointClass);
175            HashMap<String, DescriptionBuilderComposite> dbcMap = converter.produceDBC();
176           
177            DescriptionBuilderComposite dbc = dbcMap.get(endpointClassName);
178            dbc.setClassLoader(classLoader);
179            dbc.setWsdlDefinition(wsdlDefinition);
180            dbc.setClassName(endpointClassName);
181            dbc.setCustomWsdlGenerator(new WSDLGeneratorImpl(wsdlDefinition));
182            
183            if (dbc.getWebServiceAnnot() != null) { //information specified in .wsdl should overwrite annotation.
184                WebServiceAnnot serviceAnnot = dbc.getWebServiceAnnot();
185                serviceAnnot.setPortName(portQName.getLocalPart());
186                serviceAnnot.setServiceName(serviceQName.getLocalPart());
187                serviceAnnot.setTargetNamespace(serviceQName.getNamespaceURI());
188                if (dbc.getBindingTypeAnnot() !=null && bindingS != null && !bindingS.equals("")) {
189                    BindingTypeAnnot bindingAnnot = dbc.getBindingTypeAnnot();
190                    bindingAnnot.setValue(bindingS);
191                }
192            } else if (dbc.getWebServiceProviderAnnot() != null) { 
193                WebServiceProviderAnnot serviceProviderAnnot = dbc.getWebServiceProviderAnnot(); 
194                serviceProviderAnnot.setPortName(portQName.getLocalPart());
195                serviceProviderAnnot.setServiceName(serviceQName.getLocalPart());
196                serviceProviderAnnot.setTargetNamespace(serviceQName.getNamespaceURI());
197                if (dbc.getBindingTypeAnnot() !=null && bindingS != null && !bindingS.equals("")) {
198                    BindingTypeAnnot bindingAnnot = dbc.getBindingTypeAnnot();
199                    bindingAnnot.setValue(bindingS);
200                }
201            }
202    
203            AxisService service = getService(dbcMap);       
204            
205            service.setName(serviceQName.getLocalPart());
206            service.setEndpointName(portQName.getLocalPart());
207            
208            for(Iterator<AxisOperation> opIterator = service.getOperations() ; opIterator.hasNext() ;){
209                AxisOperation operation = opIterator.next();
210                operation.setMessageReceiver(this.messageReceiver);
211                String MEP = operation.getMessageExchangePattern();
212                if (!WSDLUtil.isOutputPresentForMEP(MEP)) {
213                    List<MethodDescriptionComposite> mdcList = dbc.getMethodDescriptionComposite(operation.getName().toString());
214                    for(Iterator<MethodDescriptionComposite> mIterator = mdcList.iterator(); mIterator.hasNext();){
215                        MethodDescriptionComposite mdc = mIterator.next();
216                        //TODO: JAXWS spec says need to check Holder param exist before taking a method as OneWay
217                        mdc.setOneWayAnnot(true);
218                    }
219                }
220            }
221    
222            return service;
223        }
224    
225        private AxisService getService(HashMap<String, DescriptionBuilderComposite> dbcMap) {
226            return getEndpointDescription(dbcMap).getAxisService();
227        }
228            
229        private EndpointDescription getEndpointDescription(HashMap<String, DescriptionBuilderComposite> dbcMap) {
230            List<ServiceDescription> serviceDescList = DescriptionFactory.createServiceDescriptionFromDBCMap(dbcMap);
231            if (serviceDescList == null || serviceDescList.isEmpty()) {
232                throw new RuntimeException("No service");
233            }
234            ServiceDescription serviceDescription = serviceDescList.get(0);
235            EndpointDescription[] edArray = serviceDescription.getEndpointDescriptions();  
236            if (edArray == null || edArray.length == 0) {
237                throw new RuntimeException("No endpoint");
238            }
239            return edArray[0];
240        }
241    
242        private class WSDLGeneratorImpl implements WsdlGenerator {
243            private Definition def;
244    
245            public WSDLGeneratorImpl(Definition def) {
246                this.def = def;
247            }
248            
249            public WsdlComposite generateWsdl(String implClass, String bindingType) throws WebServiceException {
250                // Need WSDL generation code
251                WsdlComposite composite = new WsdlComposite();
252                composite.setWsdlFileName(implClass);
253                HashMap<String, Definition> testMap = new HashMap<String, Definition>();
254                testMap.put(composite.getWsdlFileName(), def);
255                composite.setWsdlDefinition(testMap);
256                return composite;
257            }
258        }
259        
260        protected Definition readWSDL(String wsdlLocation, 
261                                      URL configurationBaseUrl, 
262                                      ClassLoader classLoader)
263            throws IOException, WSDLException {
264            Definition wsdlDefinition = null;
265            URL wsdlURL = getWsdlURL(wsdlLocation, configurationBaseUrl, classLoader);
266            InputStream wsdlStream = null;
267            try {
268                wsdlStream = wsdlURL.openStream();
269                WSDLFactory factory = WSDLFactory.newInstance();
270                WSDLReader reader = factory.newWSDLReader();
271                reader.setFeature("javax.wsdl.importDocuments", true);
272                reader.setFeature("javax.wsdl.verbose", false);
273                SimpleWSDLLocator wsdlLocator = new SimpleWSDLLocator(wsdlURL.toString());
274                wsdlDefinition = reader.readWSDL(wsdlLocator);
275            } finally {
276                if (wsdlStream != null) {
277                    wsdlStream.close();
278                }
279            }
280            return wsdlDefinition;
281        }
282        
283        public static URL getWsdlURL(String wsdlFile, URL configurationBaseUrl, ClassLoader classLoader) {
284            URL wsdlURL = null;
285            if (wsdlFile != null) {
286                try {
287                    wsdlURL = new URL(wsdlFile);
288                } catch (MalformedURLException e) {
289                    // Not a URL, try as a resource
290                    wsdlURL = classLoader.getResource(wsdlFile);
291    
292                    if (wsdlURL == null && configurationBaseUrl != null) {
293                        // Cannot get it as a resource, try with
294                        // configurationBaseUrl
295                        try {
296                            wsdlURL = new URL(configurationBaseUrl, wsdlFile);
297                        } catch (MalformedURLException ee) {
298                            // ignore
299                        }
300                    }
301                }
302            }
303            return wsdlURL;
304        }
305        
306        public static EndpointDescription getEndpointDescription(AxisService service) {
307            Parameter param = service.getParameter(EndpointDescription.AXIS_SERVICE_PARAMETER);
308            return (param == null) ? null : (EndpointDescription) param.getValue();
309        }
310             
311    }