RPCHandler.java |
/* * The Apache Software License, Version 1.1 * * * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Axis" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.jboss.axis.message; /** * * @author Glen Daniels (gdaniels@allaire.com) */ import org.jboss.axis.AxisFault; import org.jboss.axis.Constants; import org.jboss.axis.description.OperationDesc; import org.jboss.axis.description.ParameterDesc; import org.jboss.axis.encoding.DeserializationContext; import org.jboss.axis.encoding.Deserializer; import org.jboss.axis.encoding.DeserializerImpl; import org.jboss.axis.encoding.MethodTarget; import org.jboss.axis.soap.SOAPConstants; import org.jboss.axis.utils.JavaUtils; import org.jboss.axis.utils.Messages; import org.jboss.logging.Logger; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import javax.xml.namespace.QName; import javax.xml.soap.SOAPElement; import java.util.Vector; /** * 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: * <p/> * <methodName> * <param1 xsi:type="xsd:string">Hello!</param1> * <param2>3.14159</param2> * </methodName> * <p/> * ...we'll get onStartChild() events for <param1> and <param2>. * * @author Glen Daniels (gdaniels@apache.org) */ public class RPCHandler extends SOAPHandler { private static Logger log = Logger.getLogger(RPCHandler.class.getName()); private RPCElement rpcElem; private RPCParam currentParam = null; private boolean isResponse; private OperationDesc operation; private boolean isHeaderElement; public RPCHandler(RPCElement rpcElem, boolean isResponse) { this.rpcElem = rpcElem; this.isResponse = isResponse; } public void setOperation(OperationDesc myOperation) { this.operation = myOperation; } /** * Indicate RPCHandler is processing header elements * * @param value boolean indicating whether * header elements are being processed. */ public void setHeaderElement(boolean value) { isHeaderElement = true; } /** * 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 */ public void startElement(String namespace, String localName, String prefix, Attributes attributes, DeserializationContext context) throws SAXException { super.startElement(namespace, localName, prefix, attributes, context); currentParam = null; } /** * Register the start of a parameter (child element of the method call * element). * <p/> * 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. */ public SOAPHandler onStartChild(String namespace, String localName, String prefix, Attributes attributes, DeserializationContext context) throws SAXException { if (log.isDebugEnabled()) { log.debug("Enter: RPCHandler.onStartChild()"); } if (!context.isDoneParsing()) { try { context.pushNewElement(new SOAPElementAxisImpl(namespace, localName, prefix, attributes, context)); } catch (AxisFault axisFault) { throw new SAXException(axisFault); } } SOAPElementAxisImpl curEl = context.getCurElement(); QName type = null; QName qname = new QName(namespace, localName); ParameterDesc paramDesc = null; SOAPConstants soapConstants = context.getMessageContext().getSOAPConstants(); if (soapConstants == SOAPConstants.SOAP12_CONSTANTS && Constants.QNAME_RPC_RESULT.equals(qname)) { // TODO: fix it ... now we just skip it return new DeserializerImpl(); } Vector params = rpcElem.getParams(); // 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(params.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(); // Keep the association so we can use it later // (see RPCProvider.processMessage()) currentParam.setParamDesc(paramDesc); if (type == null) { type = paramDesc.getTypeQName(); } } // 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 MethodTarget(currentParam, RPCParam.getValueSetMethod())); 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) { if (type != null) { dser = context.getDeserializerForType(type); if (null != destClass && dser == null && destClass.isAssignableFrom(SOAPElement.class)) { //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) { throw new SAXException(Messages.getMessage("noDeser01", localName, "" + type)); } if (paramDesc != null && paramDesc.getJavaType() != null && !Constants.XSD_ANYTYPE.equals(type)) { // If we have an xsi:type, make sure it makes sense with the current paramDesc type Class xsiClass = context.getTypeMapping().getClassForQName(type); if (xsiClass != null && !JavaUtils.isConvertable(xsiClass, destClass)) { throw new SAXException("Bad types (" + xsiClass + " -> " + destClass + ")"); } } } else { dser = new DeserializerImpl(); if (dser == null) { throw new SAXException(Messages.getMessage("noDeser01", localName, "" + type)); } } } dser.setDefaultType(type); dser.registerValueTarget(new MethodTarget(currentParam, RPCParam.getValueSetMethod())); if (log.isDebugEnabled()) { log.debug("Exit: RPCHandler.onStartChild()"); } return (SOAPHandler)dser; } public void endElement(String namespace, String localName, DeserializationContext context) throws SAXException { // 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); } }
RPCHandler.java |