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 26package com.sun.tools.internal.ws.processor.generator; 27 28import com.sun.codemodel.internal.*; 29import com.sun.tools.internal.ws.api.TJavaGeneratorExtension; 30import com.sun.tools.internal.ws.processor.model.*; 31import com.sun.tools.internal.ws.processor.model.java.JavaInterface; 32import com.sun.tools.internal.ws.processor.model.java.JavaMethod; 33import com.sun.tools.internal.ws.processor.model.java.JavaParameter; 34import com.sun.tools.internal.ws.processor.model.jaxb.JAXBType; 35import com.sun.tools.internal.ws.processor.model.jaxb.JAXBTypeAndAnnotation; 36import com.sun.tools.internal.ws.wscompile.ErrorReceiver; 37import com.sun.tools.internal.ws.wscompile.Options; 38import com.sun.tools.internal.ws.wscompile.WsimportOptions; 39import com.sun.tools.internal.ws.wsdl.document.soap.SOAPStyle; 40import com.sun.tools.internal.ws.wsdl.document.PortType; 41import com.sun.tools.internal.ws.resources.GeneratorMessages; 42 43import javax.jws.WebMethod; 44import javax.jws.WebParam; 45import javax.jws.WebService; 46import javax.jws.soap.SOAPBinding; 47import javax.xml.bind.annotation.XmlSeeAlso; 48import javax.xml.namespace.QName; 49import javax.xml.ws.Holder; 50import java.util.ArrayList; 51import java.util.List; 52 53import org.xml.sax.Locator; 54 55public class SeiGenerator extends GeneratorBase { 56 private TJavaGeneratorExtension extension; 57 private List<TJavaGeneratorExtension> extensionHandlers; 58 59 public static void generate(Model model, WsimportOptions options, ErrorReceiver receiver, TJavaGeneratorExtension... extensions){ 60 SeiGenerator seiGenerator = new SeiGenerator(); 61 seiGenerator.init(model, options, receiver, extensions); 62 seiGenerator.doGeneration(); 63 } 64 65 public void init(Model model, WsimportOptions options, ErrorReceiver receiver, TJavaGeneratorExtension... extensions) { 66 init(model, options, receiver); 67 extensionHandlers = new ArrayList<TJavaGeneratorExtension>(); 68 69 // register handlers for default extensions 70 71 // 2.2 Spec requires generation of @Action when wsam:Action is explicitly stated in wsdl 72 if (options.target.isLaterThan(Options.Target.V2_2)) { 73 register(new W3CAddressingJavaGeneratorExtension()); 74 } 75 76 for (TJavaGeneratorExtension j : extensions) { 77 register(j); 78 } 79 80 this.extension = new JavaGeneratorExtensionFacade(extensionHandlers.toArray(new TJavaGeneratorExtension[extensionHandlers.size()])); 81 } 82 83 private void write(Port port) { 84 JavaInterface intf = port.getJavaInterface(); 85 String className = Names.customJavaTypeClassName(intf); 86 87 if (donotOverride && GeneratorUtil.classExists(options, className)) { 88 log("Class " + className + " exists. Not overriding."); 89 return; 90 } 91 92 93 JDefinedClass cls; 94 try { 95 cls = getClass(className, ClassType.INTERFACE); 96 } catch (JClassAlreadyExistsException e) { 97 QName portTypeName = 98 (QName) port.getProperty( 99 ModelProperties.PROPERTY_WSDL_PORT_TYPE_NAME); 100 Locator loc = null; 101 if(portTypeName != null){ 102 PortType pt = port.portTypes.get(portTypeName); 103 if (pt!=null) { 104 loc = pt.getLocator(); 105 } 106 } 107 receiver.error(loc, GeneratorMessages.GENERATOR_SEI_CLASS_ALREADY_EXIST(intf.getName(), portTypeName)); 108 return; 109 } 110 // If the class has methods it has already been defined 111 // so skip it. 112 if (!cls.methods().isEmpty()) { 113 return; 114 } 115 116 //write class comment - JAXWS warning 117 JDocComment comment = cls.javadoc(); 118 119 String ptDoc = intf.getJavaDoc(); 120 if(ptDoc != null){ 121 comment.add(ptDoc); 122 comment.add("\n\n"); 123 } 124 125 for(String doc:getJAXWSClassComment()){ 126 comment.add(doc); 127 } 128 129 130 //@WebService 131 JAnnotationUse webServiceAnn = cls.annotate(cm.ref(WebService.class)); 132 writeWebServiceAnnotation(port, webServiceAnn); 133 134 //@HandlerChain 135 writeHandlerConfig(Names.customJavaTypeClassName(port.getJavaInterface()), cls, options); 136 137 //@SOAPBinding 138 writeSOAPBinding(port, cls); 139 140 //@XmlSeeAlso 141 if (options.target.isLaterThan(Options.Target.V2_1)) { 142 writeXmlSeeAlso(cls); 143 } 144 145 for (Operation operation: port.getOperations()) { 146 JavaMethod method = operation.getJavaMethod(); 147 148 //@WebMethod 149 JMethod m; 150 JDocComment methodDoc; 151 String methodJavaDoc = operation.getJavaDoc(); 152 if(method.getReturnType().getName().equals("void")){ 153 m = cls.method(JMod.PUBLIC, void.class, method.getName()); 154 methodDoc = m.javadoc(); 155 }else { 156 JAXBTypeAndAnnotation retType = method.getReturnType().getType(); 157 m = cls.method(JMod.PUBLIC, retType.getType(), method.getName()); 158 retType.annotate(m); 159 methodDoc = m.javadoc(); 160 JCommentPart ret = methodDoc.addReturn(); 161 ret.add("returns "+retType.getName()); 162 } 163 if (methodJavaDoc != null) { 164 methodDoc.add(methodJavaDoc); 165 } 166 167 writeWebMethod(operation, m); 168 JClass holder = cm.ref(Holder.class); 169 for (JavaParameter parameter: method.getParametersList()) { 170 JVar var; 171 JAXBTypeAndAnnotation paramType = parameter.getType().getType(); 172 if (parameter.isHolder()) { 173 var = m.param(holder.narrow(paramType.getType().boxify()), parameter.getName()); 174 }else{ 175 var = m.param(paramType.getType(), parameter.getName()); 176 } 177 178 //annotate parameter with JAXB annotations 179 paramType.annotate(var); 180 methodDoc.addParam(var); 181 JAnnotationUse paramAnn = var.annotate(cm.ref(WebParam.class)); 182 writeWebParam(operation, parameter, paramAnn); 183 } 184 com.sun.tools.internal.ws.wsdl.document.Operation wsdlOp = operation.getWSDLPortTypeOperation(); 185 for(Fault fault:operation.getFaultsSet()){ 186 m._throws(fault.getExceptionClass()); 187 methodDoc.addThrows(fault.getExceptionClass()); 188 wsdlOp.putFault(fault.getWsdlFaultName(), fault.getExceptionClass()); 189 } 190 191 //It should be the last thing to invoke after JMethod is built completely 192 extension.writeMethodAnnotations(wsdlOp, m); 193 } 194 } 195 196 private void writeXmlSeeAlso(JDefinedClass cls) { 197 if (model.getJAXBModel().getS2JJAXBModel() != null) { 198 List<JClass> objectFactories = model.getJAXBModel().getS2JJAXBModel().getAllObjectFactories(); 199 200 //if there are no object facotires, dont generate @XmlSeeAlso 201 if (objectFactories.isEmpty()) { 202 return; 203 } 204 205 JAnnotationUse xmlSeeAlso = cls.annotate(cm.ref(XmlSeeAlso.class)); 206 JAnnotationArrayMember paramArray = xmlSeeAlso.paramArray("value"); 207 for (JClass of : objectFactories) { 208 paramArray = paramArray.param(of); 209 } 210 } 211 212 } 213 214 private void writeWebMethod(Operation operation, JMethod m) { 215 Response response = operation.getResponse(); 216 JAnnotationUse webMethodAnn = m.annotate(cm.ref(WebMethod.class)); 217 String operationName = (operation instanceof AsyncOperation)? 218 ((AsyncOperation)operation).getNormalOperation().getName().getLocalPart(): 219 operation.getName().getLocalPart(); 220 221 if(!m.name().equals(operationName)){ 222 webMethodAnn.param("operationName", operationName); 223 } 224 225 if (operation.getSOAPAction() != null && operation.getSOAPAction().length() > 0){ 226 webMethodAnn.param("action", operation.getSOAPAction()); 227 } 228 229 if (operation.getResponse() == null){ 230 m.annotate(javax.jws.Oneway.class); 231 }else if (!operation.getJavaMethod().getReturnType().getName().equals("void") && 232 operation.getResponse().getParametersList().size() > 0){ 233 Block block; 234 String resultName = null; 235 String nsURI = null; 236 if (operation.getResponse().getBodyBlocks().hasNext()) { 237 block = operation.getResponse().getBodyBlocks().next(); 238 resultName = block.getName().getLocalPart(); 239 if(isDocStyle || block.getLocation() == Block.HEADER){ 240 nsURI = block.getName().getNamespaceURI(); 241 } 242 } 243 244 for (Parameter parameter : operation.getResponse().getParametersList()) { 245 if (parameter.getParameterIndex() == -1) { 246 if(operation.isWrapped()||!isDocStyle){ 247 if(parameter.getBlock().getLocation() == Block.HEADER){ 248 resultName = parameter.getBlock().getName().getLocalPart(); 249 }else{ 250 resultName = parameter.getName(); 251 } 252 if (isDocStyle || (parameter.getBlock().getLocation() == Block.HEADER)) { 253 nsURI = parameter.getType().getName().getNamespaceURI(); 254 } 255 }else if(isDocStyle){ 256 JAXBType t = (JAXBType)parameter.getType(); 257 resultName = t.getName().getLocalPart(); 258 nsURI = t.getName().getNamespaceURI(); 259 } 260 if(!(operation instanceof AsyncOperation)){ 261 JAnnotationUse wr = null; 262 263 if(!resultName.equals("return")){ 264 wr = m.annotate(javax.jws.WebResult.class); 265 wr.param("name", resultName); 266 } 267 if (nsURI != null || (isDocStyle && operation.isWrapped())) { 268 if(wr == null) { 269 wr = m.annotate(javax.jws.WebResult.class); 270 } 271 wr.param("targetNamespace", nsURI); 272 } 273 //doclit wrapped could have additional headers 274 if(!(isDocStyle && operation.isWrapped()) || 275 (parameter.getBlock().getLocation() == Block.HEADER)){ 276 if (wr == null) { 277 wr = m.annotate(javax.jws.WebResult.class); 278 } 279 wr.param("partName", parameter.getName()); 280 } 281 if(parameter.getBlock().getLocation() == Block.HEADER){ 282 if (wr == null) { 283 wr = m.annotate(javax.jws.WebResult.class); 284 } 285 wr.param("header",true); 286 } 287 } 288 } 289 290 } 291 } 292 293 //DOC/BARE 294 if (!sameParamStyle) { 295 if(!operation.isWrapped()) { 296 JAnnotationUse sb = m.annotate(SOAPBinding.class); 297 sb.param("parameterStyle", SOAPBinding.ParameterStyle.BARE); 298 } 299 } 300 301 if (operation.isWrapped() && operation.getStyle().equals(SOAPStyle.DOCUMENT)) { 302 Block reqBlock = operation.getRequest().getBodyBlocks().next(); 303 JAnnotationUse reqW = m.annotate(javax.xml.ws.RequestWrapper.class); 304 reqW.param("localName", reqBlock.getName().getLocalPart()); 305 reqW.param("targetNamespace", reqBlock.getName().getNamespaceURI()); 306 reqW.param("className", reqBlock.getType().getJavaType().getName()); 307 308 if (response != null) { 309 JAnnotationUse resW = m.annotate(javax.xml.ws.ResponseWrapper.class); 310 Block resBlock = response.getBodyBlocks().next(); 311 resW.param("localName", resBlock.getName().getLocalPart()); 312 resW.param("targetNamespace", resBlock.getName().getNamespaceURI()); 313 resW.param("className", resBlock.getType().getJavaType().getName()); 314 } 315 } 316 } 317 318 private boolean isMessageParam(Parameter param, Message message) { 319 Block block = param.getBlock(); 320 321 return (message.getBodyBlockCount() > 0 && block.equals(message.getBodyBlocks().next())) || 322 (message.getHeaderBlockCount() > 0 && 323 block.equals(message.getHeaderBlocks().next())); 324 } 325 326 private boolean isHeaderParam(Parameter param, Message message) { 327 if (message.getHeaderBlockCount() == 0) { 328 return false; 329 } 330 331 for (Block headerBlock : message.getHeaderBlocksMap().values()) { 332 if (param.getBlock().equals(headerBlock)) { 333 return true; 334 } 335 } 336 337 return false; 338 } 339 340 private boolean isAttachmentParam(Parameter param, Message message){ 341 if (message.getAttachmentBlockCount() == 0) { 342 return false; 343 } 344 345 for (Block attBlock : message.getAttachmentBlocksMap().values()) { 346 if (param.getBlock().equals(attBlock)) { 347 return true; 348 } 349 } 350 351 return false; 352 } 353 354 private boolean isUnboundParam(Parameter param, Message message){ 355 if (message.getUnboundBlocksCount() == 0) { 356 return false; 357 } 358 359 for (Block unboundBlock : message.getUnboundBlocksMap().values()) { 360 if (param.getBlock().equals(unboundBlock)) { 361 return true; 362 } 363 } 364 365 return false; 366 } 367 368 private void writeWebParam(Operation operation, JavaParameter javaParameter, JAnnotationUse paramAnno) { 369 Parameter param = javaParameter.getParameter(); 370 Request req = operation.getRequest(); 371 Response res = operation.getResponse(); 372 373 boolean header = isHeaderParam(param, req) || 374 (res != null && isHeaderParam(param, res)); 375 376 String name; 377 boolean isWrapped = operation.isWrapped(); 378 379 if ((param.getBlock().getLocation() == Block.HEADER) || (isDocStyle && !isWrapped)) { 380 name = param.getBlock().getName().getLocalPart(); 381 } else { 382 name = param.getName(); 383 } 384 385 paramAnno.param("name", name); 386 387 String ns= null; 388 389 if (isDocStyle) { 390 ns = param.getBlock().getName().getNamespaceURI(); // its bare nsuri 391 if(isWrapped){ 392 ns = param.getType().getName().getNamespaceURI(); 393 } 394 }else if(header){ 395 ns = param.getBlock().getName().getNamespaceURI(); 396 } 397 398 if (ns != null || (isDocStyle && isWrapped)) { 399 paramAnno.param("targetNamespace", ns); 400 } 401 402 if (header) { 403 paramAnno.param("header", true); 404 } 405 406 if (param.isINOUT()){ 407 paramAnno.param("mode", javax.jws.WebParam.Mode.INOUT); 408 }else if ((res != null) && (isMessageParam(param, res) || isHeaderParam(param, res) || isAttachmentParam(param, res) || 409 isUnboundParam(param,res) || param.isOUT())){ 410 paramAnno.param("mode", javax.jws.WebParam.Mode.OUT); 411 } 412 413 //doclit wrapped could have additional headers 414 if (!(isDocStyle && isWrapped) || header) { 415 paramAnno.param("partName", javaParameter.getParameter().getName()); 416 } 417 } 418 419 private boolean isDocStyle = true; 420 private boolean sameParamStyle = true; 421 private void writeSOAPBinding(Port port, JDefinedClass cls) { 422 JAnnotationUse soapBindingAnn = null; 423 isDocStyle = port.getStyle() == null || port.getStyle().equals(SOAPStyle.DOCUMENT); 424 if(!isDocStyle){ 425 soapBindingAnn = cls.annotate(SOAPBinding.class); 426 soapBindingAnn.param("style", SOAPBinding.Style.RPC); 427 port.setWrapped(true); 428 } 429 if(isDocStyle){ 430 boolean first = true; 431 boolean isWrapper = true; 432 for(Operation operation:port.getOperations()){ 433 if(first){ 434 isWrapper = operation.isWrapped(); 435 first = false; 436 continue; 437 } 438 sameParamStyle = (isWrapper == operation.isWrapped()); 439 if (!sameParamStyle) { 440 break; 441 } 442 } 443 if (sameParamStyle) { 444 port.setWrapped(isWrapper); 445 } 446 } 447 if(sameParamStyle && !port.isWrapped()){ 448 if (soapBindingAnn == null) { 449 soapBindingAnn = cls.annotate(SOAPBinding.class); 450 } 451 soapBindingAnn.param("parameterStyle", SOAPBinding.ParameterStyle.BARE); 452 } 453 } 454 455 private void writeWebServiceAnnotation(Port port, JAnnotationUse wsa) { 456 QName name = (QName) port.getProperty(ModelProperties.PROPERTY_WSDL_PORT_TYPE_NAME); 457 wsa.param("name", name.getLocalPart()); 458 wsa.param("targetNamespace", name.getNamespaceURI()); 459 } 460 461 @Override 462 public void visit(Model model) throws Exception { 463 for(Service s:model.getServices()){ 464 s.accept(this); 465 } 466 } 467 468 @Override 469 public void visit(Service service) throws Exception { 470 String jd = model.getJavaDoc(); 471 if(jd != null){ 472 JPackage pkg = cm._package(options.defaultPackage); 473 pkg.javadoc().add(jd); 474 } 475 476 for(Port p:service.getPorts()){ 477 visitPort(service, p); 478 } 479 } 480 481 private void visitPort(Service service, Port port) { 482 if (port.isProvider()) { 483 return; // Not generating for Provider based endpoint 484 } 485 write(port); 486 } 487 488 private void register(TJavaGeneratorExtension h) { 489 extensionHandlers.add(h); 490 } 491} 492