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    package org.apache.geronimo.cxf.builder;
018    
019    import java.io.FileNotFoundException;
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.net.URL;
023    import java.util.Collections;
024    import java.util.HashMap;
025    import java.util.Map;
026    import java.util.jar.JarFile;
027    
028    import javax.xml.bind.JAXBContext;
029    import javax.xml.bind.JAXBElement;
030    import javax.xml.bind.JAXBException;
031    import javax.xml.bind.Unmarshaller;
032    import javax.xml.transform.stream.StreamSource;
033    
034    import org.apache.commons.logging.Log;
035    import org.apache.commons.logging.LogFactory;
036    import org.apache.cxf.jaxws.javaee.HandlerChainsType;
037    import org.apache.cxf.jaxws.javaee.PortComponentType;
038    import org.apache.cxf.jaxws.javaee.ServiceImplBeanType;
039    import org.apache.cxf.jaxws.javaee.WebserviceDescriptionType;
040    import org.apache.cxf.jaxws.javaee.WebservicesType;
041    import org.apache.cxf.jaxws.support.JaxWsImplementorInfo;
042    import org.apache.geronimo.common.DeploymentException;
043    import org.apache.geronimo.cxf.pojo.POJOWebServiceContainerFactoryGBean;
044    import org.apache.geronimo.gbean.GBeanData;
045    import org.apache.geronimo.gbean.GBeanInfo;
046    import org.apache.geronimo.gbean.GBeanInfoBuilder;
047    import org.apache.geronimo.j2ee.deployment.Module;
048    import org.apache.geronimo.j2ee.deployment.WebServiceBuilder;
049    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
050    import org.apache.geronimo.jaxws.JAXWSUtils;
051    import org.apache.geronimo.jaxws.PortInfo;
052    import org.apache.geronimo.jaxws.builder.JAXWSServiceBuilder;
053    import org.apache.geronimo.jaxws.builder.WARWebServiceFinder;
054    import org.apache.geronimo.jaxws.builder.WsdlGenerator;
055    import org.apache.geronimo.kernel.repository.Environment;
056    
057    public class CXFBuilder extends JAXWSServiceBuilder {
058        private static final Log LOG = LogFactory.getLog(CXFBuilder.class);
059        
060        /**
061         * This property if enabled will cause the Sun wsgen tool to be used to 
062         * generate the WSDL for servies without WSDL. By default CXF tooling
063         * will be used the generate the WSDL.
064         */
065        private static final String USE_WSGEN_PROPERTY = 
066            "org.apache.geronimo.cxf.use.wsgen";
067    
068        public CXFBuilder() {
069            super(null);
070        }
071    
072        public CXFBuilder(Environment defaultEnvironment) {
073            super(defaultEnvironment);
074            this.webServiceFinder = new WARWebServiceFinder();
075        }
076    
077        protected GBeanInfo getContainerFactoryGBeanInfo() {
078            return POJOWebServiceContainerFactoryGBean.GBEAN_INFO;
079        }
080    
081        protected Map<String, PortInfo> parseWebServiceDescriptor(InputStream in,
082                                                                  URL wsDDUrl,
083                                                                  JarFile moduleFile,
084                                                                  boolean isEJB,
085                                                                  Map correctedPortLocations)
086                throws DeploymentException {
087    
088            LOG.debug("Parsing descriptor " + wsDDUrl);
089    
090            Map<String, PortInfo> map = null;
091    
092            try {
093                JAXBContext ctx = JAXBContext.newInstance(WebservicesType.class);
094                Unmarshaller unmarshaller = ctx.createUnmarshaller();
095                Object obj = unmarshaller.unmarshal(new StreamSource(in), WebservicesType.class);
096    
097                if (obj instanceof JAXBElement) {
098                    obj = ((JAXBElement) obj).getValue();
099                }
100    
101                if (!(obj instanceof WebservicesType)) {
102                    return map;
103                }
104                WebservicesType wst = (WebservicesType) obj;
105    
106                for (WebserviceDescriptionType desc : wst.getWebserviceDescription()) {
107                    String wsdlFile = null;
108                    if (desc.getWsdlFile() != null) {
109                        wsdlFile = getString(desc.getWsdlFile().getValue());
110                    }
111    
112                    String serviceName = desc.getWebserviceDescriptionName().getValue();
113    
114                    for (PortComponentType port : desc.getPortComponent()) {
115    
116                        PortInfo portInfo = new PortInfo();
117    
118                        String serviceLink = null;
119                        ServiceImplBeanType beanType = port.getServiceImplBean();
120                        if (beanType.getEjbLink() != null) {
121                            serviceLink = beanType.getEjbLink().getValue();
122                        } else if (beanType.getServletLink().getValue() != null) {
123                            serviceLink = beanType.getServletLink().getValue();
124                        }
125                        portInfo.setServiceLink(serviceLink);
126    
127                        if (port.getServiceEndpointInterface() != null) {
128                            String sei = port.getServiceEndpointInterface().getValue();
129                            portInfo.setServiceEndpointInterfaceName(sei);
130                        }
131    
132                        String portName = port.getPortComponentName().getValue();
133                        portInfo.setPortName(portName);
134    
135                        portInfo.setProtocolBinding(port.getProtocolBinding());
136                        portInfo.setServiceName(serviceName);
137                        portInfo.setWsdlFile(wsdlFile);
138    
139                        if (port.getEnableMtom() != null) {
140                            portInfo.setEnableMTOM(port.getEnableMtom().isValue());
141                        }
142    
143                        portInfo.setHandlers(HandlerChainsType.class, port.getHandlerChains());
144    
145                        if (port.getWsdlPort() != null) {
146                            portInfo.setWsdlPort(port.getWsdlPort().getValue());
147                        }
148    
149                        if (port.getWsdlService() != null) {
150                            portInfo.setWsdlService(port.getWsdlService().getValue());
151                        }
152    
153                        String location = (String) correctedPortLocations.get(serviceLink);
154                        portInfo.setLocation(location);
155    
156                        if (map == null) {
157                            map = new HashMap<String, PortInfo>();
158                        }
159                        map.put(serviceLink, portInfo);
160                    }
161                }
162    
163                return map;
164            } catch (FileNotFoundException e) {
165                return Collections.emptyMap();
166            } catch (IOException ex) {
167                throw new DeploymentException("Unable to read " + wsDDUrl, ex);
168            } catch (JAXBException ex) {
169                throw new DeploymentException("Unable to parse " + wsDDUrl, ex);
170            } catch (Exception ex) {
171                throw new DeploymentException("Unknown deployment error", ex);
172            } finally {
173                try {
174                    in.close();
175                } catch (IOException e) {
176                    // ignore
177                }
178            }
179        }
180            
181        private static String getString(String in) {
182            if (in != null) {
183                in = in.trim();
184                if (in.length() == 0) {
185                    return null;
186                }
187            }
188            return in;
189        }
190            
191        @Override
192        protected void initialize(GBeanData targetGBean, Class serviceClass, PortInfo portInfo, Module module) 
193            throws DeploymentException {  
194            if (Boolean.getBoolean(USE_WSGEN_PROPERTY)) {
195                generateWSDL(serviceClass, portInfo, module);
196            }
197        }
198        
199        private void generateWSDL(Class serviceClass, PortInfo portInfo, Module module) 
200            throws DeploymentException {
201            if (isWsdlSet(portInfo, serviceClass)) {
202                LOG.debug("Service " + portInfo.getServiceName() + " has WSDL.");
203                return;
204            }        
205            LOG.debug("Service " + portInfo.getServiceName() + " does not have WSDL. Generating WSDL...");
206    
207            WsdlGenerator generator = new WsdlGenerator();
208            generator.setSunSAAJ();
209            
210            JaxWsImplementorInfo serviceInfo = new JaxWsImplementorInfo(serviceClass);
211            
212            // set wsdl service
213            if (portInfo.getWsdlService() == null) {
214                generator.setWsdlService(serviceInfo.getServiceName());
215            } else {
216                generator.setWsdlService(portInfo.getWsdlService());
217            }
218            
219            // set wsdl port
220            if (portInfo.getWsdlPort() != null) {
221                generator.setWsdlPort(portInfo.getWsdlPort());
222            }
223                            
224            String wsdlFile = generator.generateWsdl(module, serviceClass.getName(), module.getEarContext(), portInfo);
225            portInfo.setWsdlFile(wsdlFile);
226            
227            LOG.debug("Generated " + wsdlFile + " for service " + portInfo.getServiceName()); 
228        }   
229        
230        private boolean isWsdlSet(PortInfo portInfo, Class serviceClass) {
231            return (portInfo.getWsdlFile() != null && !portInfo.getWsdlFile().trim().equals(""))
232                    || JAXWSUtils.containsWsdlLocation(serviceClass, serviceClass.getClassLoader());
233        }    
234        
235        public static final GBeanInfo GBEAN_INFO;
236    
237        static {
238            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(CXFBuilder.class, NameFactory.MODULE_BUILDER);
239            infoBuilder.addInterface(WebServiceBuilder.class);
240            infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true);
241    
242            infoBuilder.setConstructor(new String[]{"defaultEnvironment"});
243    
244            GBEAN_INFO = infoBuilder.getBeanInfo();
245        }
246    
247        public static GBeanInfo getGBeanInfo() {
248            return GBEAN_INFO;
249        }
250    
251    }