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.builder; 019 020 import java.io.FileNotFoundException; 021 import java.io.IOException; 022 import java.io.InputStream; 023 import java.io.StringWriter; 024 import java.net.URI; 025 import java.net.URL; 026 import java.util.Collections; 027 import java.util.HashMap; 028 import java.util.Map; 029 import java.util.jar.JarFile; 030 031 import javax.xml.namespace.QName; 032 import javax.xml.ws.http.HTTPBinding; 033 034 import org.apache.commons.logging.Log; 035 import org.apache.commons.logging.LogFactory; 036 import org.apache.geronimo.axis2.client.Axis2ServiceReference; 037 import org.apache.geronimo.axis2.pojo.POJOWebServiceContainerFactoryGBean; 038 import org.apache.geronimo.common.DeploymentException; 039 import org.apache.geronimo.deployment.DeploymentContext; 040 import org.apache.geronimo.gbean.GBeanData; 041 import org.apache.geronimo.gbean.GBeanInfo; 042 import org.apache.geronimo.gbean.GBeanInfoBuilder; 043 import org.apache.geronimo.j2ee.deployment.Module; 044 import org.apache.geronimo.j2ee.deployment.WebModule; 045 import org.apache.geronimo.j2ee.deployment.WebServiceBuilder; 046 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 047 import org.apache.geronimo.jaxws.JAXWSUtils; 048 import org.apache.geronimo.jaxws.PortInfo; 049 import org.apache.geronimo.jaxws.builder.EndpointInfoBuilder; 050 import org.apache.geronimo.jaxws.builder.JAXWSServiceBuilder; 051 import org.apache.geronimo.jaxws.builder.WsdlGenerator; 052 import org.apache.geronimo.jaxws.client.EndpointInfo; 053 import org.apache.geronimo.kernel.repository.Environment; 054 import org.apache.geronimo.xbeans.geronimo.naming.GerServiceRefType; 055 import org.apache.geronimo.xbeans.javaee.PortComponentRefType; 056 import org.apache.geronimo.xbeans.javaee.PortComponentType; 057 import org.apache.geronimo.xbeans.javaee.ServiceImplBeanType; 058 import org.apache.geronimo.xbeans.javaee.ServiceRefHandlerChainsType; 059 import org.apache.geronimo.xbeans.javaee.WebserviceDescriptionType; 060 import org.apache.geronimo.xbeans.javaee.WebservicesDocument; 061 import org.apache.geronimo.xbeans.javaee.WebservicesType; 062 import org.apache.xmlbeans.XmlCursor; 063 import org.apache.xmlbeans.XmlObject; 064 import org.apache.xmlbeans.XmlOptions; 065 066 /** 067 * @version $Rev$ $Date$ 068 */ 069 public class Axis2Builder extends JAXWSServiceBuilder { 070 071 private static final Log log = LogFactory.getLog(Axis2Builder.class); 072 073 public Axis2Builder(Environment defaultEnviroment) { 074 super(defaultEnviroment); 075 } 076 077 public Axis2Builder(){ 078 super(null); 079 } 080 081 protected GBeanInfo getContainerFactoryGBeanInfo() { 082 return POJOWebServiceContainerFactoryGBean.GBEAN_INFO; 083 } 084 085 protected Map<String, PortInfo> parseWebServiceDescriptor(InputStream in, 086 URL wsDDUrl, 087 JarFile moduleFile, 088 boolean isEJB, 089 Map correctedPortLocations) 090 throws DeploymentException { 091 092 log.debug("Parsing descriptor " + wsDDUrl); 093 094 Map<String, PortInfo> map = null; 095 XmlCursor cursor = null; 096 097 try { 098 XmlObject xobj = XmlObject.Factory.parse(in); 099 100 cursor = xobj.newCursor(); 101 cursor.toStartDoc(); 102 cursor.toFirstChild(); 103 //the checking is needed as we also send JAX-RPC based webservices.xml here 104 if ("http://java.sun.com/xml/ns/javaee".equals(cursor.getName().getNamespaceURI())) { 105 WebservicesDocument wd = (WebservicesDocument)xobj.changeType(WebservicesDocument.type); 106 WebservicesType wst = wd.getWebservices(); 107 108 for (WebserviceDescriptionType desc : wst.getWebserviceDescriptionArray()) { 109 String wsdlFile = null; 110 if (desc.getWsdlFile() != null) { 111 wsdlFile = getString(desc.getWsdlFile().getStringValue()); 112 } 113 114 String serviceName = desc.getWebserviceDescriptionName().getStringValue(); 115 116 for (PortComponentType port : desc.getPortComponentArray()) { 117 118 PortInfo portInfo = new PortInfo(); 119 String serviceLink = null; 120 ServiceImplBeanType beanType = port.getServiceImplBean(); 121 if (beanType.getEjbLink() != null) { 122 serviceLink = beanType.getEjbLink().getStringValue(); 123 } else if (beanType.getServletLink().getStringValue() != null) { 124 serviceLink = beanType.getServletLink().getStringValue(); 125 } 126 portInfo.setServiceLink(serviceLink); 127 128 if (port.getServiceEndpointInterface() != null) { 129 String sei = port.getServiceEndpointInterface().getStringValue(); 130 portInfo.setServiceEndpointInterfaceName(sei); 131 } 132 133 String portName = port.getPortComponentName().getStringValue(); 134 portInfo.setPortName(portName); 135 136 portInfo.setProtocolBinding(port.getProtocolBinding()); 137 portInfo.setServiceName(serviceName); 138 portInfo.setWsdlFile(wsdlFile); 139 140 if (port.getEnableMtom() != null) { 141 portInfo.setEnableMTOM(port.getEnableMtom().getBooleanValue()); 142 } 143 144 if (port.getHandlerChains() != null) { 145 StringBuffer chains = new StringBuffer("<handler-chains xmlns=\"http://java.sun.com/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"); 146 chains.append(port.getHandlerChains().xmlText()); 147 chains.append("</handler-chains>"); 148 portInfo.setHandlersAsXML(chains.toString()); 149 } 150 151 if (port.getWsdlPort() != null) { 152 portInfo.setWsdlPort(port.getWsdlPort().getQNameValue()); 153 } 154 155 if (port.getWsdlService() != null) { 156 portInfo.setWsdlService(port.getWsdlService().getQNameValue()); 157 } 158 159 String location = (String) correctedPortLocations.get(serviceLink); 160 portInfo.setLocation(location); 161 162 if (map == null) { 163 map = new HashMap<String, PortInfo>(); 164 } 165 166 map.put(serviceLink, portInfo); 167 } 168 } 169 } else { 170 log.debug("Descriptor ignored (not a Java EE 5 descriptor)"); 171 } 172 173 return map; 174 } catch (FileNotFoundException e) { 175 return Collections.emptyMap(); 176 } catch (IOException ex) { 177 throw new DeploymentException("Unable to read " + wsDDUrl, ex); 178 } catch (Exception ex) { 179 throw new DeploymentException("Unknown deployment error", ex); 180 } finally { 181 try { 182 cursor.dispose(); 183 in.close(); 184 } catch (IOException e) { 185 // ignore 186 } 187 } 188 } 189 190 public boolean configurePOJO(GBeanData targetGBean, 191 String servletName, 192 Module module, 193 String seiClassName, 194 DeploymentContext context) 195 throws DeploymentException { 196 197 boolean status = super.configurePOJO(targetGBean, servletName, module, seiClassName, context); 198 if(!status) { 199 return false; 200 } 201 202 //change the URL 203 Map sharedContext = ((WebModule) module).getSharedContext(); 204 String contextRoot = ((WebModule) module).getContextRoot(); 205 Map portInfoMap = (Map) sharedContext.get(getKey()); 206 PortInfo portInfo; 207 208 if(portInfoMap != null && portInfoMap.get(servletName) != null){ 209 portInfo = (PortInfo) portInfoMap.get(servletName); 210 processURLPattern(contextRoot, portInfo); 211 } 212 213 return status; 214 } 215 216 public Object createService(Class serviceInterface, 217 Class serviceReference, 218 URI wsdlURI, 219 QName serviceQName, 220 Map<Class, PortComponentRefType> portComponentRefMap, 221 ServiceRefHandlerChainsType handlerChains, 222 GerServiceRefType serviceRefType, 223 Module module, 224 ClassLoader cl) throws DeploymentException { 225 EndpointInfoBuilder builder = new EndpointInfoBuilder(serviceInterface, 226 serviceRefType, portComponentRefMap, module.getModuleFile(), 227 wsdlURI, serviceQName); 228 builder.build(); 229 230 wsdlURI = builder.getWsdlURI(); 231 serviceQName = builder.getServiceQName(); 232 Map<Object, EndpointInfo> seiInfoMap = builder.getEndpointInfo(); 233 234 String handlerChainsXML = null; 235 try { 236 handlerChainsXML = getHandlerChainAsString(handlerChains); 237 } catch (IOException e) { 238 // this should not happen 239 log.warn("Failed to serialize handler chains", e); 240 } 241 242 String serviceReferenceName = (serviceReference == null) ? null : serviceReference.getName(); 243 return new Axis2ServiceReference(serviceInterface.getName(), serviceReferenceName, wsdlURI, 244 serviceQName, module.getModuleName(), handlerChainsXML, seiInfoMap); 245 } 246 247 private static String getHandlerChainAsString(ServiceRefHandlerChainsType handlerChains) 248 throws IOException { 249 String xml = null; 250 if (handlerChains != null) { 251 StringWriter w = new StringWriter(); 252 XmlOptions options = new XmlOptions(); 253 options.setSaveSyntheticDocumentElement(new QName("http://java.sun.com/xml/ns/javaee", "handler-chains")); 254 handlerChains.save(w, options); 255 xml = w.toString(); 256 } 257 return xml; 258 } 259 260 private static String getString(String in) { 261 if (in != null) { 262 in = in.trim(); 263 if (in.length() == 0) { 264 return null; 265 } 266 } 267 return in; 268 } 269 270 private void processURLPattern(String contextRoot, PortInfo portInfo) throws DeploymentException { 271 //if the user specifies a url-pattern, set it here. 272 String oldup = portInfo.getLocation(); 273 if (oldup == null || oldup.length() == 0) { 274 //if we cannot grab a valid urlpattern, default it to the port-component-name. 275 oldup = portInfo.getPortName(); 276 } else { 277 int i = oldup.indexOf(contextRoot); 278 oldup = oldup.substring(i + contextRoot.length() + 1); 279 oldup = oldup.trim(); 280 if (oldup.indexOf("*") > 0) { 281 //uncomment this before we fix this issue. workarond by assuming * is at the end. 282 //throw new DeploymentException("Per JSR 109, the url-pattern should not contain an asterisk."); 283 oldup = oldup.substring(0, oldup.length() - 1); 284 } 285 //trim the forward slashes at the beginning or end. 286 if (oldup.substring(0, 1).equalsIgnoreCase("/")) { 287 oldup = oldup.substring(1); 288 } 289 if (oldup.substring(oldup.length()-1).equalsIgnoreCase("/")) { 290 oldup = oldup.substring(0, oldup.length() - 1); 291 } 292 293 } 294 portInfo.setLocation(oldup); 295 } 296 297 @Override 298 protected void initialize(GBeanData targetGBean, Class serviceClass, PortInfo portInfo, Module module) 299 throws DeploymentException { 300 if (isWsdlSet(portInfo, serviceClass)) { 301 log.debug("Service " + portInfo.getServiceName() + " has WSDL."); 302 return; 303 } 304 305 if (isHTTPBinding(portInfo, serviceClass)) { 306 log.debug("Service " + portInfo.getServiceName() + " is HTTPBinding. Only SOAP 1.1 or 1.2 is supported."); 307 return; 308 } 309 310 log.debug("Service " + portInfo.getServiceName() + " does not have WSDL. Generating WSDL..."); 311 312 WsdlGenerator generator = new WsdlGenerator(); 313 generator.setAxis2SAAJ(); 314 315 // set wsdl service 316 if (portInfo.getWsdlService() == null) { 317 generator.setWsdlService(JAXWSUtils.getServiceQName(serviceClass)); 318 } else { 319 generator.setWsdlService(portInfo.getWsdlService()); 320 } 321 322 // set wsdl port 323 if (portInfo.getWsdlPort() != null) { 324 generator.setWsdlPort(portInfo.getWsdlPort()); 325 } 326 327 String wsdlFile = generator.generateWsdl(module, serviceClass.getName(), module.getEarContext(), portInfo); 328 portInfo.setWsdlFile(wsdlFile); 329 330 log.debug("Generated " + wsdlFile + " for service " + portInfo.getServiceName()); 331 } 332 333 private boolean isWsdlSet(PortInfo portInfo, Class serviceClass) { 334 return (portInfo.getWsdlFile() != null && !portInfo.getWsdlFile().trim().equals("")) 335 || JAXWSUtils.containsWsdlLocation(serviceClass, serviceClass.getClassLoader()); 336 } 337 338 private boolean isHTTPBinding(PortInfo portInfo, Class serviceClass) { 339 String bindingURI = ""; 340 String bindingURIFromAnnot; 341 342 if (portInfo.getProtocolBinding() != null) { 343 bindingURI = JAXWSUtils.getBindingURI(portInfo.getProtocolBinding()); 344 } 345 bindingURIFromAnnot = JAXWSUtils.getBindingURIFromAnnot(serviceClass, serviceClass.getClassLoader()); 346 347 if (bindingURI != null && !bindingURI.trim().equals("")) { 348 return bindingURI.equals(HTTPBinding.HTTP_BINDING); 349 } else if (bindingURIFromAnnot != null && !bindingURIFromAnnot.trim().equals("")) { 350 return bindingURIFromAnnot.equals(HTTPBinding.HTTP_BINDING); 351 } 352 353 return false; 354 } 355 356 public static final GBeanInfo GBEAN_INFO; 357 358 static { 359 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(Axis2Builder.class, NameFactory.MODULE_BUILDER); 360 infoBuilder.addInterface(WebServiceBuilder.class); 361 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true); 362 infoBuilder.setConstructor(new String[]{"defaultEnvironment"}); 363 GBEAN_INFO = infoBuilder.getBeanInfo(); 364 } 365 366 public static GBeanInfo getGBeanInfo() { 367 return GBEAN_INFO; 368 } 369 }