1 /* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.internal.ws.processor.generator; 27 28 import com.sun.codemodel.internal.ClassType; 29 import com.sun.codemodel.internal.JAnnotationUse; 30 import com.sun.codemodel.internal.JBlock; 31 import com.sun.codemodel.internal.JCatchBlock; 32 import com.sun.codemodel.internal.JClass; 33 import com.sun.codemodel.internal.JClassAlreadyExistsException; 34 import com.sun.codemodel.internal.JCommentPart; 35 import com.sun.codemodel.internal.JConditional; 36 import com.sun.codemodel.internal.JDefinedClass; 37 import com.sun.codemodel.internal.JDocComment; 38 import com.sun.codemodel.internal.JExpr; 39 import com.sun.codemodel.internal.JFieldVar; 40 import com.sun.codemodel.internal.JInvocation; 41 import com.sun.codemodel.internal.JMethod; 42 import com.sun.codemodel.internal.JMod; 43 import com.sun.codemodel.internal.JTryBlock; 44 import com.sun.codemodel.internal.JType; 45 import com.sun.codemodel.internal.JVar; 46 import com.sun.tools.internal.ws.processor.model.Model; 47 import com.sun.tools.internal.ws.processor.model.ModelProperties; 48 import com.sun.tools.internal.ws.processor.model.Port; 49 import com.sun.tools.internal.ws.processor.model.Service; 50 import com.sun.tools.internal.ws.processor.model.java.JavaInterface; 51 import com.sun.tools.internal.ws.resources.GeneratorMessages; 52 import com.sun.tools.internal.ws.wscompile.ErrorReceiver; 53 import com.sun.tools.internal.ws.wscompile.Options; 54 import com.sun.tools.internal.ws.wscompile.WsimportOptions; 55 import com.sun.tools.internal.ws.wsdl.document.PortType; 56 import com.sun.xml.internal.ws.spi.db.BindingHelper; 57 58 import org.xml.sax.Locator; 59 60 import javax.xml.namespace.QName; 61 import javax.xml.ws.WebEndpoint; 62 import javax.xml.ws.WebServiceClient; 63 import javax.xml.ws.WebServiceFeature; 64 import javax.xml.ws.WebServiceException; 65 import java.net.MalformedURLException; 66 import java.net.URL; 67 68 import com.sun.xml.internal.ws.util.ServiceFinder; 69 import java.util.Locale; 70 71 /** 72 * @author WS Development Team 73 * @author Jitendra Kotamraju 74 */ 75 public class ServiceGenerator extends GeneratorBase { 76 77 public static void generate(Model model, WsimportOptions options, ErrorReceiver receiver) { 78 ServiceGenerator serviceGenerator = new ServiceGenerator(model, options, receiver); 79 serviceGenerator.doGeneration(); 80 } 81 82 private ServiceGenerator(Model model, WsimportOptions options, ErrorReceiver receiver) { 83 init(model, options, receiver); 84 } 85 86 @Override 87 public void visit(Service service) { 88 JavaInterface intf = service.getJavaInterface(); 89 String className = Names.customJavaTypeClassName(intf); 90 if (donotOverride && GeneratorUtil.classExists(options, className)) { 91 log("Class " + className + " exists. Not overriding."); 92 return; 93 } 94 95 JDefinedClass cls; 96 try { 97 cls = getClass(className, ClassType.CLASS); 98 } catch (JClassAlreadyExistsException e) { 99 receiver.error(service.getLocator(), GeneratorMessages.GENERATOR_SERVICE_CLASS_ALREADY_EXIST(className, service.getName())); 100 return; 101 } 102 103 cls._extends(javax.xml.ws.Service.class); 104 String serviceFieldName = BindingHelper.mangleNameToClassName(service.getName().getLocalPart()).toUpperCase(Locale.ENGLISH); 105 String wsdlLocationName = serviceFieldName + "_WSDL_LOCATION"; 106 JFieldVar urlField = cls.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, URL.class, wsdlLocationName); 107 108 JFieldVar exField = cls.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, WebServiceException.class, serviceFieldName+"_EXCEPTION"); 109 110 111 String serviceName = serviceFieldName + "_QNAME"; 112 cls.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, QName.class, serviceName, 113 JExpr._new(cm.ref(QName.class)).arg(service.getName().getNamespaceURI()).arg(service.getName().getLocalPart())); 114 115 JClass qNameCls = cm.ref(QName.class); 116 JInvocation inv; 117 inv = JExpr._new(qNameCls); 118 inv.arg("namespace"); 119 inv.arg("localpart"); 120 121 if (options.useBaseResourceAndURLToLoadWSDL) { 122 writeClassLoaderBaseResourceWSDLLocation(className, cls, urlField, exField); 123 } else if (wsdlLocation.startsWith("http://") || wsdlLocation.startsWith("https://") || wsdlLocation.startsWith("file:/")) { 124 writeAbsWSDLLocation(cls, urlField, exField); 125 } else if (wsdlLocation.startsWith("META-INF/")) { 126 writeClassLoaderResourceWSDLLocation(className, cls, urlField, exField); 127 } else { 128 writeResourceWSDLLocation(className, cls, urlField, exField); 129 } 130 131 //write class comment - JAXWS warning 132 JDocComment comment = cls.javadoc(); 133 134 if (service.getJavaDoc() != null) { 135 comment.add(service.getJavaDoc()); 136 comment.add("\n\n"); 137 } 138 139 for (String doc : getJAXWSClassComment()) { 140 comment.add(doc); 141 } 142 143 // Generating constructor 144 // for e.g: public ExampleService() 145 JMethod constructor1 = cls.constructor(JMod.PUBLIC); 146 String constructor1Str = String.format("super(__getWsdlLocation(), %s);", serviceName); 147 constructor1.body().directStatement(constructor1Str); 148 149 // Generating constructor 150 // for e.g: public ExampleService(WebServiceFeature ... features) 151 if (options.target.isLaterThan(Options.Target.V2_2)) { 152 JMethod constructor2 = cls.constructor(JMod.PUBLIC); 153 constructor2.varParam(WebServiceFeature.class, "features"); 154 String constructor2Str = String.format("super(__getWsdlLocation(), %s, features);", serviceName); 155 constructor2.body().directStatement(constructor2Str); 156 } 157 158 // Generating constructor 159 // for e.g: public ExampleService(URL wsdlLocation) 160 if (options.target.isLaterThan(Options.Target.V2_2)) { 161 JMethod constructor3 = cls.constructor(JMod.PUBLIC); 162 constructor3.param(URL.class, "wsdlLocation"); 163 String constructor3Str = String.format("super(wsdlLocation, %s);", serviceName); 164 constructor3.body().directStatement(constructor3Str); 165 } 166 167 // Generating constructor 168 // for e.g: public ExampleService(URL wsdlLocation, WebServiceFeature ... features) 169 if (options.target.isLaterThan(Options.Target.V2_2)) { 170 JMethod constructor4 = cls.constructor(JMod.PUBLIC); 171 constructor4.param(URL.class, "wsdlLocation"); 172 constructor4.varParam(WebServiceFeature.class, "features"); 173 String constructor4Str = String.format("super(wsdlLocation, %s, features);", serviceName); 174 constructor4.body().directStatement(constructor4Str); 175 } 176 177 // Generating constructor 178 // for e.g: public ExampleService(URL wsdlLocation, QName serviceName) 179 JMethod constructor5 = cls.constructor(JMod.PUBLIC); 180 constructor5.param(URL.class, "wsdlLocation"); 181 constructor5.param(QName.class, "serviceName"); 182 constructor5.body().directStatement("super(wsdlLocation, serviceName);"); 183 184 // Generating constructor 185 // for e.g: public ExampleService(URL, QName, WebServiceFeature ...) 186 if (options.target.isLaterThan(Options.Target.V2_2)) { 187 JMethod constructor6 = cls.constructor(JMod.PUBLIC); 188 constructor6.param(URL.class, "wsdlLocation"); 189 constructor6.param(QName.class, "serviceName"); 190 constructor6.varParam(WebServiceFeature.class, "features"); 191 constructor6.body().directStatement("super(wsdlLocation, serviceName, features);"); 192 } 193 194 //@WebService 195 JAnnotationUse webServiceClientAnn = cls.annotate(cm.ref(WebServiceClient.class)); 196 writeWebServiceClientAnnotation(service, webServiceClientAnn); 197 198 // additional annotations 199 for (GeneratorExtension f:ServiceFinder.find(GeneratorExtension.class)) { 200 f.writeWebServiceClientAnnotation(options, cm, cls); 201 } 202 203 204 //@HandlerChain 205 writeHandlerConfig(Names.customJavaTypeClassName(service.getJavaInterface()), cls, options); 206 207 for (Port port : service.getPorts()) { 208 if (port.isProvider()) { 209 continue; // No getXYZPort() for porvider based endpoint 210 } 211 212 //Get the SEI class 213 JType retType; 214 try { 215 retType = getClass(port.getJavaInterface().getName(), ClassType.INTERFACE); 216 } catch (JClassAlreadyExistsException e) { 217 QName portTypeName = 218 (QName) port.getProperty( 219 ModelProperties.PROPERTY_WSDL_PORT_TYPE_NAME); 220 Locator loc = null; 221 if (portTypeName != null) { 222 PortType pt = port.portTypes.get(portTypeName); 223 if (pt != null) { 224 loc = pt.getLocator(); 225 } 226 } 227 receiver.error(loc, GeneratorMessages.GENERATOR_SEI_CLASS_ALREADY_EXIST(port.getJavaInterface().getName(), portTypeName)); 228 return; 229 } 230 231 //write getXyzPort() 232 writeDefaultGetPort(port, retType, cls); 233 234 //write getXyzPort(WebServicesFeature...) 235 if (options.target.isLaterThan(Options.Target.V2_1)) { 236 writeGetPort(port, retType, cls); 237 } 238 } 239 240 writeGetWsdlLocation(cm.ref(URL.class), cls, urlField, exField); 241 } 242 243 private void writeGetPort(Port port, JType retType, JDefinedClass cls) { 244 JMethod m = cls.method(JMod.PUBLIC, retType, port.getPortGetter()); 245 JDocComment methodDoc = m.javadoc(); 246 if (port.getJavaDoc() != null) { 247 methodDoc.add(port.getJavaDoc()); 248 } 249 JCommentPart ret = methodDoc.addReturn(); 250 JCommentPart paramDoc = methodDoc.addParam("features"); 251 paramDoc.append("A list of "); 252 paramDoc.append("{@link " + WebServiceFeature.class.getName() + "}"); 253 paramDoc.append("to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values."); 254 ret.add("returns " + retType.name()); 255 m.varParam(WebServiceFeature.class, "features"); 256 JBlock body = m.body(); 257 StringBuilder statement = new StringBuilder("return "); 258 statement.append("super.getPort(new QName(\"").append(port.getName().getNamespaceURI()).append("\", \"").append(port.getName().getLocalPart()).append("\"), "); 259 statement.append(retType.name()); 260 statement.append(".class, features);"); 261 body.directStatement(statement.toString()); 262 writeWebEndpoint(port, m); 263 } 264 265 266 /* 267 Generates the code to create URL for absolute WSDL location 268 269 for e.g.: 270 static { 271 URL url = null; 272 WebServiceException e = null; 273 try { 274 url = new URL("http://ExampleService.wsdl"); 275 } catch (MalformedURLException ex) { 276 e = new WebServiceException(ex); 277 } 278 EXAMPLESERVICE_WSDL_LOCATION = url; 279 EXAMPLESERVICE_EXCEPTION = e; 280 } 281 */ 282 private void writeAbsWSDLLocation(JDefinedClass cls, JFieldVar urlField, JFieldVar exField) { 283 JBlock staticBlock = cls.init(); 284 JVar urlVar = staticBlock.decl(cm.ref(URL.class), "url", JExpr._null()); 285 JVar exVar = staticBlock.decl(cm.ref(WebServiceException.class), "e", JExpr._null()); 286 287 JTryBlock tryBlock = staticBlock._try(); 288 tryBlock.body().assign(urlVar, JExpr._new(cm.ref(URL.class)).arg(wsdlLocation)); 289 JCatchBlock catchBlock = tryBlock._catch(cm.ref(MalformedURLException.class)); 290 catchBlock.param("ex"); 291 catchBlock.body().assign(exVar, JExpr._new(cm.ref(WebServiceException.class)).arg(JExpr.ref("ex"))); 292 293 staticBlock.assign(urlField, urlVar); 294 staticBlock.assign(exField, exVar); 295 } 296 297 /* 298 Generates the code to create URL for WSDL location as resource 299 300 for e.g.: 301 static { 302 EXAMPLESERVICE_WSDL_LOCATION = ExampleService.class.getResource(...); 303 Exception e = null; 304 if (EXAMPLESERVICE_WSDL_LOCATION == null) { 305 e = new WebServiceException("..."); 306 } 307 EXAMPLESERVICE_EXCEPTION = e; 308 } 309 */ 310 private void writeResourceWSDLLocation(String className, JDefinedClass cls, JFieldVar urlField, JFieldVar exField) { 311 JBlock staticBlock = cls.init(); 312 staticBlock.assign(urlField, JExpr.dotclass(cm.ref(className)).invoke("getResource").arg(wsdlLocation)); 313 JVar exVar = staticBlock.decl(cm.ref(WebServiceException.class), "e", JExpr._null()); 314 JConditional ifBlock = staticBlock._if(urlField.eq(JExpr._null())); 315 ifBlock._then().assign(exVar, JExpr._new(cm.ref(WebServiceException.class)).arg( 316 "Cannot find "+JExpr.quotify('\'', wsdlLocation)+" wsdl. Place the resource correctly in the classpath.")); 317 staticBlock.assign(exField, exVar); 318 } 319 320 /* 321 Generates the code to create URL for WSDL location as classloader resource 322 323 for e.g.: 324 static { 325 EXAMPLESERVICE_WSDL_LOCATION = ExampleService.class.getClassLoader().getResource(...); 326 Exception e = null; 327 if (EXAMPLESERVICE_WSDL_LOCATION == null) { 328 e = new WebServiceException("..."); 329 } 330 EXAMPLESERVICE_EXCEPTION = e; 331 } 332 */ 333 private void writeClassLoaderResourceWSDLLocation(String className, JDefinedClass cls, JFieldVar urlField, JFieldVar exField) { 334 JBlock staticBlock = cls.init(); 335 staticBlock.assign(urlField, JExpr.dotclass(cm.ref(className)).invoke("getClassLoader").invoke("getResource").arg(wsdlLocation)); 336 JVar exVar = staticBlock.decl(cm.ref(WebServiceException.class), "e", JExpr._null()); 337 JConditional ifBlock = staticBlock._if(urlField.eq(JExpr._null())); 338 ifBlock._then().assign(exVar, JExpr._new(cm.ref(WebServiceException.class)).arg( 339 "Cannot find "+JExpr.quotify('\'', wsdlLocation)+" wsdl. Place the resource correctly in the classpath.")); 340 staticBlock.assign(exField, exVar); 341 } 342 343 /* 344 Generates the code to create URL for WSDL location from classloader base resource 345 346 for e.g.: 347 static { 348 Exception e = null; 349 URL url = null; 350 try { 351 url = new URL(ExampleService.class.getClassLoader().getResource("."), ...); 352 } catch (MalformedURLException murl) { 353 e = new WebServiceException(murl); 354 } 355 EXAMPLESERVICE_WSDL_LOCATION = url; 356 EXAMPLESERVICE_EXCEPTION = e; 357 } 358 */ 359 private void writeClassLoaderBaseResourceWSDLLocation(String className, JDefinedClass cls, JFieldVar urlField, JFieldVar exField) { 360 JBlock staticBlock = cls.init(); 361 JVar exVar = staticBlock.decl(cm.ref(WebServiceException.class), "e", JExpr._null()); 362 JVar urlVar = staticBlock.decl(cm.ref(URL.class), "url", JExpr._null()); 363 JTryBlock tryBlock = staticBlock._try(); 364 tryBlock.body().assign(urlVar, JExpr._new(cm.ref(URL.class)).arg(JExpr.dotclass(cm.ref(className)).invoke("getResource").arg(".")).arg(wsdlLocation)); 365 JCatchBlock catchBlock = tryBlock._catch(cm.ref(MalformedURLException.class)); 366 JVar murlVar = catchBlock.param("murl"); 367 catchBlock.body().assign(exVar, JExpr._new(cm.ref(WebServiceException.class)).arg(murlVar)); 368 staticBlock.assign(urlField, urlVar); 369 staticBlock.assign(exField, exVar); 370 } 371 372 /* 373 Generates code that gives wsdl URL. If there is an exception in 374 creating the URL, it throws an exception. 375 376 for example: 377 378 private URL __getWsdlLocation() { 379 if (EXAMPLESERVICE_EXCEPTION != null) { 380 throw EXAMPLESERVICE_EXCEPTION; 381 } 382 return EXAMPLESERVICE_WSDL_LOCATION; 383 } 384 */ 385 private void writeGetWsdlLocation(JType retType, JDefinedClass cls, JFieldVar urlField, JFieldVar exField) { 386 JMethod m = cls.method(JMod.PRIVATE|JMod.STATIC , retType, "__getWsdlLocation"); 387 JConditional ifBlock = m.body()._if(exField.ne(JExpr._null())); 388 ifBlock._then()._throw(exField); 389 m.body()._return(urlField); 390 } 391 392 private void writeDefaultGetPort(Port port, JType retType, JDefinedClass cls) { 393 String portGetter = port.getPortGetter(); 394 JMethod m = cls.method(JMod.PUBLIC, retType, portGetter); 395 JDocComment methodDoc = m.javadoc(); 396 if (port.getJavaDoc() != null) { 397 methodDoc.add(port.getJavaDoc()); 398 } 399 JCommentPart ret = methodDoc.addReturn(); 400 ret.add("returns " + retType.name()); 401 JBlock body = m.body(); 402 StringBuilder statement = new StringBuilder("return "); 403 statement.append("super.getPort(new QName(\"").append(port.getName().getNamespaceURI()).append("\", \"").append(port.getName().getLocalPart()).append("\"), "); 404 statement.append(retType.name()); 405 statement.append(".class);"); 406 body.directStatement(statement.toString()); 407 writeWebEndpoint(port, m); 408 } 409 410 private void writeWebServiceClientAnnotation(Service service, JAnnotationUse wsa) { 411 String serviceName = service.getName().getLocalPart(); 412 String serviceNS = service.getName().getNamespaceURI(); 413 wsa.param("name", serviceName); 414 wsa.param("targetNamespace", serviceNS); 415 wsa.param("wsdlLocation", wsdlLocation); 416 } 417 418 private void writeWebEndpoint(Port port, JMethod m) { 419 JAnnotationUse webEndpointAnn = m.annotate(cm.ref(WebEndpoint.class)); 420 webEndpointAnn.param("name", port.getName().getLocalPart()); 421 } 422 }