FileDocCategorySizeDatePackage
RPCProvider.javaAPI DocApache Axis 1.417603Sat Apr 22 18:57:26 BST 2006org.apache.axis.providers.java

RPCProvider

public class RPCProvider extends JavaProvider
Implement message processing by walking over RPCElements of the envelope body, invoking the appropriate methods on the service object.
author
Doug Davis (dug@us.ibm.com)

Fields Summary
protected static Log
log
Constructors Summary
Methods Summary
protected voidcheckMethodName(org.apache.axis.MessageContext msgContext, java.lang.String allowedMethods, java.lang.String methodName)
Throw an AxisFault if the requested method is not allowed.

param
msgContext MessageContext
param
allowedMethods list of allowed methods
param
methodName name of target method

        // Our version doesn't need to do anything, though inherited
        // ones might.
    
protected org.apache.axis.message.RPCElementcreateResponseBody(org.apache.axis.message.RPCElement body, org.apache.axis.MessageContext msgContext, org.apache.axis.description.OperationDesc operation, org.apache.axis.description.ServiceDesc serviceDesc, java.lang.Object objRes, org.apache.axis.message.SOAPEnvelope resEnv, java.util.ArrayList outs)

        String methodName = body.getMethodName();
        /* Now put the result in the result SOAPEnvelope */
        RPCElement resBody = new RPCElement(methodName + "Response");
        resBody.setPrefix(body.getPrefix());
        resBody.setNamespaceURI(body.getNamespaceURI());
        resBody.setEncodingStyle(msgContext.getEncodingStyle());
        try {
            // Return first
            if (operation.getMethod().getReturnType() != Void.TYPE) {
                QName returnQName = operation.getReturnQName();
                if (returnQName == null) {
                    String nsp = body.getNamespaceURI();
                    if(nsp == null || nsp.length()==0) {
                        nsp = serviceDesc.getDefaultNamespace();
                    }
                    returnQName = new QName(msgContext.isEncoded() ? "" :
                                                nsp,
                                            methodName + "Return");
                }

                RPCParam param = new RPCParam(returnQName, objRes);
                param.setParamDesc(operation.getReturnParamDesc());

                if (!operation.isReturnHeader()) {
                    // For SOAP 1.2 rpc style, add a result
                    if (msgContext.getSOAPConstants() == SOAPConstants.SOAP12_CONSTANTS &&
                            (serviceDesc.getStyle().equals(Style.RPC))) {
                        RPCParam resultParam = new RPCParam(Constants.QNAME_RPC_RESULT, returnQName);
                        resultParam.setXSITypeGeneration(Boolean.FALSE);
                        resBody.addParam(resultParam);
                    }
                    resBody.addParam(param);
                } else {
                    resEnv.addHeader(new RPCHeaderParam(param));
                }

            }

            // Then any other out params
            if (!outs.isEmpty()) {
                for (Iterator i = outs.iterator(); i.hasNext();) {
                    // We know this has a holder, so just unwrap the value
                    RPCParam param = (RPCParam) i.next();
                    Holder holder = (Holder) param.getObjectValue();
                    Object value = JavaUtils.getHolderValue(holder);
                    ParameterDesc paramDesc = param.getParamDesc();

                    param.setObjectValue(value);
                    if (paramDesc != null && paramDesc.isOutHeader()) {
                        resEnv.addHeader(new RPCHeaderParam(param));
                    } else {
                        resBody.addParam(param);
                    }
                }
            }
        } catch (Exception e) {
            throw e;
        }
        return resBody;
    
