Tue, 09 Apr 2013 14:51:13 +0100
8010393: Update JAX-WS RI to 2.2.9-b12941
Reviewed-by: alanb, erikj
Contributed-by: miroslav.kos@oracle.com, martin.grebac@oracle.com
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 */
26 package com.sun.tools.internal.ws.processor.modeler.annotation;
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;
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;
65 /**
66 * @author WS Development Team
67 */
68 public abstract class WebServiceVisitor extends SimpleElementVisitor6<Void, Object> {
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;
92 private static final NoTypeVisitor NO_TYPE_VISITOR = new NoTypeVisitor();
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 }
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;
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 }
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 }
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 }
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 }
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 }
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;
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 }
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 }
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 }
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 }
295 protected String getNamespace(PackageElement packageElement) {
296 return RuntimeModeler.getNamespace(packageElement.getQualifiedName().toString());
297 }
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);
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 }
337 abstract protected void processWebService(WebService webService, TypeElement element);
339 protected void postProcessWebService(WebService webService, TypeElement element) {
340 processMethods(element);
341 popSoapBinding();
342 }
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 }
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 }
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 }
419 private void inspectEndpointInterface(String endpointInterfaceName, TypeElement d) {
420 TypeElement intTypeElement = getEndpointInterfaceElement(endpointInterfaceName, d);
421 if (intTypeElement != null)
422 intTypeElement.accept(this, null);
423 }
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 }
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 }
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 }
497 abstract protected void processMethod(ExecutableElement method, WebMethod webMethod);
499 protected boolean isLegalImplementation(WebService webService, TypeElement classElement) {
500 boolean isStateful = isStateful(classElement);
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 }
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 }
543 return true;
544 }
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 }
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 }
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 }
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 }
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 }
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();
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 }
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;
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;
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 }
691 int paramIndex = 0;
692 for (VariableElement parameter : method.getParameters()) {
693 if (!isLegalParameter(parameter, method, typeElement, paramIndex++))
694 return false;
695 }
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 }
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();
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 }
746 return true;
747 }
749 protected boolean isDocLitWrapped() {
750 return soapStyle.equals(SOAPStyle.DOCUMENT) && wrapped;
751 }
753 private static final class NoTypeVisitor extends SimpleTypeVisitor6<Boolean, Void> {
755 @Override
756 public Boolean visitNoType(NoType t, Void o) {
757 return true;
758 }
760 @Override
761 protected Boolean defaultAction(TypeMirror e, Void aVoid) {
762 return false;
763 }
764 }
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 }
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 }
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 }
822 protected boolean isHolder(VariableElement param) {
823 return builder.getHolderValueType(param.asType()) != null;
824 }
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 }
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 }
848 protected static class MySoapBinding implements SOAPBinding {
850 @Override
851 public Style style() {
852 return SOAPBinding.Style.DOCUMENT;
853 }
855 @Override
856 public Use use() {
857 return SOAPBinding.Use.LITERAL;
858 }
860 @Override
861 public ParameterStyle parameterStyle() {
862 return SOAPBinding.ParameterStyle.WRAPPED;
863 }
865 @Override
866 public Class<? extends java.lang.annotation.Annotation> annotationType() {
867 return SOAPBinding.class;
868 }
869 }
870 }