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.DescriptionBuilderComposite;
051    import org.apache.axis2.jaxws.description.builder.MethodDescriptionComposite;
052    import org.apache.axis2.jaxws.description.builder.WebServiceAnnot;
053    import org.apache.axis2.jaxws.description.builder.WebServiceProviderAnnot;
054    import org.apache.axis2.jaxws.description.builder.WsdlComposite;
055    import org.apache.axis2.jaxws.description.builder.WsdlGenerator;
056    import org.apache.axis2.jaxws.description.builder.converter.JavaClassToDBCConverter;
057    import org.apache.axis2.jaxws.server.JAXWSMessageReceiver;
058    import org.apache.axis2.wsdl.WSDLUtil;
059    import org.apache.commons.logging.Log;
060    import org.apache.commons.logging.LogFactory;
061    import org.apache.geronimo.axis2.util.SimpleWSDLLocator;
062    import org.apache.geronimo.jaxws.JAXWSUtils;
063    import org.apache.geronimo.jaxws.PortInfo;
064    import org.apache.ws.commons.schema.utils.NamespaceMap;
065    
066    /**
067     * @version $Rev$ $Date$
068     */
069    public class AxisServiceGenerator {
070        private static final Log log = LogFactory.getLog(AxisServiceGenerator.class);
071            
072        private MessageReceiver messageReceiver;
073        
074        public AxisServiceGenerator(){
075            this.messageReceiver = new JAXWSMessageReceiver();
076        }
077        
078        public void setMessageReceiver(MessageReceiver messageReceiver) {
079            this.messageReceiver = messageReceiver;
080        }
081       
082        public AxisService getServiceFromClass(Class endpointClass) throws Exception {
083            ServiceDescription serviceDescription = 
084                DescriptionFactory.createServiceDescription(endpointClass);        
085            EndpointDescription[] edArray = serviceDescription.getEndpointDescriptions();
086            AxisService service = edArray[0].getAxisService();
087                    
088            if (service.getNameSpacesMap() == null) {
089                NamespaceMap map = new NamespaceMap();
090                map.put(Java2WSDLConstants.AXIS2_NAMESPACE_PREFIX,
091                        Java2WSDLConstants.AXIS2_XSD);
092                map.put(Java2WSDLConstants.DEFAULT_SCHEMA_NAMESPACE_PREFIX,
093                        Java2WSDLConstants.URI_2001_SCHEMA_XSD);
094                service.setNameSpacesMap(map);
095            }
096            
097            String endpointClassName = endpointClass.getName();
098            ClassLoader classLoader = endpointClass.getClassLoader();
099            
100            service.addParameter(new Parameter(Constants.SERVICE_CLASS, endpointClassName));
101            service.setClassLoader(classLoader);
102            
103            for(Iterator<AxisOperation> opIterator = service.getOperations() ; opIterator.hasNext() ;){
104                AxisOperation operation = opIterator.next();
105                operation.setMessageReceiver(this.messageReceiver);
106            }
107            
108            Parameter serviceDescriptionParam = 
109                new Parameter(EndpointDescription.AXIS_SERVICE_PARAMETER, edArray[0]);
110            service.addParameter(serviceDescriptionParam);
111            
112            return service;
113        }
114        
115        public AxisService getServiceFromWSDL(PortInfo portInfo, Class endpointClass, URL configurationBaseUrl) throws Exception {
116            String wsdlFile = portInfo.getWsdlFile();
117            if (wsdlFile == null || wsdlFile.equals("")) {
118                throw new Exception("WSDL file is required.");
119            }
120            
121            String endpointClassName = endpointClass.getName();
122            ClassLoader classLoader = endpointClass.getClassLoader();
123                            
124            QName serviceQName = portInfo.getWsdlService();
125            if (serviceQName == null) {
126                serviceQName = JAXWSUtils.getServiceQName(endpointClass);
127            }
128            
129            QName portQName = portInfo.getWsdlPort();
130            if (portQName == null) {
131                portQName = JAXWSUtils.getPortQName(endpointClass);
132            }
133                    
134            Definition wsdlDefinition = readWSDL(wsdlFile, configurationBaseUrl, classLoader);
135            
136            Service wsdlService = wsdlDefinition.getService(serviceQName);
137            if (wsdlService == null) {
138                throw new Exception("Service '" + serviceQName + "' not found in WSDL");
139            }
140            
141            Port port = wsdlService.getPort(portQName.getLocalPart());
142            if (port == null) {
143                throw new Exception("Port '" + portQName.getLocalPart() + "' not found in WSDL");
144            }
145            
146            String protocolBinding = null;
147            if (portInfo.getProtocolBinding() != null) {
148                protocolBinding = JAXWSUtils.getBindingURI(portInfo.getProtocolBinding());
149            } else {
150                protocolBinding = getBindingFromWSDL(port);
151            }
152            
153            Class endPointClass = classLoader.loadClass(endpointClassName);
154            JavaClassToDBCConverter converter = new JavaClassToDBCConverter(endPointClass);
155            HashMap<String, DescriptionBuilderComposite> dbcMap = converter.produceDBC();
156           
157            DescriptionBuilderComposite dbc = dbcMap.get(endpointClassName);
158            dbc.setClassLoader(classLoader);
159            dbc.setWsdlDefinition(wsdlDefinition);
160            dbc.setClassName(endpointClassName);
161            dbc.setCustomWsdlGenerator(new WSDLGeneratorImpl(wsdlDefinition));
162            
163            if (dbc.getWebServiceAnnot() != null) { //information specified in .wsdl should overwrite annotation.
164                WebServiceAnnot serviceAnnot = dbc.getWebServiceAnnot();
165                serviceAnnot.setPortName(portQName.getLocalPart());
166                serviceAnnot.setServiceName(serviceQName.getLocalPart());
167                serviceAnnot.setTargetNamespace(serviceQName.getNamespaceURI());
168                processServiceBinding(dbc, protocolBinding);
169            } else if (dbc.getWebServiceProviderAnnot() != null) { 
170                WebServiceProviderAnnot serviceProviderAnnot = dbc.getWebServiceProviderAnnot(); 
171                serviceProviderAnnot.setPortName(portQName.getLocalPart());
172                serviceProviderAnnot.setServiceName(serviceQName.getLocalPart());
173                serviceProviderAnnot.setTargetNamespace(serviceQName.getNamespaceURI());
174                processServiceBinding(dbc, protocolBinding);
175            }
176    
177            /*
178            if (portInfo.isMTOMEnabled() != null) {
179                dbc.setIsMTOMEnabled(portInfo.isMTOMEnabled().booleanValue());
180            }
181            */
182    
183            AxisService service = getService(dbcMap);       
184            
185            service.setName(serviceQName.getLocalPart());
186            service.setEndpointName(portQName.getLocalPart());
187            
188            for(Iterator<AxisOperation> opIterator = service.getOperations() ; opIterator.hasNext() ;){
189                AxisOperation operation = opIterator.next();
190                operation.setMessageReceiver(this.messageReceiver);
191                String MEP = operation.getMessageExchangePattern();
192                if (!WSDLUtil.isOutputPresentForMEP(MEP)) {
193                    List<MethodDescriptionComposite> mdcList = dbc.getMethodDescriptionComposite(operation.getName().toString());
194                    for(Iterator<MethodDescriptionComposite> mIterator = mdcList.iterator(); mIterator.hasNext();){
195                        MethodDescriptionComposite mdc = mIterator.next();
196                        //TODO: JAXWS spec says need to check Holder param exist before taking a method as OneWay
197                        mdc.setOneWayAnnot(true);
198                    }
199                }
200            }
201    
202            return service;
203        }
204    
205        private String getBindingFromWSDL(Port port) {        
206            Binding binding = port.getBinding();
207            List extElements = binding.getExtensibilityElements();
208            Iterator extElementsIterator = extElements.iterator();
209            String bindingS = javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING; //this is the default.
210            while (extElementsIterator.hasNext()) {
211                Object o = extElementsIterator.next();
212                if (o instanceof SOAPBinding) {
213                    SOAPBinding sp = (SOAPBinding)o;
214                    if (sp.getElementType().getNamespaceURI().equals("http://schemas.xmlsoap.org/wsdl/soap/")) {
215                        bindingS = javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING;
216                    } 
217                } else if (o instanceof SOAP12Binding) {
218                    SOAP12Binding sp = (SOAP12Binding)o;
219                    if (sp.getElementType().getNamespaceURI().equals("http://schemas.xmlsoap.org/wsdl/soap12/")) {
220                        bindingS = javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING;
221                    }
222                } else if (o instanceof HTTPBinding) {
223                    HTTPBinding sp = (HTTPBinding)o;
224                    if (sp.getElementType().getNamespaceURI().equals("http://schemas.xmlsoap.org/wsdl/http/")) {
225                        bindingS = javax.xml.ws.http.HTTPBinding.HTTP_BINDING;
226                    }               
227                }
228            }
229            return bindingS;
230        }
231    
232        private void processServiceBinding(DescriptionBuilderComposite dbc, String bindingFromWSDL) {
233            if (dbc.getBindingTypeAnnot() == null || bindingFromWSDL == null || bindingFromWSDL.length() == 0) {
234                return;
235            }
236            String bindingFromAnnotation = dbc.getBindingTypeAnnot().value();
237            if (bindingFromAnnotation.equals(bindingFromWSDL)) {
238                return;
239            }
240            if (bindingFromWSDL.equals(javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING)) {
241                if (!bindingFromAnnotation.equals(javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_MTOM_BINDING)) {
242                    dbc.getBindingTypeAnnot().setValue(bindingFromWSDL);
243                }
244            } else if (bindingFromWSDL.equals(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)) {
245                if (!bindingFromAnnotation.equals(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_MTOM_BINDING)) {
246                    dbc.getBindingTypeAnnot().setValue(bindingFromWSDL);
247                }
248            } else {
249                dbc.getBindingTypeAnnot().setValue(bindingFromWSDL);
250            }
251        }
252    
253        private AxisService getService(HashMap<String, DescriptionBuilderComposite> dbcMap) {
254            return getEndpointDescription(dbcMap).getAxisService();
255        }
256            
257        private EndpointDescription getEndpointDescription(HashMap<String, DescriptionBuilderComposite> dbcMap) {
258            List<ServiceDescription> serviceDescList = DescriptionFactory.createServiceDescriptionFromDBCMap(dbcMap);
259            if (serviceDescList == null || serviceDescList.isEmpty()) {
260                throw new RuntimeException("No service");
261            }
262            ServiceDescription serviceDescription = serviceDescList.get(0);
263            EndpointDescription[] edArray = serviceDescription.getEndpointDescriptions();  
264            if (edArray == null || edArray.length == 0) {
265                throw new RuntimeException("No endpoint");
266            }
267            return edArray[0];
268        }
269    
270        private static class WSDLGeneratorImpl implements WsdlGenerator {
271            private Definition def;
272    
273            public WSDLGeneratorImpl(Definition def) {
274                this.def = def;
275            }
276            
277            public WsdlComposite generateWsdl(String implClass, String bindingType) throws WebServiceException {
278                // Need WSDL generation code
279                WsdlComposite composite = new WsdlComposite();
280                composite.setWsdlFileName(implClass);
281                HashMap<String, Definition> testMap = new HashMap<String, Definition>();
282                testMap.put(composite.getWsdlFileName(), def);
283                composite.setWsdlDefinition(testMap);
284                return composite;
285            }
286        }
287        
288        protected Definition readWSDL(String wsdlLocation, 
289                                      URL configurationBaseUrl, 
290                                      ClassLoader classLoader)
291            throws IOException, WSDLException {
292            Definition wsdlDefinition = null;
293            URL wsdlURL = getWsdlURL(wsdlLocation, configurationBaseUrl, classLoader);
294            InputStream wsdlStream = null;
295            try {
296                wsdlStream = wsdlURL.openStream();
297                WSDLFactory factory = WSDLFactory.newInstance();
298                WSDLReader reader = factory.newWSDLReader();
299                reader.setFeature("javax.wsdl.importDocuments", true);
300                reader.setFeature("javax.wsdl.verbose", false);
301                SimpleWSDLLocator wsdlLocator = new SimpleWSDLLocator(wsdlURL.toString());
302                wsdlDefinition = reader.readWSDL(wsdlLocator);
303            } finally {
304                if (wsdlStream != null) {
305                    wsdlStream.close();
306                }
307            }
308            return wsdlDefinition;
309        }
310        
311        public static URL getWsdlURL(String wsdlFile, URL configurationBaseUrl, ClassLoader classLoader) {
312            URL wsdlURL = null;
313            if (wsdlFile != null) {
314                try {
315                    wsdlURL = new URL(wsdlFile);
316                } catch (MalformedURLException e) {
317                    // Not a URL, try as a resource
318                    wsdlURL = classLoader.getResource(wsdlFile);
319    
320                    if (wsdlURL == null && configurationBaseUrl != null) {
321                        // Cannot get it as a resource, try with
322                        // configurationBaseUrl
323                        try {
324                            wsdlURL = new URL(configurationBaseUrl, wsdlFile);
325                        } catch (MalformedURLException ee) {
326                            // ignore
327                        }
328                    }
329                }
330            }
331            return wsdlURL;
332        }
333        
334        public static EndpointDescription getEndpointDescription(AxisService service) {
335            Parameter param = service.getParameter(EndpointDescription.AXIS_SERVICE_PARAMETER);
336            return (param == null) ? null : (EndpointDescription) param.getValue();
337        }
338        
339        public static boolean isSOAP11(AxisService service) {
340            EndpointDescription desc = AxisServiceGenerator.getEndpointDescription(service);
341            return javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING.equals(desc.getBindingType()) ||
342                   javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_MTOM_BINDING.equals(desc.getBindingType());
343        }
344        
345        public static boolean isHTTP(AxisService service) {
346            EndpointDescription desc = AxisServiceGenerator.getEndpointDescription(service);
347            return javax.xml.ws.http.HTTPBinding.HTTP_BINDING.equals(desc.getBindingType());
348        }
349             
350    }