protected org.apache.axis.message.RPCElementgetBody(org.apache.axis.message.SOAPEnvelope reqEnv, org.apache.axis.MessageContext msgContext)

        SOAPService service = msgContext.getService();
        ServiceDesc serviceDesc = service.getServiceDescription();
        OperationDesc operation = msgContext.getOperation();
        Vector bodies = reqEnv.getBodyElements();
        if (log.isDebugEnabled()) {
            log.debug(Messages.getMessage("bodyElems00", "" + bodies.size()));
            if(bodies.size()>0){
                log.debug(Messages.getMessage("bodyIs00", "" + bodies.get(0)));
            }
        }
        RPCElement body = null;        // Find the first "root" body element, which is the RPC call.
        for (int bNum = 0; body == null && bNum < bodies.size(); bNum++) {
            // If this is a regular old SOAPBodyElement, and it's a root,
            // we're probably a non-wrapped doc/lit service.  In this case,
            // we deserialize the element, and create an RPCElement "wrapper"
            // around it which points to the correct method.
            // FIXME : There should be a cleaner way to do this...
            if (!(bodies.get(bNum) instanceof RPCElement)) {
                SOAPBodyElement bodyEl = (SOAPBodyElement) bodies.get(bNum);
                // igors: better check if bodyEl.getID() != null
                // to make sure this loop does not step on SOAP-ENC objects
                // that follow the parameters! FIXME?
                if (bodyEl.isRoot() && operation != null && bodyEl.getID() == null) {
                    ParameterDesc param = operation.getParameter(bNum);
                    // at least do not step on non-existent parameters!
                    if (param != null) {
                        Object val = bodyEl.getValueAsType(param.getTypeQName());
                        body = new RPCElement("",
                                              operation.getName(),
                                              new Object[]{val});
                    }
                }
            } else {
                body = (RPCElement) bodies.get(bNum);
            }
        }        // special case code for a document style operation with no
        // arguments (which is a strange thing to have, but whatever)
        if (body == null) {
            // throw an error if this isn't a document style service
            if (!(serviceDesc.getStyle().equals(Style.DOCUMENT))) {
                throw new Exception(Messages.getMessage("noBody00"));
            }

            // look for a method in the service that has no arguments,
            // use the first one we find.
            ArrayList ops = serviceDesc.getOperations();
            for (Iterator iterator = ops.iterator(); iterator.hasNext();) {
                OperationDesc desc = (OperationDesc) iterator.next();
                if (desc.getNumInParams() == 0) {
                    // found one with no parameters, use it
                    msgContext.setOperation(desc);
                    // create an empty element
                    body = new RPCElement(desc.getName());
                    // stop looking
                    break;
                }
            }

            // If we still didn't find anything, report no body error.
            if (body == null) {
                throw new Exception(Messages.getMessage("noBody00"));
            }
        }
        return body;
    
protected org.apache.axis.description.OperationDescgetOperationDesc(org.apache.axis.MessageContext msgContext, org.apache.axis.message.RPCElement body)

        SOAPService service = msgContext.getService();
        ServiceDesc serviceDesc = service.getServiceDescription();
        String methodName = body.getMethodName();

        // FIXME (there should be a cleaner way to do this)
        OperationDesc operation = msgContext.getOperation();
        if (operation == null) {
            QName qname = new QName(body.getNamespaceURI(),
                    body.getName());
            operation = serviceDesc.getOperationByElementQName(qname);

        if (operation == null) {
            SOAPConstants soapConstants = msgContext == null ?
                    SOAPConstants.SOAP11_CONSTANTS :
                    msgContext.getSOAPConstants();
            if (soapConstants == SOAPConstants.SOAP12_CONSTANTS) {
                AxisFault fault =
                        new AxisFault(Constants.FAULT_SOAP12_SENDER,
                                      Messages.getMessage("noSuchOperation",
                                                          methodName),
                                      null,
                                      null);
                fault.addFaultSubCode(Constants.FAULT_SUBCODE_PROC_NOT_PRESENT);
                throw new SAXException(fault);
            } else {
                throw new AxisFault(Constants.FAULT_CLIENT, Messages.getMessage("noSuchOperation", methodName),
                        null, null);
            }
            } else {
                 msgContext.setOperation(operation);
            }
        }
        return operation;
    
protected java.lang.ObjectinvokeMethod(org.apache.axis.MessageContext msgContext, java.lang.reflect.Method method, java.lang.Object obj, java.lang.Object[] argValues)
This method encapsulates the method invocation.

param
msgContext MessageContext
param
method the target method.
param
obj the target object
param
argValues the method arguments

        return (method.invoke(obj, argValues));
    
public voidprocessMessage(org.apache.axis.MessageContext msgContext, org.apache.axis.message.SOAPEnvelope reqEnv, org.apache.axis.message.SOAPEnvelope resEnv, java.lang.Object obj)
Process the current message. Result in resEnv.

