in axis-rt-core/src/main/java/org/apache/axis/description/JavaServiceDesc.java [573:787]
private void syncOperationToClass(OperationDesc oper, Class implClass)
{
// ------------------------------------------------
// Developer Note:
//
// The goal of the sync code is to associate
// the OperationDesc/ParamterDesc with the
// target Method. There are a number of ways to get to this
// point depending on what information
// is available. Here are the main scenarios:
//
// A) Deployment with wsdd (non-skeleton):
// * OperationDesc/ParameterDesc loaded from deploy.wsdd
// * Loaded ParameterDesc does not have javaType,
// so it is discovered using the TypeMappingRegistry
// (also loaded via deploy.wsdd) and the
// typeQName specified by the ParameterDesc.
// * Sync occurs using the discovered
// javaTypes and the javaTypes of the Method
// parameters
//
// B) Deployment with no wsdd OperationDesc info (non-skeleton):
// * Implementation Class introspected to build
// OperationDesc/ParameterDesc.
// * ParameterDesc is known via introspection.
// * ParameterDesc are discovered using javaType
// and TypeMappingRegistry.
// * Sync occurs using the introspected
// javaTypes and the javaTypes of the Method
// parameters
//
// C) Deployment with wsdd (skeleton):
// * OperationDesc/ParameterDesc loaded from the Skeleton
// * In this scenario the ParameterDescs' already
// have javaTypes (see E below).
// * Sync occurs using the ParameterDesc
// javaTypes and the javaTypes of the Method
// parameters.
//
// D) Commandline Java2WSDL loading non-Skeleton Class/Interface
// * Class/Interface introspected to build
// OperationDesc/ParameterDesc.
// * The javaTypes of the ParameterDesc are set using introspection.
// * typeQNames are determined for built-in types using
// from the default TypeMappingRegistry. Other
// typeQNames are guessed from the javaType. Note
// that there is no loaded TypeMappingRegistry.
// * Sync occurs using the ParameterDesc
// javaTypes and the javaTypes of the Method
// parameters.
//
// E) Commandline Java2WSDL loading Skeleton Class
// * OperationDesc/ParameterDesc loaded from Skeleton
// * Each ParameterDesc has an appropriate typeQName
// * Each ParameterDesc also has a javaType, which is
// essential for sync'ing up with the
// method since there is no loaded TypeMappingRegistry.
// * Syncronization occurs using the ParameterDesc
// javaTypes and the javaTypes of the Method
// parameters.
//
// So in each scenario, the ultimate sync'ing occurs
// using the javaTypes of the ParameterDescs and the
// javaTypes of the Method parameters.
//
// ------------------------------------------------
// If we're already mapped to a Java method, no need to do anything.
if (oper.getMethod() != null)
return;
// Find the method. We do this once for each Operation.
Method[] methods = getMethods(implClass);
// A place to keep track of possible matches
Method possibleMatch = null;
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (Modifier.isPublic(method.getModifiers()) &&
method.getName().equals(oper.getName()) &&
method2OperationMap.get(method) == null) {
if (style == Style.MESSAGE) {
int messageOperType = checkMessageMethod(method);
if(messageOperType == OperationDesc.MSG_METHOD_NONCONFORMING) continue;
if (messageOperType == -1) {
throw new InternalException("Couldn't match method to any of the allowable message-style patterns!");
}
oper.setMessageOperationStyle(messageOperType);
// Don't bother checking params if we're message style
possibleMatch = method;
break;
}
// Check params
Class [] paramTypes = method.getParameterTypes();
if (paramTypes.length != oper.getNumParams())
continue;
int j;
boolean conversionNecessary = false;
for (j = 0; j < paramTypes.length; j++) {
Class type = paramTypes[j];
Class actualType = type;
if (Holder.class.isAssignableFrom(type)) {
actualType = JavaUtils.getHolderValueType(type);
}
ParameterDesc param = oper.getParameter(j);
QName typeQName = param.getTypeQName();
if (typeQName == null) {
// No typeQName is available. Set it using
// information from the actual type.
// (Scenarios B and D)
// There is no need to try and match with
// the Method parameter javaType because
// the ParameterDesc is being constructed
// by introspecting the Method.
typeQName = getTypeMapping().getTypeQName(actualType);
param.setTypeQName(typeQName);
} else {
// A type qname is available.
// Ensure that the ParameterDesc javaType
// is convertable to the Method parameter type
//
// Use the available javaType (Scenarios C and E)
// or get one from the TMR (Scenario A).
Class paramClass = param.getJavaType();
if (paramClass != null &&
JavaUtils.getHolderValueType(paramClass) != null) {
paramClass = JavaUtils.getHolderValueType(paramClass);
}
if (paramClass == null) {
paramClass = getTypeMapping().getClassForQName(param.getTypeQName(),
type);
}
if (paramClass != null) {
// This is a match if the paramClass is somehow
// convertable to the "real" parameter type. If not,
// break out of this loop.
if (!JavaUtils.isConvertable(paramClass, actualType)) {
break;
}
if (!actualType.isAssignableFrom(paramClass)) {
// This doesn't fit without conversion
conversionNecessary = true;
}
}
}
// In all scenarios the ParameterDesc javaType is set to
// match the javaType in the corresponding parameter.
// This is essential.
param.setJavaType(type);
}
if (j != paramTypes.length) {
// failed.
continue;
}
// This is our latest possibility
possibleMatch = method;
// If this is exactly it, stop now. Otherwise keep looking
// just in case we find a better match.
if (!conversionNecessary) {
break;
}
}
}
// At this point, we may or may not have a possible match.
// FIXME : Should we prefer an exact match from a base class over
// a with-conversion match from the target class? If so,
// we'll need to change the logic below.
if (possibleMatch != null) {
Class returnClass = possibleMatch.getReturnType();
oper.setReturnClass(returnClass);
QName returnType = oper.getReturnType();
if (returnType == null) {
oper.setReturnType(getTypeMapping().getTypeQName(returnClass));
}
// Do the faults
createFaultMetadata(possibleMatch, oper);
oper.setMethod(possibleMatch);
method2OperationMap.put(possibleMatch, oper);
return;
}
// Didn't find a match. Try the superclass, if appropriate
Class superClass = implClass.getSuperclass();
if (superClass != null &&
!superClass.getName().startsWith("java.") &&
!superClass.getName().startsWith("javax.") &&
(stopClasses == null ||
!stopClasses.contains(superClass.getName()))) {
syncOperationToClass(oper, superClass);
}
// Exception if sync fails to find method for operation
if (oper.getMethod() == null) {
InternalException ie =
new InternalException(Messages.getMessage("serviceDescOperSync00",
oper.getName(),
implClass.getName()));
throw ie;
}
}