FileDocCategorySizeDatePackage
RPCHandler.javaAPI DocApache Axis 1.412237Sat Apr 22 18:57:28 BST 2006org.apache.axis.message

RPCHandler

public class RPCHandler extends SOAPHandler
This is the SOAPHandler which is called for each RPC parameter as we're deserializing the XML for a method call or return. In other words for this XML: Hello! 3.14159 ...we'll get onStartChild() events for and .
author
Glen Daniels (gdaniels@apache.org)

Fields Summary
protected static Log
log
private RPCElement
rpcElem
private RPCParam
currentParam
private boolean
isResponse
private org.apache.axis.description.OperationDesc
operation
private boolean
isHeaderElement
Constructors Summary
public RPCHandler(RPCElement rpcElem, boolean isResponse)


        
         
    
        this.rpcElem = rpcElem;
        this.isResponse = isResponse;
    
Methods Summary
public voidendElement(java.lang.String namespace, java.lang.String localName, org.apache.axis.encoding.DeserializationContext context)

        // endElement may not be called in all circumstances.
        // In addition, onStartChild may be called after endElement
        // (for header parameter/response processing).  
        // So please don't add important logic to this method.
        if (log.isDebugEnabled()) {
            log.debug(Messages.getMessage("setProp00",
                    "MessageContext", "RPCHandler.endElement()."));
        }
        context.getMessageContext().setProperty("RPC", rpcElem);
    