param
msgContext self-explanatory
param
reqEnv the request envelope
param
resEnv the response envelope
param
obj the service object itself


                                   
       
                                
                                
                                
              
        if (log.isDebugEnabled()) {
            log.debug("Enter: RPCProvider.processMessage()");
        }

        SOAPService service = msgContext.getService();
        ServiceDesc serviceDesc = service.getServiceDescription();
        RPCElement body = getBody(reqEnv, msgContext);

        Vector args = null;
        try {
            args = body.getParams();
        } catch (SAXException e) {
            if(e.getException() != null)
                throw e.getException();
            throw e;
        }
        int numArgs = args.size();
        OperationDesc operation = getOperationDesc(msgContext, body);

        // Create the array we'll use to hold the actual parameter
        // values.  We know how big to make it from the metadata.
        Object[] argValues = new Object[operation.getNumParams()];

        // A place to keep track of the out params (INOUTs and OUTs)
        ArrayList outs = new ArrayList();

        // Put the values contained in the RPCParams into an array
        // suitable for passing to java.lang.reflect.Method.invoke()
        // Make sure we respect parameter ordering if we know about it
        // from metadata, and handle whatever conversions are necessary
        // (values -> Holders, etc)
        for (int i = 0; i < numArgs; i++) {
            RPCParam rpcParam = (RPCParam) args.get(i);
            Object value = rpcParam.getObjectValue();

            // first check the type on the paramter
            ParameterDesc paramDesc = rpcParam.getParamDesc();

            // if we found some type info try to make sure the value type is
            // correct.  For instance, if we deserialized a xsd:dateTime in
            // to a Calendar and the service takes a Date, we need to convert
            if (paramDesc != null && paramDesc.getJavaType() != null) {

                // Get the type in the signature (java type or its holder)
                Class sigType = paramDesc.getJavaType();

                // Convert the value into the expected type in the signature
                value = JavaUtils.convert(value, sigType);

                rpcParam.setObjectValue(value);
                if (paramDesc.getMode() == ParameterDesc.INOUT) {
                    outs.add(rpcParam);
                }
            }

            // Put the value (possibly converted) in the argument array
            // make sure to use the parameter order if we have it
            if (paramDesc == null || paramDesc.getOrder() == -1) {
                argValues[i] = value;
            } else {
                argValues[paramDesc.getOrder()] = value;
            }

            if (log.isDebugEnabled()) {
                log.debug("  " + Messages.getMessage("value00",
                        "" + argValues[i]));
            }
        }

        // See if any subclasses want a crack at faulting on a bad operation
        // FIXME : Does this make sense here???
        String allowedMethods = (String) service.getOption("allowedMethods");
        checkMethodName(msgContext, allowedMethods, operation.getName());

        // Now create any out holders we need to pass in
        int count = numArgs;
        for (int i = 0; i < argValues.length; i++) {

            // We are interested only in OUT/INOUT
            ParameterDesc param = operation.getParameter(i);
            if(param.getMode() == ParameterDesc.IN)
                continue;

            Class holderClass = param.getJavaType();
            if (holderClass != null &&
                    Holder.class.isAssignableFrom(holderClass)) {
                int index = count;
                // Use the parameter order if specified or just stick them to the end.
                if (param.getOrder() != -1) {
                    index = param.getOrder();
                } else {
                    count++;
                }
                // If it's already filled, don't muck with it
                if (argValues[index] != null) {
                    continue;
                }
                argValues[index] = holderClass.newInstance();
                // Store an RPCParam in the outs collection so we
                // have an easy and consistent way to write these
                // back to the client below
                RPCParam p = new RPCParam(param.getQName(),
                        argValues[index]);
                p.setParamDesc(param);
                outs.add(p);
            } else {
                throw new AxisFault(Messages.getMessage("badOutParameter00",
                        "" + param.getQName(),
                        operation.getName()));
            }
        }

        // OK!  Now we can invoke the method
        Object objRes = null;
        try {
            objRes = invokeMethod(msgContext,
                                  operation.getMethod(),
                                  obj, argValues);
        } catch (IllegalArgumentException e) {
            String methodSig = operation.getMethod().toString();
            String argClasses = "";
            for (int i = 0; i < argValues.length; i++) {
                if (argValues[i] == null) {
                    argClasses += "null";
                } else {
                    argClasses += argValues[i].getClass().getName();
                }
                if (i + 1 < argValues.length) {
                    argClasses += ",";
                }
            }
            log.info(Messages.getMessage("dispatchIAE00",
                    new String[]{methodSig, argClasses}),
                    e);
            throw new AxisFault(Messages.getMessage("dispatchIAE00",
                    new String[]{methodSig, argClasses}),
                    e);
        }

        /** If this is a one-way operation, there is nothing more to do.
         */
        if (OperationType.ONE_WAY.equals(operation.getMep()))
            return;

        RPCElement resBody = createResponseBody(body, msgContext, operation, serviceDesc, objRes, resEnv, outs);
        resEnv.addBodyElement(resBody);