blob: 6c78b15bdff0f4c470f5ba63662466fe5f1794d7 [file] [log] [blame]
/*
* Portions Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.tools.internal.ws.processor.modeler.annotation;
import com.sun.mirror.declaration.ClassDeclaration;
import com.sun.mirror.declaration.ConstructorDeclaration;
import com.sun.mirror.declaration.Declaration;
import com.sun.mirror.declaration.FieldDeclaration;
import com.sun.mirror.declaration.InterfaceDeclaration;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.declaration.Modifier;
import com.sun.mirror.declaration.PackageDeclaration;
import com.sun.mirror.declaration.ParameterDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.type.ClassType;
import com.sun.mirror.type.DeclaredType;
import com.sun.mirror.type.InterfaceType;
import com.sun.mirror.type.ReferenceType;
import com.sun.mirror.type.TypeMirror;
import com.sun.mirror.type.VoidType;
import com.sun.mirror.util.DeclarationVisitor;
import com.sun.mirror.util.SimpleDeclarationVisitor;
import com.sun.mirror.util.SourcePosition;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.StringTokenizer;
import com.sun.xml.internal.ws.modeler.RuntimeModeler;
import com.sun.tools.internal.ws.processor.model.Parameter;
import com.sun.tools.internal.ws.processor.model.Port;
import com.sun.tools.internal.ws.processor.model.Service;
import com.sun.tools.internal.ws.processor.model.java.JavaInterface;
import com.sun.tools.internal.ws.processor.model.java.JavaSimpleType;
import com.sun.tools.internal.ws.processor.model.java.JavaType;
import com.sun.tools.internal.ws.processor.modeler.JavaSimpleTypeCreator;
import com.sun.tools.internal.ws.processor.modeler.annotation.AnnotationProcessorContext.SEIContext;
import com.sun.tools.internal.ws.util.ClassNameInfo;
import com.sun.tools.internal.ws.wsdl.document.soap.SOAPStyle;
import com.sun.tools.internal.ws.wsdl.document.soap.SOAPUse;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import javax.jws.HandlerChain;
import javax.jws.Oneway;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.ParameterStyle;
import javax.xml.namespace.QName;
import com.sun.tools.internal.xjc.api.Reference;
import com.sun.tools.internal.ws.processor.modeler.annotation.AnnotationProcessorContext;
import com.sun.tools.internal.ws.processor.modeler.annotation.ModelBuilder;
import com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceConstants;
/**
*
* @author WS Development Team
*/
public abstract class WebServiceVisitor extends SimpleDeclarationVisitor implements WebServiceConstants {
protected ModelBuilder builder;
protected String wsdlNamespace;
protected String typeNamespace;
protected Stack<SOAPBinding> soapBindingStack;
protected SOAPBinding typeDeclSOAPBinding;
protected SOAPUse soapUse = SOAPUse.LITERAL;
protected SOAPStyle soapStyle = SOAPStyle.DOCUMENT;
protected boolean wrapped = true;
protected HandlerChain hChain;
protected Port port;
protected String serviceImplName;
protected String endpointInterfaceName;
protected AnnotationProcessorContext context;
protected SEIContext seiContext;
protected boolean processingSEI = false;
protected String serviceName;
protected String packageName;
protected String portName;
protected boolean endpointReferencesInterface = false;
protected boolean hasWebMethods = false;
protected JavaSimpleTypeCreator simpleTypeCreator;
protected TypeDeclaration typeDecl;
protected Set<String> processedMethods;
protected boolean pushedSOAPBinding = false;
protected static final String ANNOTATION_ELEMENT_ERROR = "webserviceap.endpointinteface.plus.element";
public WebServiceVisitor(ModelBuilder builder, AnnotationProcessorContext context) {
this.builder = builder;
this.context = context;
this.simpleTypeCreator = new JavaSimpleTypeCreator();
soapBindingStack = new Stack<SOAPBinding>();
processedMethods = new HashSet<String>();
}
public void visitInterfaceDeclaration(InterfaceDeclaration d) {
WebService webService = (WebService)d.getAnnotation(WebService.class);
if (!shouldProcessWebService(webService, d))
return;
if (builder.checkAndSetProcessed(d))
return;
typeDecl = d;
if (endpointInterfaceName != null && !endpointInterfaceName.equals(d.getQualifiedName())) {
builder.onError(d.getPosition(), "webserviceap.endpointinterfaces.do.not.match", new Object[]
{endpointInterfaceName, d.getQualifiedName()});
}
verifySEIAnnotations(webService, d);
endpointInterfaceName = d.getQualifiedName();
processingSEI = true;
preProcessWebService(webService, d);
processWebService(webService, d);
postProcessWebService(webService, d);
}
public void visitClassDeclaration(ClassDeclaration d) {
WebService webService = d.getAnnotation(WebService.class);
if (!shouldProcessWebService(webService, d))
return;
if (builder.checkAndSetProcessed(d))
return;
typeDeclSOAPBinding = d.getAnnotation(SOAPBinding.class);
typeDecl = d;
if (serviceImplName == null)
serviceImplName = d.getQualifiedName();
String endpointInterfaceName = webService != null ? webService.endpointInterface() : null;
if (endpointInterfaceName != null && endpointInterfaceName.length() > 0) {
SourcePosition pos = pos = d.getPosition();
checkForInvalidImplAnnotation(d, SOAPBinding.class);
if (webService.name().length() > 0)
annotationError(pos, ANNOTATION_ELEMENT_ERROR,"name");
endpointReferencesInterface = true;
verifyImplAnnotations(d);
inspectEndpointInterface(endpointInterfaceName, d);
serviceImplName = null;
return;
}
processingSEI = false;
preProcessWebService(webService, d);
processWebService(webService, d);
serviceImplName = null;
postProcessWebService(webService, d);
serviceImplName = null;
}
protected void verifySEIAnnotations(WebService webService, InterfaceDeclaration d) {
if (webService.endpointInterface().length() > 0) {
builder.onError(d.getPosition(), "webservicefactory.endpointinterface.on.interface",
new Object[] {d.getQualifiedName(), webService.endpointInterface()});
}
if (webService.serviceName().length() > 0) {
builder.onError(d.getPosition(), "webserviceap.invalid.sei.annotation.element",
new Object[] {"serviceName", d.getQualifiedName()});
}
if (webService.portName().length() > 0) {
builder.onError(d.getPosition(), "webserviceap.invalid.sei.annotation.element",
new Object[] {"portName", d.getQualifiedName()});
}
}
protected void verifyImplAnnotations(ClassDeclaration d) {
for (MethodDeclaration method : d.getMethods()) {
checkForInvalidImplAnnotation(method, WebMethod.class);
checkForInvalidImplAnnotation(method, Oneway.class);
checkForInvalidImplAnnotation(method, WebResult.class);
for (ParameterDeclaration param : method.getParameters()) {
checkForInvalidImplAnnotation(param, WebParam.class);
}
}
}
protected void checkForInvalidSEIAnnotation(InterfaceDeclaration d, Class annotationClass) {
Object annotation = d.getAnnotation(annotationClass);
if (annotation != null) {
SourcePosition pos = d.getPosition();
annotationError(pos, "webserviceap.invalid.sei.annotation",
new Object[] {annotationClass.getName(), d.getQualifiedName()});
}
}
protected void checkForInvalidImplAnnotation(Declaration d, Class annotationClass) {
Object annotation = d.getAnnotation(annotationClass);
if (annotation != null) {
SourcePosition pos = d.getPosition();
annotationError(pos, "webserviceap.endpointinteface.plus.annotation",
annotationClass.getName());
}
}
protected void annotationError(SourcePosition pos, String key, String element) {
annotationError(pos, key, new Object[] {element});
}
protected void annotationError(SourcePosition pos, String key, Object[] args) {
builder.onError(pos, key, args);
}
protected void preProcessWebService(WebService webService, TypeDeclaration d) {
seiContext = context.getSEIContext(d);
String targetNamespace = null;
if (webService != null)
targetNamespace = webService.targetNamespace();
if (targetNamespace == null || targetNamespace.length() == 0) {
String packageName = d.getPackage().getQualifiedName();
if (packageName == null || packageName.length() == 0) {
builder.onError(d.getPosition(), "webserviceap.no.package.class.must.have.targetnamespace",
new Object[] {d.getQualifiedName()});
}
targetNamespace = getNamespace(d.getPackage());
}
seiContext.setNamespaceURI(targetNamespace);
if (serviceImplName == null)
serviceImplName = seiContext.getSEIImplName();
if (serviceImplName != null) {
seiContext.setSEIImplName(serviceImplName);
context.addSEIContext(serviceImplName, seiContext);
}
portName = ClassNameInfo.getName(
d.getSimpleName().replace(
SIGC_INNERCLASS,
SIGC_UNDERSCORE));;
packageName = d.getPackage().getQualifiedName();
portName = webService != null && webService.name() != null && webService.name().length() >0 ?
webService.name() : portName;
serviceName = ClassNameInfo.getName(d.getQualifiedName())+SERVICE;
serviceName = webService != null && webService.serviceName() != null &&
webService.serviceName().length() > 0 ?
webService.serviceName() : serviceName;
wsdlNamespace = seiContext.getNamespaceURI();
typeNamespace = wsdlNamespace;
SOAPBinding soapBinding = d.getAnnotation(SOAPBinding.class);
if (soapBinding != null) {
pushedSOAPBinding = pushSOAPBinding(soapBinding, d, d);
} else if (d.equals(typeDecl)) {
pushedSOAPBinding = pushSOAPBinding(new MySOAPBinding(), d, d);
}
}
public static boolean sameStyle(SOAPBinding.Style style, SOAPStyle soapStyle) {
if (style.equals(SOAPBinding.Style.DOCUMENT) &&
soapStyle.equals(SOAPStyle.DOCUMENT))
return true;
if (style.equals(SOAPBinding.Style.RPC) &&
soapStyle.equals(SOAPStyle.RPC))
return true;
return false;
}
protected boolean pushSOAPBinding(SOAPBinding soapBinding, Declaration bindingDecl,
TypeDeclaration classDecl) {
boolean changed = false;
if (!sameStyle(soapBinding.style(), soapStyle)) {
changed = true;
if (pushedSOAPBinding)
builder.onError(bindingDecl.getPosition(), "webserviceap.mixed.binding.style",
new Object[] {classDecl.getQualifiedName()});
}
if (soapBinding.style().equals(SOAPBinding.Style.RPC)) {
soapStyle = SOAPStyle.RPC;
wrapped = true;
if (soapBinding.parameterStyle().equals(ParameterStyle.BARE)) {
builder.onError(bindingDecl.getPosition(), "webserviceap.rpc.literal.must.not.be.bare",
new Object[] {classDecl.getQualifiedName()});
}
} else {
soapStyle = SOAPStyle.DOCUMENT;
if (wrapped != soapBinding.parameterStyle().equals(ParameterStyle.WRAPPED)) {
wrapped = soapBinding.parameterStyle().equals(ParameterStyle.WRAPPED);
changed = true;
}
}
if (soapBinding.use().equals(SOAPBinding.Use.ENCODED)) {
builder.onError(bindingDecl.getPosition(), "webserviceap.rpc.encoded.not.supported",
new Object[] {classDecl.getQualifiedName()});
}
if (changed || soapBindingStack.empty()) {
soapBindingStack.push(soapBinding);
pushedSOAPBinding = true;
}
return changed;
}
protected SOAPBinding popSOAPBinding() {
if (pushedSOAPBinding)
soapBindingStack.pop();
SOAPBinding soapBinding = null;
if (!soapBindingStack.empty()) {
soapBinding = soapBindingStack.peek();
if (soapBinding.style().equals(SOAPBinding.Style.RPC)) {
soapStyle = SOAPStyle.RPC;
wrapped = true;
} else {
soapStyle = SOAPStyle.DOCUMENT;
wrapped = soapBinding.parameterStyle().equals(ParameterStyle.WRAPPED);
}
}
return soapBinding;
}
protected String getNamespace(PackageDeclaration packageDecl) {
return RuntimeModeler.getNamespace(packageDecl.getQualifiedName());
}
// abstract protected boolean shouldProcessWebService(WebService webService, InterfaceDeclaration intf);
// abstract protected boolean shouldProcessWebService(WebService webService, ClassDeclaration decl);
protected boolean shouldProcessWebService(WebService webService, InterfaceDeclaration intf) {
hasWebMethods = false;
if (webService == null)
builder.onError(intf.getPosition(), "webserviceap.endpointinterface.has.no.webservice.annotation",
new Object[] {intf.getQualifiedName()});
if (isLegalSEI(intf))
return true;
return false;
}
protected boolean shouldProcessWebService(WebService webService, ClassDeclaration classDecl) {
if (webService == null)
return false;
hasWebMethods = hasWebMethods(classDecl);
return isLegalImplementation(webService, classDecl);
}
abstract protected void processWebService(WebService webService, TypeDeclaration d);
protected void postProcessWebService(WebService webService, InterfaceDeclaration d) {
processMethods(d);
popSOAPBinding();
}
protected void postProcessWebService(WebService webService, ClassDeclaration d) {
processMethods(d);
popSOAPBinding();
}
protected boolean hasWebMethods(ClassDeclaration d) {
if (d.getQualifiedName().equals(JAVA_LANG_OBJECT))
return false;
WebMethod webMethod;
for (MethodDeclaration method : d.getMethods()) {
webMethod = method.getAnnotation(WebMethod.class);
if (webMethod != null) {
if (webMethod.exclude()) {
if (webMethod.operationName().length() > 0)
builder.onError(method.getPosition(), "webserviceap.invalid.webmethod.element.with.exclude",
new Object[] {"operationName", d.getQualifiedName(), method.toString()});
if (webMethod.action().length() > 0)
builder.onError(method.getPosition(), "webserviceap.invalid.webmethod.element.with.exclude",
new Object[] {"action", d.getQualifiedName(), method.toString()});
} else {
return true;
}
}
}
return false;//hasWebMethods(d.getSuperclass().getDeclaration());
}
protected void processMethods(InterfaceDeclaration d) {
builder.log("ProcessedMethods Interface: "+d);
hasWebMethods = false;
for (MethodDeclaration methodDecl : d.getMethods()) {
methodDecl.accept((DeclarationVisitor)this);
}
for (InterfaceType superType : d.getSuperinterfaces())
processMethods(superType.getDeclaration());
}
protected void processMethods(ClassDeclaration d) {
builder.log("ProcessedMethods Class: "+d);
hasWebMethods = hasWebMethods(d);
if (d.getQualifiedName().equals(JAVA_LANG_OBJECT))
return;
if (d.getAnnotation(WebService.class) != null) {
// Super classes must have @WebService annotations to pick up their methods
for (MethodDeclaration methodDecl : d.getMethods()) {
methodDecl.accept((DeclarationVisitor)this);
}
}
if (d.getSuperclass() != null) {
processMethods(d.getSuperclass().getDeclaration());
}
}
private InterfaceDeclaration getEndpointInterfaceDecl(String endpointInterfaceName,
ClassDeclaration d) {
InterfaceDeclaration intTypeDecl = null;
for (InterfaceType interfaceType : d.getSuperinterfaces()) {
if (endpointInterfaceName.equals(interfaceType.toString())) {
intTypeDecl = interfaceType.getDeclaration();
seiContext = context.getSEIContext(intTypeDecl.getQualifiedName());
assert(seiContext != null);
seiContext.setImplementsSEI(true);
break;
}
}
if (intTypeDecl == null) {
intTypeDecl = (InterfaceDeclaration)builder.getTypeDeclaration(endpointInterfaceName);
}
if (intTypeDecl == null)
builder.onError("webserviceap.endpointinterface.class.not.found",
new Object[] {endpointInterfaceName});
return intTypeDecl;
}
private void inspectEndpointInterface(String endpointInterfaceName, ClassDeclaration d) {
TypeDeclaration intTypeDecl = getEndpointInterfaceDecl(endpointInterfaceName, d);
if (intTypeDecl != null)
intTypeDecl.accept((DeclarationVisitor)this);
}
public void visitMethodDeclaration(MethodDeclaration method) {
// Methods must be public
if (!method.getModifiers().contains(Modifier.PUBLIC))
return;
if (processedMethod(method))
return;
WebMethod webMethod = method.getAnnotation(WebMethod.class);
if (webMethod != null && webMethod.exclude())
return;
SOAPBinding soapBinding = method.getAnnotation(SOAPBinding.class);
if (soapBinding == null && !method.getDeclaringType().equals(typeDecl)) {
if (method.getDeclaringType() instanceof ClassDeclaration) {
soapBinding = method.getDeclaringType().getAnnotation(SOAPBinding.class);
if (soapBinding != null)
builder.log("using "+method.getDeclaringType()+"'s SOAPBinding.");
else {
soapBinding = new MySOAPBinding();
}
}
}
boolean newBinding = false;
if (soapBinding != null) {
newBinding = pushSOAPBinding(soapBinding, method, typeDecl);
}
try {
if (shouldProcessMethod(method, webMethod)) {
processMethod(method, webMethod);
}
} finally {
if (newBinding) {
popSOAPBinding();
}
}
}
protected boolean processedMethod(MethodDeclaration method) {
String id = method.toString();
if (processedMethods.contains(id))
return true;
processedMethods.add(id);
return false;
}
protected boolean shouldProcessMethod(MethodDeclaration method, WebMethod webMethod) {
builder.log("should process method: "+method.getSimpleName()+" hasWebMethods: "+ hasWebMethods+" ");
if (hasWebMethods && webMethod == null) {
builder.log("webMethod == null");
return false;
}
boolean retval = (endpointReferencesInterface ||
method.getDeclaringType().equals(typeDecl) ||
(method.getDeclaringType().getAnnotation(WebService.class) != null));
builder.log("endpointReferencesInterface: "+endpointReferencesInterface);
builder.log("declaring class has WebSevice: "+(method.getDeclaringType().getAnnotation(WebService.class) != null));
builder.log("returning: "+retval);
return retval;
}
abstract protected void processMethod(MethodDeclaration method, WebMethod webMethod);
protected boolean isLegalImplementation(WebService webService, ClassDeclaration classDecl) {
Collection<Modifier> modifiers = classDecl.getModifiers();
if (!modifiers.contains(Modifier.PUBLIC)){
builder.onError(classDecl.getPosition(), "webserviceap.webservice.class.not.public",
new Object[] {classDecl.getQualifiedName()});
return false;
}
if (modifiers.contains(Modifier.FINAL)) {
builder.onError(classDecl.getPosition(), "webserviceap.webservice.class.is.final",
new Object[] {classDecl.getQualifiedName()});
return false;
}
if (modifiers.contains(Modifier.ABSTRACT)) {
builder.onError(classDecl.getPosition(), "webserviceap.webservice.class.is.abstract",
new Object[] {classDecl.getQualifiedName()});
return false;
}
if (classDecl.getDeclaringType() != null && !modifiers.contains(Modifier.STATIC)) {
builder.onError(classDecl.getPosition(), "webserviceap.webservice.class.is.innerclass.not.static",
new Object[] {classDecl.getQualifiedName()});
return false;
}
boolean hasDefaultConstructor = false;
for (ConstructorDeclaration constructor : classDecl.getConstructors()) {
if (constructor.getModifiers().contains(Modifier.PUBLIC) &&
constructor.getParameters().size() == 0) {
hasDefaultConstructor = true;
break;
}
}
if (!hasDefaultConstructor) {
builder.onError(classDecl.getPosition(), "webserviceap.webservice.no.default.constructor",
new Object[] {classDecl.getQualifiedName()});
return false;
}
if (webService.endpointInterface().length() == 0) {
if (!methodsAreLegal(classDecl))
return false;
} else {
InterfaceDeclaration intfDecl = getEndpointInterfaceDecl(webService.endpointInterface(), classDecl);
if (!classImplementsSEI(classDecl, intfDecl))
return false;
}
return true;
}
protected boolean classImplementsSEI(ClassDeclaration classDecl,
InterfaceDeclaration intfDecl) {
for (InterfaceType interfaceType : classDecl.getSuperinterfaces()) {
if (interfaceType.getDeclaration().equals(intfDecl))
return true;
}
boolean implementsMethod;
for (MethodDeclaration method : intfDecl.getMethods()) {
implementsMethod = false;
for (MethodDeclaration classMethod : classDecl.getMethods()) {
if (sameMethod(method, classMethod)) {
implementsMethod = true;
break;
}
}
if (!implementsMethod) {
builder.onError(method.getPosition(), "webserviceap.method.not.implemented",
new Object[] {intfDecl.getSimpleName(), classDecl.getSimpleName(),
method});
return false;
}
}
return true;
}
protected boolean sameMethod(MethodDeclaration method1, MethodDeclaration method2) {
if (!method1.getSimpleName().equals(method2.getSimpleName()))
return false;
if (!method1.getReturnType().equals(method2.getReturnType()))
return false;
ParameterDeclaration[] params1 = method1.getParameters().toArray(new ParameterDeclaration[0]);
ParameterDeclaration[] params2 = method2.getParameters().toArray(new ParameterDeclaration[0]);
if (params1.length != params2.length)
return false;
int pos = 0;
for (ParameterDeclaration param1 : method1.getParameters()) {
if (!param1.getType().equals(params2[pos++].getType()))
return false;
}
return true;
}
protected boolean isLegalSEI(InterfaceDeclaration intf) {
for (FieldDeclaration field : intf.getFields()) {
if (field.getConstantValue() != null) {
builder.onError("webserviceap.sei.cannot.contain.constant.values",
new Object[] {intf.getQualifiedName(), field.getSimpleName()});
return false;
}
}
if (!methodsAreLegal(intf))
return false;
return true;
}
protected boolean methodsAreLegal(InterfaceDeclaration intfDecl) {
hasWebMethods = false;
for (MethodDeclaration method : intfDecl.getMethods()) {
if (!isLegalMethod(method, intfDecl))
return false;
}
for (InterfaceType superIntf : intfDecl.getSuperinterfaces()) {
if (!methodsAreLegal(superIntf.getDeclaration()))
return false;
}
return true;
}
protected boolean methodsAreLegal(ClassDeclaration classDecl) {
hasWebMethods = hasWebMethods(classDecl);
for (MethodDeclaration method : classDecl.getMethods()) {
if (!isLegalMethod(method, classDecl))
return false;
}
ClassType superClass = classDecl.getSuperclass();
if (superClass != null && !methodsAreLegal(superClass.getDeclaration())) {
return false;
}
return true;
}
protected boolean isLegalMethod(MethodDeclaration method, TypeDeclaration typeDecl) {
if (hasWebMethods && method.getAnnotation(WebMethod.class) == null)
return true;
if (typeDecl instanceof ClassDeclaration && method.getModifiers().contains(Modifier.ABSTRACT)) {
builder.onError(method.getPosition(), "webserviceap.webservice.method.is.abstract",
new Object[] {typeDecl.getQualifiedName(), method.getSimpleName()});
return false;
}
if (!isLegalType(method.getReturnType())) {
builder.onError(method.getPosition(), "webserviceap.method.return.type.cannot.implement.remote",
new Object[] {typeDecl.getQualifiedName(),
method.getSimpleName(),
method.getReturnType()});
}
boolean isOneway = method.getAnnotation(Oneway.class) != null;
if (isOneway && !isValidOnewayMethod(method, typeDecl))
return false;
SOAPBinding soapBinding = method.getAnnotation(SOAPBinding.class);
if (soapBinding != null) {
if (soapBinding.style().equals(SOAPBinding.Style.RPC)) {
builder.onError(method.getPosition(),"webserviceap.rpc.soapbinding.not.allowed.on.method",
new Object[] {typeDecl.getQualifiedName(), method.toString()});
}
}
int paramIndex = 0;
for (ParameterDeclaration parameter : method.getParameters()) {
if (!isLegalParameter(parameter, method, typeDecl, paramIndex++))
return false;
}
if (!isDocLitWrapped() &&
soapStyle.equals(SOAPStyle.DOCUMENT)) {
ParameterDeclaration outParam = getOutParameter(method);
int inParams = getModeParameterCount(method, WebParam.Mode.IN);
int outParams = getModeParameterCount(method, WebParam.Mode.OUT);
if (inParams != 1) {
builder.onError(method.getPosition(),
"webserviceap.doc.bare.and.no.one.in",
new Object[] {typeDecl.getQualifiedName(), method.toString()});
}
if (method.getReturnType() instanceof VoidType) {
if (outParam == null && !isOneway) {
builder.onError(method.getPosition(),
"webserviceap.doc.bare.no.out",
new Object[] {typeDecl.getQualifiedName(), method.toString()});
}
if (outParams != 1) {
if (!isOneway && outParams != 0)
builder.onError(method.getPosition(),
"webserviceap.doc.bare.no.return.and.no.out",
new Object[] {typeDecl.getQualifiedName(), method.toString()});
}
} else {
if (outParams > 0) {
builder.onError(outParam.getPosition(),
"webserviceap.doc.bare.return.and.out",
new Object[] {typeDecl.getQualifiedName(), method.toString()});
}
}
}
return true;
}
protected boolean isLegalParameter(ParameterDeclaration param,
MethodDeclaration method,
TypeDeclaration typeDecl,
int paramIndex) {
if (!isLegalType(param.getType())) {
builder.onError(param.getPosition(), "webserviceap.method.parameter.types.cannot.implement.remote",
new Object[] {typeDecl.getQualifiedName(),
method.getSimpleName(),
param.getSimpleName(),
param.getType().toString()});
return false;
}
TypeMirror holderType;
holderType = builder.getHolderValueType(param.getType());
WebParam webParam = param.getAnnotation(WebParam.class);
WebParam.Mode mode = null;
if (webParam != null)
mode = webParam.mode();
if (holderType != null) {
if (mode != null && mode.equals(WebParam.Mode.IN))
builder.onError(param.getPosition(), "webserviceap.holder.parameters.must.not.be.in.only",
new Object[] {typeDecl.getQualifiedName(), method.toString(), paramIndex});
} else if (mode != null && !mode.equals(WebParam.Mode.IN)) {
builder.onError(param.getPosition(), "webserviceap.non.in.parameters.must.be.holder",
new Object[] {typeDecl.getQualifiedName(), method.toString(), paramIndex});
}
return true;
}
protected boolean isDocLitWrapped() {
return soapStyle.equals(SOAPStyle.DOCUMENT) && wrapped;
}
protected boolean isValidOnewayMethod(MethodDeclaration method, TypeDeclaration typeDecl) {
boolean valid = true;
if (!(method.getReturnType() instanceof VoidType)) {
// this is an error, cannot be Oneway and have a return type
builder.onError(method.getPosition(), "webserviceap.oneway.operation.cannot.have.return.type",
new Object[] {typeDecl.getQualifiedName(), method.toString()});
valid = false;
}
ParameterDeclaration outParam = getOutParameter(method);
if (outParam != null) {
builder.onError(outParam.getPosition(),
"webserviceap.oneway.and.out",
new Object[] {typeDecl.getQualifiedName(), method.toString()});
valid = false;
}
if (!isDocLitWrapped() && soapStyle.equals(SOAPStyle.DOCUMENT)) {
int inCnt = getModeParameterCount(method, WebParam.Mode.IN);
if (inCnt != 1) {
builder.onError(method.getPosition(),
"webserviceap.oneway.and.not.one.in",
new Object[] {typeDecl.getQualifiedName(), method.toString()});
valid = false;
}
}
ClassDeclaration exDecl;
for (ReferenceType thrownType : method.getThrownTypes()) {
exDecl = ((ClassType)thrownType).getDeclaration();
if (!builder.isRemoteException(exDecl)) {
builder.onError(method.getPosition(), "webserviceap.oneway.operation.cannot.declare.exceptions",
new Object[] {typeDecl.getQualifiedName(), method.toString(), exDecl.getQualifiedName()});
valid = false;
}
}
return valid;
}
protected int getModeParameterCount(MethodDeclaration method, WebParam.Mode mode) {
WebParam webParam;
int cnt = 0;
for (ParameterDeclaration param : method.getParameters()) {
webParam = param.getAnnotation(WebParam.class);
if (webParam != null) {
if (webParam.header())
continue;
if (isEquivalentModes(mode, webParam.mode()))
cnt++;
} else {
if (isEquivalentModes(mode, WebParam.Mode.IN)) {
cnt++;
}
}
}
return cnt;
}
protected boolean isEquivalentModes(WebParam.Mode mode1, WebParam.Mode mode2) {
if (mode1.equals(mode2))
return true;
assert(mode1.equals(WebParam.Mode.IN) ||
mode1.equals(WebParam.Mode.OUT));
if (mode1.equals(WebParam.Mode.IN) &&
!(mode2.equals(WebParam.Mode.OUT)))
return true;
if (mode1.equals(WebParam.Mode.OUT) &&
!(mode2.equals(WebParam.Mode.IN)))
return true;
return false;
}
protected boolean isHolder(ParameterDeclaration param) {
return builder.getHolderValueType(param.getType()) != null;
}
protected boolean isLegalType(TypeMirror type) {
if (!(type instanceof DeclaredType))
return true;
return !builder.isRemote(((DeclaredType)type).getDeclaration());
}
public void addSchemaElements(MethodDeclaration method, boolean isDocLitWrapped) {
addReturnSchemaElement(method, isDocLitWrapped);
boolean hasInParam = false;
for (ParameterDeclaration param : method.getParameters()) {
hasInParam |= addParamSchemaElement(param, method, isDocLitWrapped);
}
if (!hasInParam && soapStyle.equals(SOAPStyle.DOCUMENT) && !isDocLitWrapped) {
QName paramQName = new QName(wsdlNamespace, method.getSimpleName());
seiContext.addSchemaElement(paramQName, null);
}
}
public void addReturnSchemaElement(MethodDeclaration method, boolean isDocLitWrapped) {
TypeMirror returnType = method.getReturnType();
WebResult webResult = method.getAnnotation(WebResult.class);
String responseName = builder.getResponseName(method.getSimpleName());
String responseNamespace = wsdlNamespace;
boolean isResultHeader = false;
if (webResult != null) {
responseName = webResult.name().length() > 0 ? webResult.name() : responseName;
responseNamespace = webResult.targetNamespace().length() > 0 ? webResult.targetNamespace() : responseNamespace;
isResultHeader = webResult.header();
}
QName typeName = new QName(responseNamespace, responseName);
if (!(returnType instanceof VoidType) &&
(!isDocLitWrapped || isResultHeader)) {
Reference ref = seiContext.addReference(method);
if (!soapStyle.equals(SOAPStyle.RPC))
seiContext.addSchemaElement(typeName, ref);
}
}
public boolean addParamSchemaElement(ParameterDeclaration param, MethodDeclaration method, boolean isDocLitWrappped) {
boolean isInParam = false;
WebParam webParam = param.getAnnotation(WebParam.class);
String paramName = param.getSimpleName();
String paramNamespace = wsdlNamespace;
TypeMirror paramType = param.getType();
TypeMirror holderType = builder.getHolderValueType(paramType);
boolean isHeader = false;
if (soapStyle.equals(SOAPStyle.DOCUMENT) && !wrapped) {
paramName = method.getSimpleName();
}
if (webParam != null) {
paramName = webParam.name() != null && webParam.name().length() > 0 ? webParam.name() : paramName;
isHeader = webParam.header();
paramNamespace = webParam.targetNamespace().length() > 0 ? webParam.targetNamespace() : paramNamespace;
}
if (holderType != null) {
paramType = holderType;
}
if (isHeader || soapStyle.equals(SOAPStyle.DOCUMENT)) {
if (isHeader || !isDocLitWrappped) {
QName paramQName = new QName(paramNamespace, paramName);
Reference ref = seiContext.addReference(paramType, param);
seiContext.addSchemaElement(paramQName, ref);
}
} else
seiContext.addReference(paramType, param);
if (!isHeader && (holderType == null ||
(webParam == null || !webParam.mode().equals(WebParam.Mode.OUT)))) {
isInParam = true;
}
return isInParam;
}
protected ParameterDeclaration getOutParameter(MethodDeclaration method) {
WebParam webParam;
for (ParameterDeclaration param : method.getParameters()) {
webParam = (WebParam)param.getAnnotation(WebParam.class);
if (webParam != null &&
!webParam.mode().equals(WebParam.Mode.IN)) {
return param;
}
}
return null;
}
protected static class MySOAPBinding implements SOAPBinding {
public Style style() {return SOAPBinding.Style.DOCUMENT;}
public Use use() {return SOAPBinding.Use.LITERAL; }
public ParameterStyle parameterStyle() { return SOAPBinding.ParameterStyle.WRAPPED;}
public Class<? extends java.lang.annotation.Annotation> annotationType() {
return SOAPBinding.class;
}
}
}