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