1 /* 2 * Copyright (c) 1997, 2014, 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.modeler.annotation; 27 28 import com.sun.tools.internal.ws.processor.model.Port; 29 import com.sun.tools.internal.ws.resources.WebserviceapMessages; 30 import com.sun.tools.internal.ws.util.ClassNameInfo; 31 import com.sun.tools.internal.ws.wsdl.document.soap.SOAPStyle; 32 import com.sun.xml.internal.ws.model.RuntimeModeler; 33 34 import javax.jws.Oneway; 35 import javax.jws.WebMethod; 36 import javax.jws.WebParam; 37 import javax.jws.WebResult; 38 import javax.jws.WebService; 39 import javax.jws.soap.SOAPBinding; 40 import javax.jws.soap.SOAPBinding.ParameterStyle; 41 import javax.lang.model.element.Element; 42 import javax.lang.model.element.ElementKind; 43 import javax.lang.model.element.ExecutableElement; 44 import javax.lang.model.element.Modifier; 45 import javax.lang.model.element.Name; 46 import javax.lang.model.element.PackageElement; 47 import javax.lang.model.element.TypeElement; 48 import javax.lang.model.element.VariableElement; 49 import javax.lang.model.type.DeclaredType; 50 import javax.lang.model.type.NoType; 51 import javax.lang.model.type.TypeKind; 52 import javax.lang.model.type.TypeMirror; 53 import javax.lang.model.util.ElementFilter; 54 import javax.lang.model.util.SimpleElementVisitor6; 55 import javax.lang.model.util.SimpleTypeVisitor6; 56 import javax.lang.model.util.Types; 57 import java.lang.annotation.Annotation; 58 import java.util.Collection; 59 import java.util.HashSet; 60 import java.util.List; 61 import java.util.Set; 62 import java.util.Stack; 63 64 /** 65 * @author WS Development Team 66 */ 67 public abstract class WebServiceVisitor extends SimpleElementVisitor6<Void, Object> { 68 69 protected ModelBuilder builder; 70 protected String wsdlNamespace; 71 protected String typeNamespace; 72 protected Stack<SOAPBinding> soapBindingStack; 73 protected SOAPBinding typeElementSoapBinding; 74 protected SOAPStyle soapStyle = SOAPStyle.DOCUMENT; 75 protected boolean wrapped = true; 76 protected Port port; 77 protected Name serviceImplName; 78 protected Name endpointInterfaceName; 79 protected AnnotationProcessorContext context; 80 protected AnnotationProcessorContext.SeiContext seiContext; 81 protected boolean processingSei = false; 82 protected String serviceName; 83 protected Name packageName; 84 protected String portName; 85 protected boolean endpointReferencesInterface = false; 86 protected boolean hasWebMethods = false; 87 protected TypeElement typeElement; 88 protected Set<String> processedMethods; 89 protected boolean pushedSoapBinding = false; 90 91 private static final NoTypeVisitor NO_TYPE_VISITOR = new NoTypeVisitor(); 92 93 public WebServiceVisitor(ModelBuilder builder, AnnotationProcessorContext context) { 94 this.builder = builder; 95 this.context = context; 96 soapBindingStack = new Stack<SOAPBinding>(); 97 processedMethods = new HashSet<String>(); 98 } 99 100 @Override 101 public Void visitType(TypeElement e, Object o) { 102 WebService webService = e.getAnnotation(WebService.class); 103 if (!shouldProcessWebService(webService, e)) 104 return null; 105 if (builder.checkAndSetProcessed(e)) 106 return null; 107 typeElement = e; 108 109 switch (e.getKind()) { 110 case INTERFACE: { 111 if (endpointInterfaceName != null && !endpointInterfaceName.equals(e.getQualifiedName())) { 112 builder.processError(WebserviceapMessages.WEBSERVICEAP_ENDPOINTINTERFACES_DO_NOT_MATCH(endpointInterfaceName, e.getQualifiedName()), e); 113 } 114 verifySeiAnnotations(webService, e); 115 endpointInterfaceName = e.getQualifiedName(); 116 processingSei = true; 117 preProcessWebService(webService, e); 118 processWebService(webService, e); 119 postProcessWebService(webService, e); 120 break; 121 } 122 case CLASS: { 123 typeElementSoapBinding = e.getAnnotation(SOAPBinding.class); 124 if (serviceImplName == null) 125 serviceImplName = e.getQualifiedName(); 126 String endpointInterfaceName = webService != null ? webService.endpointInterface() : null; 127 if (endpointInterfaceName != null && endpointInterfaceName.length() > 0) { 128 checkForInvalidImplAnnotation(e, SOAPBinding.class); 129 if (webService.name().length() > 0) 130 builder.processError(WebserviceapMessages.WEBSERVICEAP_ENDPOINTINTEFACE_PLUS_ELEMENT("name"), e); 131 endpointReferencesInterface = true; 132 verifyImplAnnotations(e); 133 inspectEndpointInterface(endpointInterfaceName, e); 134 serviceImplName = null; 135 return null; 136 } 137 processingSei = false; 138 preProcessWebService(webService, e); 139 processWebService(webService, e); 140 serviceImplName = null; 141 postProcessWebService(webService, e); 142 serviceImplName = null; 143 break; 144 } 145 default: 146 break; 147 } 148 return null; 149 } 150 151 protected void verifySeiAnnotations(WebService webService, TypeElement d) { 152 if (webService.endpointInterface().length() > 0) { 153 builder.processError(WebserviceapMessages.WEBSERVICEAP_ENDPOINTINTERFACE_ON_INTERFACE( 154 d.getQualifiedName(), webService.endpointInterface()), d); 155 } 156 if (webService.serviceName().length() > 0) { 157 builder.processError(WebserviceapMessages.WEBSERVICEAP_INVALID_SEI_ANNOTATION_ELEMENT( 158 "serviceName", d.getQualifiedName()), d); 159 } 160 if (webService.portName().length() > 0) { 161 builder.processError(WebserviceapMessages.WEBSERVICEAP_INVALID_SEI_ANNOTATION_ELEMENT( 162 "portName", d.getQualifiedName()), d); 163 } 164 } 165 166 protected void verifyImplAnnotations(TypeElement d) { 167 for (ExecutableElement method : ElementFilter.methodsIn(d.getEnclosedElements())) { 168 checkForInvalidImplAnnotation(method, WebMethod.class); 169 checkForInvalidImplAnnotation(method, Oneway.class); 170 checkForInvalidImplAnnotation(method, WebResult.class); 171 for (VariableElement param : method.getParameters()) { 172 checkForInvalidImplAnnotation(param, WebParam.class); 173 } 174 } 175 } 176 177 protected void checkForInvalidSeiAnnotation(TypeElement element, Class annotationClass) { 178 Object annotation = element.getAnnotation(annotationClass); 179 if (annotation != null) { 180 builder.processError(WebserviceapMessages.WEBSERVICEAP_INVALID_SEI_ANNOTATION( 181 annotationClass.getName(), element.getQualifiedName()), element); 182 } 183 } 184 185 protected void checkForInvalidImplAnnotation(Element element, Class annotationClass) { 186 Object annotation = element.getAnnotation(annotationClass); 187 if (annotation != null) { 188 builder.processError(WebserviceapMessages.WEBSERVICEAP_ENDPOINTINTEFACE_PLUS_ANNOTATION(annotationClass.getName()), element); 189 } 190 } 191 192 protected void preProcessWebService(WebService webService, TypeElement element) { 193 processedMethods = new HashSet<String>(); 194 seiContext = context.getSeiContext(element); 195 String targetNamespace = null; 196 if (webService != null) 197 targetNamespace = webService.targetNamespace(); 198 PackageElement packageElement = builder.getProcessingEnvironment().getElementUtils().getPackageOf(element); 199 if (targetNamespace == null || targetNamespace.length() == 0) { 200 String packageName = packageElement.getQualifiedName().toString(); 201 if (packageName == null || packageName.length() == 0) { 202 builder.processError(WebserviceapMessages.WEBSERVICEAP_NO_PACKAGE_CLASS_MUST_HAVE_TARGETNAMESPACE( 203 element.getQualifiedName()), element); 204 } 205 targetNamespace = RuntimeModeler.getNamespace(packageName); 206 } 207 seiContext.setNamespaceUri(targetNamespace); 208 if (serviceImplName == null) 209 serviceImplName = seiContext.getSeiImplName(); 210 if (serviceImplName != null) { 211 seiContext.setSeiImplName(serviceImplName); 212 context.addSeiContext(serviceImplName, seiContext); 213 } 214 portName = ClassNameInfo.getName(element.getSimpleName().toString().replace('$', '_')); 215 packageName = packageElement.getQualifiedName(); 216 portName = webService != null && webService.name() != null && webService.name().length() > 0 ? 217 webService.name() : portName; 218 serviceName = ClassNameInfo.getName(element.getQualifiedName().toString()) + WebServiceConstants.SERVICE.getValue(); 219 serviceName = webService != null && webService.serviceName() != null && webService.serviceName().length() > 0 ? 220 webService.serviceName() : serviceName; 221 wsdlNamespace = seiContext.getNamespaceUri(); 222 typeNamespace = wsdlNamespace; 223 224 SOAPBinding soapBinding = element.getAnnotation(SOAPBinding.class); 225 if (soapBinding != null) { 226 pushedSoapBinding = pushSoapBinding(soapBinding, element, element); 227 } else if (element.equals(typeElement)) { 228 pushedSoapBinding = pushSoapBinding(new MySoapBinding(), element, element); 229 } 230 } 231 232 public static boolean sameStyle(SOAPBinding.Style style, SOAPStyle soapStyle) { 233 return style.equals(SOAPBinding.Style.DOCUMENT) 234 && soapStyle.equals(SOAPStyle.DOCUMENT) 235 || style.equals(SOAPBinding.Style.RPC) 236 && soapStyle.equals(SOAPStyle.RPC); 237 } 238 239 protected boolean pushSoapBinding(SOAPBinding soapBinding, Element bindingElement, TypeElement classElement) { 240 boolean changed = false; 241 if (!sameStyle(soapBinding.style(), soapStyle)) { 242 changed = true; 243 if (pushedSoapBinding) 244 builder.processError(WebserviceapMessages.WEBSERVICEAP_MIXED_BINDING_STYLE( 245 classElement.getQualifiedName()), bindingElement); 246 } 247 if (soapBinding.style().equals(SOAPBinding.Style.RPC)) { 248 soapStyle = SOAPStyle.RPC; 249 wrapped = true; 250 if (soapBinding.parameterStyle().equals(ParameterStyle.BARE)) { 251 builder.processError(WebserviceapMessages.WEBSERVICEAP_RPC_LITERAL_MUST_NOT_BE_BARE( 252 classElement.getQualifiedName()), bindingElement); 253 } 254 } else { 255 soapStyle = SOAPStyle.DOCUMENT; 256 if (wrapped != soapBinding.parameterStyle().equals(ParameterStyle.WRAPPED)) { 257 wrapped = soapBinding.parameterStyle().equals(ParameterStyle.WRAPPED); 258 changed = true; 259 } 260 } 261 if (soapBinding.use().equals(SOAPBinding.Use.ENCODED)) { 262 String style = "rpc"; 263 if (soapBinding.style().equals(SOAPBinding.Style.DOCUMENT)) 264 style = "document"; 265 builder.processError(WebserviceapMessages.WEBSERVICE_ENCODED_NOT_SUPPORTED( 266 classElement.getQualifiedName(), style), bindingElement); 267 } 268 if (changed || soapBindingStack.empty()) { 269 soapBindingStack.push(soapBinding); 270 pushedSoapBinding = true; 271 } 272 return changed; 273 } 274 275 protected SOAPBinding popSoapBinding() { 276 if (pushedSoapBinding) 277 soapBindingStack.pop(); 278 SOAPBinding soapBinding = null; 279 if (!soapBindingStack.empty()) { 280 soapBinding = soapBindingStack.peek(); 281 if (soapBinding.style().equals(SOAPBinding.Style.RPC)) { 282 soapStyle = SOAPStyle.RPC; 283 wrapped = true; 284 } else { 285 soapStyle = SOAPStyle.DOCUMENT; 286 wrapped = soapBinding.parameterStyle().equals(ParameterStyle.WRAPPED); 287 } 288 } else { 289 pushedSoapBinding = false; 290 } 291 return soapBinding; 292 } 293 294 protected String getNamespace(PackageElement packageElement) { 295 return RuntimeModeler.getNamespace(packageElement.getQualifiedName().toString()); 296 } 297 298 protected boolean shouldProcessWebService(WebService webService, TypeElement element) { 299 switch (element.getKind()) { 300 case INTERFACE: { 301 hasWebMethods = false; 302 if (webService == null) 303 builder.processError(WebserviceapMessages.WEBSERVICEAP_ENDPOINTINTERFACE_HAS_NO_WEBSERVICE_ANNOTATION( 304 element.getQualifiedName()), element); 305 306 SOAPBinding soapBinding = element.getAnnotation(SOAPBinding.class); 307 if (soapBinding != null 308 && soapBinding.style() == SOAPBinding.Style.RPC 309 && soapBinding.parameterStyle() == SOAPBinding.ParameterStyle.BARE) { 310 builder.processError(WebserviceapMessages.WEBSERVICEAP_INVALID_SOAPBINDING_PARAMETERSTYLE( 311 soapBinding, element), element); 312 return false; 313 } 314 return isLegalSei(element); 315 } 316 case CLASS: { 317 if (webService == null) 318 return false; 319 hasWebMethods = hasWebMethods(element); 320 SOAPBinding soapBinding = element.getAnnotation(SOAPBinding.class); 321 if (soapBinding != null 322 && soapBinding.style() == SOAPBinding.Style.RPC 323 && soapBinding.parameterStyle() == SOAPBinding.ParameterStyle.BARE) { 324 builder.processError(WebserviceapMessages.WEBSERVICEAP_INVALID_SOAPBINDING_PARAMETERSTYLE( 325 soapBinding, element), element); 326 return false; 327 } 328 return isLegalImplementation(webService, element); 329 } 330 default: { 331 throw new IllegalArgumentException("Class or Interface was expecting. But element: " + element); 332 } 333 } 334 } 335 336 abstract protected void processWebService(WebService webService, TypeElement element); 337 338 protected void postProcessWebService(WebService webService, TypeElement element) { 339 processMethods(element); 340 popSoapBinding(); 341 } 342 343 protected boolean hasWebMethods(TypeElement element) { 344 if (element.getQualifiedName().toString().equals(Object.class.getName())) 345 return false; 346 WebMethod webMethod; 347 for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) { 348 webMethod = method.getAnnotation(WebMethod.class); 349 if (webMethod != null) { 350 if (webMethod.exclude()) { 351 if (webMethod.operationName().length() > 0) 352 builder.processError(WebserviceapMessages.WEBSERVICEAP_INVALID_WEBMETHOD_ELEMENT_WITH_EXCLUDE( 353 "operationName", element.getQualifiedName(), method.toString()), method); 354 if (webMethod.action().length() > 0) 355 builder.processError(WebserviceapMessages.WEBSERVICEAP_INVALID_WEBMETHOD_ELEMENT_WITH_EXCLUDE( 356 "action", element.getQualifiedName(), method.toString()), method); 357 } else { 358 return true; 359 } 360 } 361 } 362 return false;//hasWebMethods(d.getSuperclass().getDeclaration()); 363 } 364 365 protected void processMethods(TypeElement element) { 366 switch (element.getKind()) { 367 case INTERFACE: { 368 builder.log("ProcessedMethods Interface: " + element); 369 hasWebMethods = false; 370 for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) { 371 method.accept(this, null); 372 } 373 for (TypeMirror superType : element.getInterfaces()) 374 processMethods((TypeElement) ((DeclaredType) superType).asElement()); 375 break; 376 } 377 case CLASS: { 378 builder.log("ProcessedMethods Class: " + element); 379 hasWebMethods = hasWebMethods(element); 380 if (element.getQualifiedName().toString().equals(Object.class.getName())) 381 return; 382 if (element.getAnnotation(WebService.class) != null) { 383 // Super classes must have @WebService annotations to pick up their methods 384 for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) { 385 method.accept(this, null); 386 } 387 } 388 TypeMirror superclass = element.getSuperclass(); 389 if (!superclass.getKind().equals(TypeKind.NONE)) { 390 processMethods((TypeElement) ((DeclaredType) superclass).asElement()); 391 } 392 break; 393 } 394 default: 395 break; 396 } 397 } 398 399 private TypeElement getEndpointInterfaceElement(String endpointInterfaceName, TypeElement element) { 400 TypeElement intTypeElement = null; 401 for (TypeMirror interfaceType : element.getInterfaces()) { 402 if (endpointInterfaceName.equals(interfaceType.toString())) { 403 intTypeElement = (TypeElement) ((DeclaredType) interfaceType).asElement(); 404 seiContext = context.getSeiContext(intTypeElement.getQualifiedName()); 405 assert (seiContext != null); 406 seiContext.setImplementsSei(true); 407 break; 408 } 409 } 410 if (intTypeElement == null) { 411 intTypeElement = builder.getProcessingEnvironment().getElementUtils().getTypeElement(endpointInterfaceName); 412 } 413 if (intTypeElement == null) 414 builder.processError(WebserviceapMessages.WEBSERVICEAP_ENDPOINTINTERFACE_CLASS_NOT_FOUND(endpointInterfaceName)); 415 return intTypeElement; 416 } 417 418 private void inspectEndpointInterface(String endpointInterfaceName, TypeElement d) { 419 TypeElement intTypeElement = getEndpointInterfaceElement(endpointInterfaceName, d); 420 if (intTypeElement != null) 421 intTypeElement.accept(this, null); 422 } 423 424 @Override 425 public Void visitExecutable(ExecutableElement method, Object o) { 426 // Methods must be public 427 if (!method.getModifiers().contains(Modifier.PUBLIC)) 428 return null; 429 if (processedMethod(method)) 430 return null; 431 WebMethod webMethod = method.getAnnotation(WebMethod.class); 432 if (webMethod != null && webMethod.exclude()) 433 return null; 434 SOAPBinding soapBinding = method.getAnnotation(SOAPBinding.class); 435 if (soapBinding == null && !method.getEnclosingElement().equals(typeElement)) { 436 if (method.getEnclosingElement().getKind().equals(ElementKind.CLASS)) { 437 soapBinding = method.getEnclosingElement().getAnnotation(SOAPBinding.class); 438 if (soapBinding != null) 439 builder.log("using " + method.getEnclosingElement() + "'s SOAPBinding."); 440 else { 441 soapBinding = new MySoapBinding(); 442 } 443 } 444 } 445 boolean newBinding = false; 446 if (soapBinding != null) { 447 newBinding = pushSoapBinding(soapBinding, method, typeElement); 448 } 449 try { 450 if (shouldProcessMethod(method, webMethod)) { 451 processMethod(method, webMethod); 452 } 453 } finally { 454 if (newBinding) { 455 popSoapBinding(); 456 } 457 } 458 return null; 459 } 460 461 protected boolean processedMethod(ExecutableElement method) { 462 String id = method.toString(); 463 if (processedMethods.contains(id)) 464 return true; 465 processedMethods.add(id); 466 return false; 467 } 468 469 protected boolean shouldProcessMethod(ExecutableElement method, WebMethod webMethod) { 470 builder.log("should process method: " + method.getSimpleName() + " hasWebMethods: " + hasWebMethods + " "); 471 /* 472 Fix for https://jax-ws.dev.java.net/issues/show_bug.cgi?id=577 473 if (hasWebMethods && webMethod == null) { 474 builder.log("webMethod == null"); 475 return false; 476 } 477 */ 478 Collection<Modifier> modifiers = method.getModifiers(); 479 boolean staticFinal = modifiers.contains(Modifier.STATIC) || modifiers.contains(Modifier.FINAL); 480 if (staticFinal) { 481 if (webMethod != null) { 482 builder.processError(WebserviceapMessages.WEBSERVICEAP_WEBSERVICE_METHOD_IS_STATIC_OR_FINAL(method.getEnclosingElement(), 483 method), method); 484 } 485 return false; 486 } 487 boolean result = (endpointReferencesInterface || 488 method.getEnclosingElement().equals(typeElement) || 489 (method.getEnclosingElement().getAnnotation(WebService.class) != null)); 490 builder.log("endpointReferencesInterface: " + endpointReferencesInterface); 491 builder.log("declaring class has WebService: " + (method.getEnclosingElement().getAnnotation(WebService.class) != null)); 492 builder.log("returning: " + result); 493 return result; 494 } 495 496 abstract protected void processMethod(ExecutableElement method, WebMethod webMethod); 497 498 protected boolean isLegalImplementation(WebService webService, TypeElement classElement) { 499 boolean isStateful = isStateful(classElement); 500 501 Collection<Modifier> modifiers = classElement.getModifiers(); 502 if (!modifiers.contains(Modifier.PUBLIC)) { 503 builder.processError(WebserviceapMessages.WEBSERVICEAP_WEBSERVICE_CLASS_NOT_PUBLIC(classElement.getQualifiedName()), classElement); 504 return false; 505 } 506 if (modifiers.contains(Modifier.FINAL) && !isStateful) { 507 builder.processError(WebserviceapMessages.WEBSERVICEAP_WEBSERVICE_CLASS_IS_FINAL(classElement.getQualifiedName()), classElement); 508 return false; 509 } 510 if (modifiers.contains(Modifier.ABSTRACT) && !isStateful) { 511 builder.processError(WebserviceapMessages.WEBSERVICEAP_WEBSERVICE_CLASS_IS_ABSTRACT(classElement.getQualifiedName()), classElement); 512 return false; 513 } 514 boolean hasDefaultConstructor = false; 515 for (ExecutableElement constructor : ElementFilter.constructorsIn(classElement.getEnclosedElements())) { 516 if (constructor.getModifiers().contains(Modifier.PUBLIC) && 517 constructor.getParameters().isEmpty()) { 518 hasDefaultConstructor = true; 519 break; 520 } 521 } 522 if (!hasDefaultConstructor && !isStateful) { 523 if (classElement.getEnclosingElement() != null && !modifiers.contains(Modifier.STATIC)) { 524 builder.processError(WebserviceapMessages.WEBSERVICEAP_WEBSERVICE_CLASS_IS_INNERCLASS_NOT_STATIC( 525 classElement.getQualifiedName()), classElement); 526 return false; 527 } 528 529 builder.processError(WebserviceapMessages.WEBSERVICEAP_WEBSERVICE_NO_DEFAULT_CONSTRUCTOR( 530 classElement.getQualifiedName()), classElement); 531 return false; 532 } 533 if (webService.endpointInterface().isEmpty()) { 534 if (!methodsAreLegal(classElement)) 535 return false; 536 } else { 537 TypeElement interfaceElement = getEndpointInterfaceElement(webService.endpointInterface(), classElement); 538 if (!classImplementsSei(classElement, interfaceElement)) 539 return false; 540 } 541 542 return true; 543 } 544 545 private boolean isStateful(TypeElement classElement) { 546 try { 547 // We don't want dependency on rt-ha module as its not integrated in JDK 548 return classElement.getAnnotation((Class<? extends Annotation>) Class.forName("com.sun.xml.internal.ws.developer.Stateful")) != null; 549 } catch (ClassNotFoundException e) { 550 //ignore 551 } 552 return false; 553 } 554 555 protected boolean classImplementsSei(TypeElement classElement, TypeElement interfaceElement) { 556 for (TypeMirror interfaceType : classElement.getInterfaces()) { 557 if (((DeclaredType) interfaceType).asElement().equals(interfaceElement)) 558 return true; 559 } 560 List<ExecutableElement> classMethods = getClassMethods(classElement); 561 boolean implementsMethod; 562 for (ExecutableElement interfaceMethod : ElementFilter.methodsIn(interfaceElement.getEnclosedElements())) { 563 implementsMethod = false; 564 for (ExecutableElement classMethod : classMethods) { 565 if (sameMethod(interfaceMethod, classMethod)) { 566 implementsMethod = true; 567 classMethods.remove(classMethod); 568 break; 569 } 570 } 571 if (!implementsMethod) { 572 builder.processError(WebserviceapMessages.WEBSERVICEAP_METHOD_NOT_IMPLEMENTED(interfaceElement.getSimpleName(), classElement.getSimpleName(), interfaceMethod), interfaceMethod); 573 return false; 574 } 575 } 576 return true; 577 } 578 579 private static List<ExecutableElement> getClassMethods(TypeElement classElement) { 580 if (classElement.getQualifiedName().toString().equals(Object.class.getName())) // we don't need Object's methods 581 return null; 582 TypeElement superclassElement = (TypeElement) ((DeclaredType) classElement.getSuperclass()).asElement(); 583 List<ExecutableElement> superclassesMethods = getClassMethods(superclassElement); 584 List<ExecutableElement> classMethods = ElementFilter.methodsIn(classElement.getEnclosedElements()); 585 if (superclassesMethods == null) 586 return classMethods; 587 else 588 superclassesMethods.addAll(classMethods); 589 return superclassesMethods; 590 } 591 592 protected boolean sameMethod(ExecutableElement method1, ExecutableElement method2) { 593 if (!method1.getSimpleName().equals(method2.getSimpleName())) 594 return false; 595 Types typeUtils = builder.getProcessingEnvironment().getTypeUtils(); 596 if(!typeUtils.isSameType(method1.getReturnType(), method2.getReturnType()) 597 && !typeUtils.isSubtype(method2.getReturnType(), method1.getReturnType())) 598 return false; 599 List<? extends VariableElement> parameters1 = method1.getParameters(); 600 List<? extends VariableElement> parameters2 = method2.getParameters(); 601 if (parameters1.size() != parameters2.size()) 602 return false; 603 for (int i = 0; i < parameters1.size(); i++) { 604 if (!typeUtils.isSameType(parameters1.get(i).asType(), parameters2.get(i).asType())) 605 return false; 606 } 607 return true; 608 } 609 610 protected boolean isLegalSei(TypeElement interfaceElement) { 611 return methodsAreLegal(interfaceElement); 612 } 613 614 protected boolean methodsAreLegal(TypeElement element) { 615 switch (element.getKind()) { 616 case INTERFACE: { 617 hasWebMethods = false; 618 for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) { 619 if (!isLegalMethod(method, element)) 620 return false; 621 } 622 for (TypeMirror superInterface : element.getInterfaces()) { 623 if (!methodsAreLegal((TypeElement) ((DeclaredType) superInterface).asElement())) 624 return false; 625 } 626 return true; 627 } 628 case CLASS: { 629 hasWebMethods = hasWebMethods(element); 630 for (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) { 631 if (!method.getModifiers().contains(Modifier.PUBLIC)) 632 continue; // let's validate only public methods 633 if (!isLegalMethod(method, element)) 634 return false; 635 } 636 DeclaredType superClass = (DeclaredType) element.getSuperclass(); 637 638 TypeElement tE = (TypeElement) superClass.asElement(); 639 return tE.getQualifiedName().toString().equals(Object.class.getName()) 640 || methodsAreLegal(tE); 641 } 642 default: { 643 throw new IllegalArgumentException("Class or interface was expecting. But element: " + element); 644 } 645 } 646 } 647 648 protected boolean isLegalMethod(ExecutableElement method, TypeElement typeElement) { 649 WebMethod webMethod = method.getAnnotation(WebMethod.class); 650 //SEI cannot have methods with @WebMethod(exclude=true) 651 if (typeElement.getKind().equals(ElementKind.INTERFACE) && webMethod != null && webMethod.exclude()) 652 builder.processError(WebserviceapMessages.WEBSERVICEAP_INVALID_SEI_ANNOTATION_ELEMENT_EXCLUDE("exclude=true", typeElement.getQualifiedName(), method.toString()), method); 653 // With https://jax-ws.dev.java.net/issues/show_bug.cgi?id=577, hasWebMethods has no effect 654 if (hasWebMethods && webMethod == null) // backwards compatibility (for legacyWebMethod computation) 655 return true; 656 657 if ((webMethod != null) && webMethod.exclude()) { 658 return true; 659 } 660 /* 661 This check is not needed as Impl class is already checked that it is not abstract. 662 if (typeElement instanceof TypeElement && method.getModifiers().contains(Modifier.ABSTRACT)) { // use Kind.equals instead of instanceOf 663 builder.processError(method.getPosition(), WebserviceapMessages.WEBSERVICEAP_WEBSERVICE_METHOD_IS_ABSTRACT(typeElement.getQualifiedName(), method.getSimpleName())); 664 return false; 665 } 666 */ 667 TypeMirror returnType = method.getReturnType(); 668 if (!isLegalType(returnType)) { 669 builder.processError(WebserviceapMessages.WEBSERVICEAP_METHOD_RETURN_TYPE_CANNOT_IMPLEMENT_REMOTE(typeElement.getQualifiedName(), 670 method.getSimpleName(), 671 returnType), method); 672 } 673 boolean isOneWay = method.getAnnotation(Oneway.class) != null; 674 if (isOneWay && !isValidOneWayMethod(method, typeElement)) 675 return false; 676 677 SOAPBinding soapBinding = method.getAnnotation(SOAPBinding.class); 678 if (soapBinding != null) { 679 if (soapBinding.style().equals(SOAPBinding.Style.RPC)) { 680 builder.processError(WebserviceapMessages.WEBSERVICEAP_RPC_SOAPBINDING_NOT_ALLOWED_ON_METHOD(typeElement.getQualifiedName(), method.toString()), method); 681 } 682 } 683 684 int paramIndex = 0; 685 for (VariableElement parameter : method.getParameters()) { 686 if (!isLegalParameter(parameter, method, typeElement, paramIndex++)) 687 return false; 688 } 689 690 if (!isDocLitWrapped() && soapStyle.equals(SOAPStyle.DOCUMENT)) { 691 VariableElement outParam = getOutParameter(method); 692 int inParams = getModeParameterCount(method, WebParam.Mode.IN); 693 int outParams = getModeParameterCount(method, WebParam.Mode.OUT); 694 if (inParams != 1) { 695 builder.processError(WebserviceapMessages.WEBSERVICEAP_DOC_BARE_AND_NO_ONE_IN(typeElement.getQualifiedName(), method.toString()), method); 696 } 697 if (returnType.accept(NO_TYPE_VISITOR, null)) { 698 if (outParam == null && !isOneWay) { 699 builder.processError(WebserviceapMessages.WEBSERVICEAP_DOC_BARE_NO_OUT(typeElement.getQualifiedName(), method.toString()), method); 700 } 701 if (outParams != 1) { 702 if (!isOneWay && outParams != 0) 703 builder.processError(WebserviceapMessages.WEBSERVICEAP_DOC_BARE_NO_RETURN_AND_NO_OUT(typeElement.getQualifiedName(), method.toString()), method); 704 } 705 } else { 706 if (outParams > 0) { 707 builder.processError(WebserviceapMessages.WEBSERVICEAP_DOC_BARE_RETURN_AND_OUT(typeElement.getQualifiedName(), method.toString()), outParam); 708 } 709 } 710 } 711 return true; 712 } 713 714 protected boolean isLegalParameter(VariableElement param, 715 ExecutableElement method, 716 TypeElement typeElement, 717 int paramIndex) { 718 if (!isLegalType(param.asType())) { 719 builder.processError(WebserviceapMessages.WEBSERVICEAP_METHOD_PARAMETER_TYPES_CANNOT_IMPLEMENT_REMOTE(typeElement.getQualifiedName(), 720 method.getSimpleName(), 721 param.getSimpleName(), 722 param.asType().toString()), param); 723 return false; 724 } 725 TypeMirror holderType; 726 holderType = builder.getHolderValueType(param.asType()); 727 WebParam webParam = param.getAnnotation(WebParam.class); 728 WebParam.Mode mode = null; 729 if (webParam != null) 730 mode = webParam.mode(); 731 732 if (holderType != null) { 733 if (mode != null && mode == WebParam.Mode.IN) 734 builder.processError(WebserviceapMessages.WEBSERVICEAP_HOLDER_PARAMETERS_MUST_NOT_BE_IN_ONLY(typeElement.getQualifiedName(), method.toString(), paramIndex), param); 735 } else if (mode != null && mode != WebParam.Mode.IN) { 736 builder.processError(WebserviceapMessages.WEBSERVICEAP_NON_IN_PARAMETERS_MUST_BE_HOLDER(typeElement.getQualifiedName(), method.toString(), paramIndex), param); 737 } 738 739 return true; 740 } 741 742 protected boolean isDocLitWrapped() { 743 return soapStyle.equals(SOAPStyle.DOCUMENT) && wrapped; 744 } 745 746 private static final class NoTypeVisitor extends SimpleTypeVisitor6<Boolean, Void> { 747 748 @Override 749 public Boolean visitNoType(NoType t, Void o) { 750 return true; 751 } 752 753 @Override 754 protected Boolean defaultAction(TypeMirror e, Void aVoid) { 755 return false; 756 } 757 } 758 759 protected boolean isValidOneWayMethod(ExecutableElement method, TypeElement typeElement) { 760 boolean valid = true; 761 if (!(method.getReturnType().accept(NO_TYPE_VISITOR, null))) { 762 // this is an error, cannot be OneWay and have a return type 763 builder.processError(WebserviceapMessages.WEBSERVICEAP_ONEWAY_OPERATION_CANNOT_HAVE_RETURN_TYPE(typeElement.getQualifiedName(), method.toString()), method); 764 valid = false; 765 } 766 VariableElement outParam = getOutParameter(method); 767 if (outParam != null) { 768 builder.processError(WebserviceapMessages.WEBSERVICEAP_ONEWAY_AND_OUT(typeElement.getQualifiedName(), method.toString()), outParam); 769 valid = false; 770 } 771 if (!isDocLitWrapped() && soapStyle.equals(SOAPStyle.DOCUMENT)) { 772 int inCnt = getModeParameterCount(method, WebParam.Mode.IN); 773 if (inCnt != 1) { 774 builder.processError(WebserviceapMessages.WEBSERVICEAP_ONEWAY_AND_NOT_ONE_IN(typeElement.getQualifiedName(), method.toString()), method); 775 valid = false; 776 } 777 } 778 for (TypeMirror thrownType : method.getThrownTypes()) { 779 TypeElement thrownElement = (TypeElement) ((DeclaredType) thrownType).asElement(); 780 if (builder.isServiceException(thrownType)) { 781 builder.processError(WebserviceapMessages.WEBSERVICEAP_ONEWAY_OPERATION_CANNOT_DECLARE_EXCEPTIONS( 782 typeElement.getQualifiedName(), method.toString(), thrownElement.getQualifiedName()), method); 783 valid = false; 784 } 785 } 786 return valid; 787 } 788 789 protected int getModeParameterCount(ExecutableElement method, WebParam.Mode mode) { 790 WebParam webParam; 791 int cnt = 0; 792 for (VariableElement param : method.getParameters()) { 793 webParam = param.getAnnotation(WebParam.class); 794 if (webParam != null) { 795 if (webParam.header()) 796 continue; 797 if (isEquivalentModes(mode, webParam.mode())) 798 cnt++; 799 } else { 800 if (isEquivalentModes(mode, WebParam.Mode.IN)) { 801 cnt++; 802 } 803 } 804 } 805 return cnt; 806 } 807 808 protected boolean isEquivalentModes(WebParam.Mode mode1, WebParam.Mode mode2) { 809 if (mode1.equals(mode2)) 810 return true; 811 assert mode1 == WebParam.Mode.IN || mode1 == WebParam.Mode.OUT; 812 return (mode1 == WebParam.Mode.IN && mode2 != WebParam.Mode.OUT) || (mode1 == WebParam.Mode.OUT && mode2 != WebParam.Mode.IN); 813 } 814 815 protected boolean isHolder(VariableElement param) { 816 return builder.getHolderValueType(param.asType()) != null; 817 } 818 819 protected boolean isLegalType(TypeMirror type) { 820 if (!(type != null && type.getKind().equals(TypeKind.DECLARED))) 821 return true; 822 TypeElement tE = (TypeElement) ((DeclaredType) type).asElement(); 823 if (tE == null) { 824 // can be null, if this type's declaration is unknown. This may be the result of a processing error, such as a missing class file. 825 builder.processError(WebserviceapMessages.WEBSERVICEAP_COULD_NOT_FIND_TYPEDECL(type.toString(), context.getRound())); 826 } 827 return !builder.isRemote(tE); 828 } 829 830 protected VariableElement getOutParameter(ExecutableElement method) { 831 WebParam webParam; 832 for (VariableElement param : method.getParameters()) { 833 webParam = param.getAnnotation(WebParam.class); 834 if (webParam != null && webParam.mode() != WebParam.Mode.IN) { 835 return param; 836 } 837 } 838 return null; 839 } 840 841 protected static class MySoapBinding implements SOAPBinding { 842 843 @Override 844 public Style style() { 845 return SOAPBinding.Style.DOCUMENT; 846 } 847 848 @Override 849 public Use use() { 850 return SOAPBinding.Use.LITERAL; 851 } 852 853 @Override 854 public ParameterStyle parameterStyle() { 855 return SOAPBinding.ParameterStyle.WRAPPED; 856 } 857 858 @Override 859 public Class<? extends java.lang.annotation.Annotation> annotationType() { 860 return SOAPBinding.class; 861 } 862 } 863 }