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