JwsImplGenerator.java revision 524:dcaa586ab756
1217309Snwhitehorn/* 2217309Snwhitehorn * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3217309Snwhitehorn * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4217309Snwhitehorn * 5217309Snwhitehorn * This code is free software; you can redistribute it and/or modify it 6217309Snwhitehorn * under the terms of the GNU General Public License version 2 only, as 7217309Snwhitehorn * published by the Free Software Foundation. Oracle designates this 8217309Snwhitehorn * particular file as subject to the "Classpath" exception as provided 9217309Snwhitehorn * 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.processor.model.*; 30import com.sun.tools.internal.ws.processor.model.java.JavaInterface; 31import com.sun.tools.internal.ws.processor.model.java.JavaMethod; 32import com.sun.tools.internal.ws.processor.model.java.JavaParameter; 33import com.sun.tools.internal.ws.processor.model.jaxb.JAXBTypeAndAnnotation; 34import com.sun.tools.internal.ws.wsdl.document.Definitions; 35import com.sun.tools.internal.ws.wsdl.document.Binding; 36import com.sun.tools.internal.ws.wsdl.document.soap.SOAP12Binding; 37import com.sun.tools.internal.ws.wsdl.document.soap.SOAPBinding; 38import com.sun.tools.internal.ws.wsdl.document.soap.SOAPConstants; 39import com.sun.tools.internal.ws.api.wsdl.TWSDLExtension; 40import com.sun.tools.internal.ws.wscompile.ErrorReceiver; 41import com.sun.tools.internal.ws.processor.model.ModelProperties; 42import com.sun.tools.internal.ws.wscompile.WsimportOptions; 43import com.sun.codemodel.internal.JClassAlreadyExistsException; 44import com.sun.xml.internal.ws.api.SOAPVersion; 45 46import com.sun.xml.internal.ws.util.ServiceFinder; 47 48import javax.jws.WebService; 49import javax.xml.ws.BindingType; 50import javax.xml.namespace.QName; 51import javax.xml.ws.Holder; 52import java.io.File; 53import java.text.MessageFormat; 54import java.util.ArrayList; 55import java.util.HashMap; 56import java.util.List; 57import java.util.Iterator; 58import java.util.Map; 59 60/** 61 * Generator for placeholder JWS implementations 62 * 63 * @since 2.2.6 64 */ 65public final class JwsImplGenerator extends GeneratorBase { 66 private static final Map<String, String> TRANSLATION_MAP = new HashMap<String, String>( 67 1); 68 static 69 { 70 TRANSLATION_MAP.put(SOAPConstants.URI_SOAP_TRANSPORT_HTTP, 71 javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING); 72 } 73 // save the generated impl files' info 74 private final List<String> implFiles = new ArrayList<String>(); 75 76 public static List<String> generate(Model model, WsimportOptions options, 77 ErrorReceiver receiver) { 78 // options check 79 80 // Generate it according the implDestDir option 81 if (options.implDestDir == null) 82 return null; 83 84 JwsImplGenerator jwsImplGenerator = new JwsImplGenerator(); 85 jwsImplGenerator.init(model, options, receiver); 86 jwsImplGenerator.doGeneration(); 87 // print a warning message while implFiles.size() is zero 88 if (jwsImplGenerator.implFiles.isEmpty()) { 89 StringBuilder msg = new StringBuilder(); 90 if (options.implServiceName != null) 91 msg.append("serviceName=[").append(options.implServiceName).append("] "); 92 if (options.implPortName != null) 93 msg.append("portName=[").append(options.implPortName).append("] "); 94 95 if (msg.length() > 0) 96 msg.append(", Not found in wsdl file.\n"); 97 98 msg.append("No impl files generated!"); 99 receiver.warning(null, msg.toString()); 100 } 101 102 return jwsImplGenerator.implFiles; 103 } 104 105 /** 106 * Move impl files to implDestDir 107 */ 108 public static boolean moveToImplDestDir(List<String> gImplFiles, 109 WsimportOptions options, ErrorReceiver receiver) { 110 if (options.implDestDir == null || gImplFiles == null 111 || gImplFiles.isEmpty()) 112 return true; 113 114 List<ImplFile> generatedImplFiles = ImplFile.toImplFiles(gImplFiles); 115 116 try { 117 File implDestDir = makePackageDir(options); 118 119 File movedF; 120 File f; 121 for (ImplFile implF : generatedImplFiles) { 122 movedF = findFile(options, implF.qualifiedName); 123 if (movedF == null) { 124 // should never happen 125 receiver.warning(null, "Class " + implF.qualifiedName 126 + " is not generated. Not moving."); 127 return false; 128 } 129 130 f = new File(implDestDir, implF.name); 131 if (!movedF.equals(f)) { //bug 10102169 132 133 if (f.exists()) 134 { 135 if (!f.delete()){ 136 receiver.error("Class " + implF.qualifiedName 137 + " has existed in destImplDir, and it " 138 + "can not be written!", null); 139 } 140 } 141 if(!movedF.renameTo(f)) 142 { 143 throw new Exception(); 144 } 145 } 146 } 147 } catch (Exception e) { 148 receiver.error("Moving WebService Impl files failed!", e); 149 return false; 150 } 151 return true; 152 } 153 154 private JwsImplGenerator() { 155 donotOverride = true; 156 } 157 158 @Override 159 public void visit(Service service) { 160 QName serviceName = service.getName(); 161 // process the ordered service only if it is defined 162 if (options.implServiceName != null 163 && !equalsNSOptional(options.implServiceName, serviceName)) 164 return; 165 166 for (Port port : service.getPorts()) { 167 if (port.isProvider()) { 168 continue; // Not generating for Provider based endpoint 169 } 170 171 // Generate the impl class name according to 172 // Xpath(/definitions/service/port[@name]); 173 QName portName = port.getName(); 174 175 // process the ordered port only if it is defined 176 if (options.implPortName != null 177 && !equalsNSOptional(options.implPortName, portName)) 178 continue; 179 180 String simpleClassName = serviceName.getLocalPart() + "_" 181 + portName.getLocalPart() + "Impl"; 182 String className = makePackageQualified(simpleClassName); 183 implFiles.add(className); 184 185 if (donotOverride && GeneratorUtil.classExists(options, className)) { 186 log("Class " + className + " exists. Not overriding."); 187 return; 188 } 189 190 JDefinedClass cls = null; 191 try { 192 cls = getClass(className, ClassType.CLASS); 193 } catch (JClassAlreadyExistsException e) { 194 log("Class " + className 195 + " generates failed. JClassAlreadyExistsException[" + className 196 + "]."); 197 return; 198 } 199 200 // Each serviceImpl will implements one port interface 201 JavaInterface portIntf = port.getJavaInterface(); 202 String portClassName = Names.customJavaTypeClassName(portIntf); 203 JDefinedClass portCls = null; 204 try { 205 portCls = getClass(portClassName, ClassType.INTERFACE); 206 } catch (JClassAlreadyExistsException e) { 207 log("Class " + className 208 + " generates failed. JClassAlreadyExistsException[" 209 + portClassName + "]."); 210 return; 211 } 212 cls._implements(portCls); 213 214 // create a default constructor 215 cls.constructor(JMod.PUBLIC); 216 217 // write class comment - JAXWS warning 218 JDocComment comment = cls.javadoc(); 219 220 if (service.getJavaDoc() != null) { 221 comment.add(service.getJavaDoc()); 222 comment.add("\n\n"); 223 } 224 225 for (String doc : getJAXWSClassComment()) { 226 comment.add(doc); 227 } 228 229 // @WebService 230 JAnnotationUse webServiceAnn = cls.annotate(cm.ref(WebService.class)); 231 writeWebServiceAnnotation(service, port, webServiceAnn); 232 233 // @BindingType 234 JAnnotationUse bindingTypeAnn = cls.annotate(cm.ref(BindingType.class)); 235 writeBindingTypeAnnotation(port, bindingTypeAnn); 236 237 // extra annotation 238 for( GeneratorExtension f : ServiceFinder.find(GeneratorExtension.class) ) { 239 f.writeWebServiceAnnotation(model, cm, cls, port); 240 } 241 242 // WebMethods 243 for (Operation operation : port.getOperations()) { 244 JavaMethod method = operation.getJavaMethod(); 245 246 // @WebMethod 247 JMethod m; 248 JDocComment methodDoc; 249 String methodJavaDoc = operation.getJavaDoc(); 250 if (method.getReturnType().getName().equals("void")) { 251 m = cls.method(JMod.PUBLIC, void.class, method.getName()); 252 methodDoc = m.javadoc(); 253 } else { 254 JAXBTypeAndAnnotation retType = method.getReturnType().getType(); 255 m = cls.method(JMod.PUBLIC, retType.getType(), method.getName()); 256 retType.annotate(m); 257 methodDoc = m.javadoc(); 258 JCommentPart ret = methodDoc.addReturn(); 259 ret.add("returns " + retType.getName()); 260 } 261 262 if (methodJavaDoc != null) 263 methodDoc.add(methodJavaDoc); 264 265 JClass holder = cm.ref(Holder.class); 266 for (JavaParameter parameter : method.getParametersList()) { 267 JVar var; 268 JAXBTypeAndAnnotation paramType = parameter.getType().getType(); 269 if (parameter.isHolder()) { 270 var = m.param(holder.narrow(paramType.getType().boxify()), 271 parameter.getName()); 272 } else { 273 var = m.param(paramType.getType(), parameter.getName()); 274 } 275 methodDoc.addParam(var); 276 } 277 278 com.sun.tools.internal.ws.wsdl.document.Operation wsdlOp = operation 279 .getWSDLPortTypeOperation(); 280 for (Fault fault : operation.getFaultsSet()) { 281 m._throws(fault.getExceptionClass()); 282 methodDoc.addThrows(fault.getExceptionClass()); 283 wsdlOp.putFault(fault.getWsdlFaultName(), fault.getExceptionClass()); 284 } 285 m.body().block().directStatement("//replace with your impl here"); 286 m.body().block().directStatement( 287 getReturnString(method.getReturnType().getName())); 288 } 289 } 290 } 291 292 /** 293 * Generate return statement according to return type. 294 * 295 * @param type 296 * The method's return type 297 * @return The whole return statement 298 */ 299 private String getReturnString(String type) { 300 final String nullReturnStr = "return null;"; 301 // complex type or array 302 if (type.indexOf('.') > -1 || type.indexOf('[') > -1) { 303 return nullReturnStr; 304 } 305 306 // primitive type 307 if (type.equals("void")) { 308 return "return;"; 309 } 310 if (type.equals("boolean")) { 311 return "return false;"; 312 } 313 if (type.equals("int") || type.equals("byte") || type.equals("short") 314 || type.equals("long") || type.equals("double") || type.equals("float")) { 315 return "return 0;"; 316 } 317 if (type.equals("char")) { 318 return "return '0';"; 319 } 320 321 return nullReturnStr; 322 } 323 324 /** 325 * 326 * @param service 327 * @param port 328 * @param webServiceAnn 329 * @param options 330 */ 331 private void writeWebServiceAnnotation(Service service, Port port, 332 JAnnotationUse webServiceAnn) { 333 webServiceAnn.param("portName", port.getName().getLocalPart()); 334 webServiceAnn.param("serviceName", service.getName().getLocalPart()); 335 webServiceAnn.param("targetNamespace", service.getName().getNamespaceURI()); 336 webServiceAnn.param("wsdlLocation", wsdlLocation); 337 webServiceAnn.param("endpointInterface", port.getJavaInterface().getName()); 338 } 339 340 //CR373098 To transform the java class name as validate. 341 private String transToValidJavaIdentifier(String s) { 342 if (s == null) { 343 return null; 344 } 345 final int len = s.length(); 346 StringBuilder retSB = new StringBuilder(); 347 if (len == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) { 348 retSB.append("J"); //update to a default start char 349 } else { 350 retSB.append(s.charAt(0)); 351 } 352 353 for (int i = 1; i < len; i++) { 354 if (!Character.isJavaIdentifierPart(s.charAt(i))) 355 ; //delete it if it is illegal //TODO: It might conflict "a-b" vs. "ab" 356 else { 357 retSB.append(s.charAt(i)); 358 } 359 } 360 return retSB.toString(); 361 } 362 363 private String makePackageQualified(String s) { 364 s = transToValidJavaIdentifier(s); 365 if (options.defaultPackage != null && !options.defaultPackage.equals("")) { 366 return options.defaultPackage + "." + s; 367 } else { 368 return s; 369 } 370 } 371 372 373 /** 374 * TODO 375 * 376 * @param port 377 * @param bindingTypeAnn 378 */ 379 private void writeBindingTypeAnnotation(Port port, 380 JAnnotationUse bindingTypeAnn) { 381 QName bName = (QName) port 382 .getProperty(ModelProperties.PROPERTY_WSDL_BINDING_NAME); 383 if (bName == null) 384 return; 385 386 String v = getBindingType(bName); 387 388 // TODO: How to decide if it is a mtom? 389 if (v != null) { 390 // transport = translate(transport); 391 bindingTypeAnn.param("value", v); 392 } 393 394 } 395 396 private String resolveBindingValue(TWSDLExtension wsdlext) { 397 if (wsdlext.getClass().equals(SOAPBinding.class)) { 398 SOAPBinding sb = (SOAPBinding) wsdlext; 399 if(javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_MTOM_BINDING.equals(sb.getTransport())) 400 return javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_MTOM_BINDING; 401 else { 402 for(GeneratorExtension f : ServiceFinder.find(GeneratorExtension.class) ) { 403 String bindingValue = f.getBindingValue(sb.getTransport(), SOAPVersion.SOAP_11); 404 if(bindingValue!=null) { 405 return bindingValue; 406 } 407 } 408 return javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING; 409 } 410 } 411 if (wsdlext.getClass().equals(SOAP12Binding.class)) { 412 SOAP12Binding sb = (SOAP12Binding) wsdlext; 413 if(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_MTOM_BINDING.equals(sb.getTransport())) 414 return javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_MTOM_BINDING; 415 else { 416 for(GeneratorExtension f : ServiceFinder.find(GeneratorExtension.class) ) { 417 String bindingValue = f.getBindingValue(sb.getTransport(), SOAPVersion.SOAP_12); 418 if(bindingValue!=null) { 419 return bindingValue; 420 } 421 } 422 return javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING; 423 } 424 } 425 return null; 426 } 427 428 private String getBindingType(QName bName) { 429 430 String value = null; 431 // process the bindings in definitions of model.entity 432 if (model.getEntity() instanceof Definitions) { 433 Definitions definitions = (Definitions) model.getEntity(); 434 if (definitions != null) { 435 Iterator bindings = definitions.bindings(); 436 if (bindings != null) { 437 while (bindings.hasNext()) { 438 Binding binding = (Binding) bindings.next(); 439 if (bName.getLocalPart().equals(binding.getName()) 440 && bName.getNamespaceURI().equals(binding.getNamespaceURI())) { 441 List<TWSDLExtension> bindextends = (List<TWSDLExtension>) binding 442 .extensions(); 443 for (TWSDLExtension wsdlext : bindextends) { 444 value = resolveBindingValue(wsdlext); 445 if (value != null) 446 break; 447 } 448 break; 449 } 450 } 451 } 452 } 453 } 454 455 // process the bindings in whole document 456 if (value == null) { 457 if (model.getEntity() instanceof Definitions) { 458 Definitions definitions = (Definitions) model.getEntity(); 459 Binding b = (Binding) definitions.resolveBindings().get(bName); 460 if (b != null) { 461 List<TWSDLExtension> bindextends = (List<TWSDLExtension>) b 462 .extensions(); 463 for (TWSDLExtension wsdlext : bindextends) { 464 value = resolveBindingValue(wsdlext); 465 if (value != null) 466 break; 467 } 468 } 469 } 470 } 471 472 return value; 473 } 474 475 /** 476 * Since the SOAP 1.1 binding transport URI defined in WSDL 1.1 specification 477 * is different with the SOAPBinding URI defined by JAX-WS 2.0 specification. 478 * We must translate the wsdl version into JAX-WS version. If the given 479 * transport URI is NOT one of the predefined transport URIs, it is returned 480 * as is. 481 * 482 * @param transportURI 483 * retrieved from WSDL 484 * @return Standard BindingType URI defined by JAX-WS 2.0 specification. 485 */ 486// private String translate(String transportURI) 487// { 488// String translatedBindingId = TRANSLATION_MAP.get(transportURI); 489// if (translatedBindingId == null) 490// translatedBindingId = transportURI; 491// 492// return translatedBindingId; 493// } 494 495 /***************************************************************************** 496 * Inner classes definition 497 */ 498 static final class ImplFile { 499 public String qualifiedName; // package+"."+simpleClassName + ".java" 500 501 public String name; // simpleClassName + ".java" 502 503 private ImplFile(String qualifiedClassName) { 504 this.qualifiedName = qualifiedClassName + ".java"; 505 506 String simpleClassName = qualifiedClassName; 507 int i = qualifiedClassName.lastIndexOf("."); 508 if (i != -1) 509 simpleClassName = qualifiedClassName.substring(i + 1); 510 511 this.name = simpleClassName + ".java"; 512 } 513 514 public static List<ImplFile> toImplFiles(List<String> qualifiedClassNames) { 515 List<ImplFile> ret = new ArrayList<ImplFile>(); 516 517 for (String qualifiedClassName : qualifiedClassNames) 518 ret.add(new ImplFile(qualifiedClassName)); 519 520 return ret; 521 } 522 } 523 524 /***************************************************************************** 525 * Other utility methods 526 */ 527 528 private static File makePackageDir(WsimportOptions options) { 529 File ret = null; 530 if (options.defaultPackage != null && !options.defaultPackage.equals("")) { 531 String subDir = options.defaultPackage.replace('.', '/'); 532 ret = new File(options.implDestDir, subDir); 533 } else { 534 ret = options.implDestDir; 535 } 536 537 boolean created = ret.mkdirs(); 538 if (options.verbose && !created) { 539 System.out.println(MessageFormat.format("Directory not created: {0}", ret)); 540 } 541 return ret; 542 } 543 544 private static String getQualifiedFileName(String canonicalBaseDir, File f) 545 throws java.io.IOException { 546 String fp = f.getCanonicalPath(); 547 if (fp == null) 548 return null; 549 fp = fp.replace(canonicalBaseDir, ""); 550 fp = fp.replace('\\', '.'); 551 fp = fp.replace('/', '.'); 552 if (fp.startsWith(".")) 553 fp = fp.substring(1); 554 555 return fp; 556 } 557 558 private static File findFile(WsimportOptions options, String qualifiedFileName) 559 throws java.io.IOException { 560 String baseDir = options.sourceDir.getCanonicalPath(); 561 String fp = null; 562 for (File f : options.getGeneratedFiles()) { 563 fp = getQualifiedFileName(baseDir, f); 564 if (qualifiedFileName.equals(fp)) 565 return f; 566 } 567 568 return null; 569 } 570 571 private static boolean equalsNSOptional(String strQName, QName checkQN) { 572 if (strQName == null) 573 return false; 574 strQName = strQName.trim(); 575 QName reqQN = QName.valueOf(strQName); 576 577 if (reqQN.getNamespaceURI() == null || reqQN.getNamespaceURI().equals("")) 578 return reqQN.getLocalPart().equals(checkQN.getLocalPart()); 579 580 return reqQN.equals(checkQN); 581 } 582} 583