public SOAPHandleronStartChild(java.lang.String namespace, java.lang.String localName, java.lang.String prefix, org.xml.sax.Attributes attributes, org.apache.axis.encoding.DeserializationContext context)
Register the start of a parameter (child element of the method call element). Our job here is to figure out a) which parameter this is (based on the QName of the element or its position), and b) what type it is (based on the xsi:type attribute or operation metadata) so we can successfully deserialize it.

        if (log.isDebugEnabled()) {
            log.debug("Enter: RPCHandler.onStartChild()");
        }

        if (!context.isDoneParsing()) {
            try {
                context.pushNewElement(new MessageElement(namespace, localName,
                                                          prefix, attributes,
                                                          context));
            } catch (AxisFault axisFault) {
                throw new SAXException(axisFault);
            }
        }
        
        MessageElement curEl = context.getCurElement();
        QName type = null;
        QName qname = new QName(namespace, localName);
        ParameterDesc paramDesc = null;

        SOAPConstants soapConstants = context.getSOAPConstants();
        if (soapConstants == SOAPConstants.SOAP12_CONSTANTS &&
            Constants.QNAME_RPC_RESULT.equals(qname)) {
            // TODO: fix it ... now we just skip it
            return new DeserializerImpl();
        }

        // Create a new param if not the same element
        if (currentParam == null ||
            !currentParam.getQName().getNamespaceURI().equals(namespace) ||
            !currentParam.getQName().getLocalPart().equals(localName)) {
            currentParam = new RPCParam(namespace, localName, null);
            rpcElem.addParam(currentParam);
        }

        // Grab xsi:type attribute if present, on either this element or
        // the referent (if it's an href).  MessageElement.getType() will
        // automatically dig through to the referent if necessary.
        type = curEl.getType();
        if (type == null) {
            type = context.getTypeFromAttributes(namespace,
                                                 localName,
                                                 attributes);
        }

        if (log.isDebugEnabled()) {
            log.debug(Messages.getMessage("typeFromAttr00", "" + type));
        }
        

        Class destClass = null;

        // If we have an operation descriptor, try to associate this parameter
        // with the appropriate ParameterDesc
        if (operation != null) {
            
            // Try by name first
            if (isResponse) {
                paramDesc = operation.getOutputParamByQName(qname);
            } else {
                paramDesc = operation.getInputParamByQName(qname);
            }

            
            // If that didn't work, try position
            // FIXME : Do we need to be in EITHER named OR positional
            //         mode?  I.e. will it screw us up to find something
            //         by position if we've already looked something up
            //         by name?  I think so...
            if (paramDesc == null) {
                if (isResponse) {
                    paramDesc = operation.getReturnParamDesc();
                }
                else {
                    paramDesc = operation.getParameter(rpcElem.getParams().size() - 1);
                }
            }
            
            if (paramDesc == null) {
                throw new SAXException(Messages.getMessage("noParmDesc"));
            }
            // Make sure that we don't find body parameters that should
            // be in the header
            if (!isHeaderElement &&
                ((isResponse && paramDesc.isOutHeader()) ||
                 (!isResponse && paramDesc.isInHeader()))) {
                throw new SAXException(
                    Messages.getMessage("expectedHeaderParam", 
                                        paramDesc.getQName().toString()));
            }

            destClass = paramDesc.getJavaType();
            if ((destClass != null) && (destClass.isArray())) {
                context.setDestinationClass(destClass);
            }
            
            // Keep the association so we can use it later
            // (see RPCProvider.processMessage())
            currentParam.setParamDesc(paramDesc);
            
            if (type == null) {
                type = paramDesc.getTypeQName();
            }
        }

        if (type != null && type.equals(XMLType.AXIS_VOID)) {
            Deserializer nilDSer =  new DeserializerImpl();
            return (SOAPHandler) nilDSer;
        }

        // If the nil attribute is set, just
        // return the base DeserializerImpl.
        // Register the value target to set the value
        // on the RPCParam.  This is necessary for cases like
        //  <method>
        //    <foo>123</foo>
        //    <foo>456</foo>
        //    <foo xsi:nil="true" />
        //  </method>
        // so that a list of 3 items is created.
        // Failure to register the target would result in the last
        // item not being added to the list
        if (context.isNil(attributes)) {
          Deserializer nilDSer =  new DeserializerImpl();
          nilDSer.registerValueTarget(new RPCParamTarget(currentParam));
          return (SOAPHandler) nilDSer;
        }
        
        Deserializer dser = null;
        if ((type == null) && (namespace != null) && (!namespace.equals(""))) {
            dser = context.getDeserializerForType(qname);
        } else {
            dser = context.getDeserializer(destClass, type);
            // !!!
            if (dser == null && destClass != null && destClass.isArray() &&
                    operation.getStyle() == Style.DOCUMENT) {
                dser = context.getDeserializerForClass(destClass);
            }
            // !!!
        }
        
        if (dser == null) {
          if (type != null) {
              dser = context.getDeserializerForType(type);
              if(null != destClass && dser == null && Element.class.isAssignableFrom(destClass)){
                //If a DOM element is expected, as last resort always allow direct mapping 
                // of parameter's SOAP xml to a DOM element.  Support of literal  parms by default.
                dser = context.getDeserializerForType(Constants.SOAP_ELEMENT);

              }
              if (dser == null) {
                dser = context.getDeserializerForClass(destClass);
              } 
              if (dser == null) {
                  throw new SAXException(Messages.getMessage(
                          "noDeser01", localName,"" + type));
              }
              if (paramDesc != null && paramDesc.getJavaType() != null) {
                  // If we have an xsi:type, make sure it makes sense
                  // with the current paramDesc type
                  Class xsiClass = 
                          context.getTypeMapping().getClassForQName(type);
                  if (null != xsiClass  && !JavaUtils.isConvertable(xsiClass, destClass)) {
                      throw new SAXException("Bad types (" +
                                             xsiClass + " -> " + destClass + ")"); // FIXME!
                  }
              }
          } else {
              dser = context.getDeserializerForClass(destClass);
              if (dser == null) {
                  dser = new DeserializerImpl();
              }
          }
        }

        dser.setDefaultType(type);

        dser.registerValueTarget(new RPCParamTarget(currentParam));

        if (log.isDebugEnabled()) {
            log.debug("Exit: RPCHandler.onStartChild()");
        }
        return (SOAPHandler)dser;
    
public voidsetHeaderElement(boolean value)
Indicate RPCHandler is processing header elements

param
value boolean indicating whether header elements are being processed.

        isHeaderElement = true;
    
public voidsetOperation(org.apache.axis.description.OperationDesc myOperation)

        this.operation = myOperation;
    
public voidstartElement(java.lang.String namespace, java.lang.String localName, java.lang.String prefix, org.xml.sax.Attributes attributes, org.apache.axis.encoding.DeserializationContext context)
This method is invoked when an element start tag is encountered. The purpose of this method in RPCHandler is to reset variables (this allows re-use of RPCHandlers)

param
namespace is the namespace of the element
param
localName is the name of the element
param
prefix is the prefix of the element
param
attributes are the attributes on the element...used to get the type
param
context is the DeserializationContext

        super.startElement(namespace, localName, prefix, attributes, context);
        currentParam = null;