| /* |
| * Copyright 2001-2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.axis.message; |
| |
| import org.apache.axis.AxisFault; |
| import org.apache.axis.Constants; |
| import org.apache.axis.encoding.Callback; |
| import org.apache.axis.encoding.CallbackTarget; |
| import org.apache.axis.encoding.DeserializationContext; |
| import org.apache.axis.encoding.Deserializer; |
| import org.apache.axis.soap.SOAPConstants; |
| import org.apache.axis.utils.Messages; |
| import org.apache.axis.utils.XMLUtils; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXException; |
| |
| import javax.xml.namespace.QName; |
| import java.lang.reflect.Constructor; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Vector; |
| |
| /** |
| * Build a Fault body element. |
| * |
| * @author Sam Ruby (rubys@us.ibm.com) |
| * @author Glen Daniels (gdaniels@apache.org) |
| * @author Tom Jordahl (tomj@macromedia.com) |
| */ |
| public class SOAPFaultBuilder extends SOAPHandler implements Callback |
| { |
| boolean waiting = false; |
| boolean passedEnd = false; |
| |
| protected SOAPFault element; |
| protected DeserializationContext context; |
| static HashMap fields_soap11 = new HashMap(); |
| static HashMap fields_soap12 = new HashMap(); |
| |
| // Fault data |
| protected QName faultCode = null; |
| protected QName[] faultSubCode = null; |
| protected String faultString = null; |
| protected String faultActor = null; |
| protected Element[] faultDetails; |
| protected String faultNode = null; |
| |
| protected SOAPFaultCodeBuilder code; |
| |
| protected Class faultClass = null; |
| protected Object faultData = null; |
| |
| static { |
| fields_soap11.put(Constants.ELEM_FAULT_CODE, Constants.XSD_QNAME); |
| fields_soap11.put(Constants.ELEM_FAULT_STRING, Constants.XSD_STRING); |
| fields_soap11.put(Constants.ELEM_FAULT_ACTOR, Constants.XSD_STRING); |
| fields_soap11.put(Constants.ELEM_FAULT_DETAIL, null); |
| } |
| |
| static { |
| fields_soap12.put(Constants.ELEM_FAULT_REASON_SOAP12, null); |
| fields_soap12.put(Constants.ELEM_FAULT_ROLE_SOAP12, Constants.XSD_STRING); |
| fields_soap12.put(Constants.ELEM_FAULT_NODE_SOAP12, Constants.XSD_STRING); |
| fields_soap12.put(Constants.ELEM_FAULT_DETAIL_SOAP12, null); |
| } |
| |
| public SOAPFaultBuilder(SOAPFault element, |
| DeserializationContext context) { |
| this.element = element; |
| this.context = context; |
| } |
| |
| public void startElement(String namespace, String localName, |
| String prefix, Attributes attributes, |
| DeserializationContext context) |
| throws SAXException |
| { |
| SOAPConstants soapConstants = context.getSOAPConstants(); |
| |
| if (soapConstants == SOAPConstants.SOAP12_CONSTANTS && |
| attributes.getValue(Constants.URI_SOAP12_ENV, Constants.ATTR_ENCODING_STYLE) != null) { |
| |
| AxisFault fault = new AxisFault(Constants.FAULT_SOAP12_SENDER, |
| null, Messages.getMessage("noEncodingStyleAttrAppear", "Fault"), null, null, null); |
| |
| throw new SAXException(fault); |
| } |
| |
| super.startElement(namespace, localName, prefix, attributes, context); |
| } |
| |
| void setFaultData(Object data) { |
| faultData = data; |
| if (waiting && passedEnd) { |
| // This happened after the end of the <soap:Fault>, so make |
| // sure we set up the fault. |
| createFault(); |
| } |
| waiting = false; |
| } |
| |
| public void setFaultClass(Class faultClass) { |
| this.faultClass = faultClass; |
| } |
| |
| /** |
| * Final call back where we can populate the exception with data. |
| */ |
| public void endElement(String namespace, String localName, |
| DeserializationContext context) |
| throws SAXException { |
| super.endElement(namespace, localName, context); |
| if (!waiting) { |
| createFault(); |
| } else { |
| passedEnd = true; |
| } |
| } |
| |
| void setWaiting(boolean waiting) { |
| this.waiting = waiting; |
| } |
| |
| /** |
| * When we're sure we have everything, this gets called. |
| */ |
| private void createFault() { |
| AxisFault f = null; |
| |
| SOAPConstants soapConstants = context.getMessageContext() == null ? |
| SOAPConstants.SOAP11_CONSTANTS : |
| context.getMessageContext().getSOAPConstants(); |
| |
| if (faultClass != null) { |
| // Custom fault handling |
| try { |
| |
| // If we have an element which is fault data, It can be: |
| // 1. A simple type that needs to be passed in to the constructor |
| // 2. A complex type that is the exception itself |
| if (faultData != null) { |
| if (faultData instanceof AxisFault) { |
| // This is our exception class |
| f = (AxisFault) faultData; |
| } else { |
| // We need to create the exception, |
| // passing the data to the constructor. |
| Class argClass = ConvertWrapper(faultData.getClass()); |
| try { |
| Constructor con = |
| faultClass.getConstructor( |
| new Class[] { argClass }); |
| f = (AxisFault) con.newInstance(new Object[] { faultData }); |
| } catch(Exception e){ |
| // Don't do anything here, since a problem above means |
| // we'll just fall through and use a plain AxisFault. |
| } |
| if (f == null && faultData instanceof Exception) { |
| f = AxisFault.makeFault((Exception)faultData); |
| } |
| } |
| } |
| // If we have an AxisFault, set the fields |
| if (AxisFault.class.isAssignableFrom(faultClass)) { |
| if (f == null) { |
| // this is to support the <exceptionName> detail |
| f = (AxisFault) faultClass.newInstance(); |
| } |
| |
| if (soapConstants == SOAPConstants.SOAP12_CONSTANTS) { |
| f.setFaultCode(code.getFaultCode()); |
| |
| SOAPFaultCodeBuilder c = code; |
| while ((c = c.getNext()) != null) { |
| f.addFaultSubCode(c.getFaultCode()); |
| } |
| } else { |
| f.setFaultCode(faultCode); |
| } |
| |
| f.setFaultString(faultString); |
| f.setFaultActor(faultActor); |
| f.setFaultNode(faultNode); |
| f.setFaultDetail(faultDetails); |
| } |
| } catch (Exception e) { |
| // Don't do anything here, since a problem above means |
| // we'll just fall through and use a plain AxisFault. |
| } |
| } |
| |
| if (f == null) { |
| if (soapConstants == SOAPConstants.SOAP12_CONSTANTS) { |
| faultCode = code.getFaultCode(); |
| if (code.getNext() != null) |
| { |
| Vector v = new Vector(); |
| |
| SOAPFaultCodeBuilder c = code; |
| while ((c = c.getNext()) != null) |
| v.add(c.getFaultCode()); |
| |
| faultSubCode = (QName[])v.toArray(new QName[v.size()]); |
| } |
| } |
| |
| f = new AxisFault(faultCode, |
| faultSubCode, |
| faultString, |
| faultActor, |
| faultNode, |
| faultDetails); |
| |
| try { |
| Vector headers = element.getEnvelope().getHeaders(); |
| for (int i = 0; i < headers.size(); i++) { |
| SOAPHeaderElement header = |
| (SOAPHeaderElement) headers.elementAt(i); |
| f.addHeader(header); |
| } |
| } catch (AxisFault axisFault) { |
| // What to do here? |
| } |
| } |
| |
| element.setFault(f); |
| } |
| |
| public SOAPHandler onStartChild(String namespace, |
| String name, |
| String prefix, |
| Attributes attributes, |
| DeserializationContext context) |
| throws SAXException |
| { |
| SOAPHandler retHandler = null; |
| |
| SOAPConstants soapConstants = context.getMessageContext() == null ? |
| SOAPConstants.SOAP11_CONSTANTS : |
| context.getMessageContext().getSOAPConstants(); |
| |
| QName qName; |
| // If we found the type for this field, get the deserializer |
| // otherwise, if this is the details element, use the special |
| // SOAPFaultDetailsBuilder handler to take care of custom fault data |
| if (soapConstants == SOAPConstants.SOAP12_CONSTANTS) { |
| qName = (QName)fields_soap12.get(name); |
| if (qName == null) { |
| QName thisQName = new QName(namespace, name); |
| if (thisQName.equals(Constants.QNAME_FAULTCODE_SOAP12)) |
| return (code = new SOAPFaultCodeBuilder()); |
| else if (thisQName.equals(Constants.QNAME_FAULTREASON_SOAP12)) |
| return new SOAPFaultReasonBuilder(this); |
| else if (thisQName.equals(Constants.QNAME_FAULTDETAIL_SOAP12)) |
| return new SOAPFaultDetailsBuilder(this); |
| |
| } |
| } else { |
| qName = (QName)fields_soap11.get(name); |
| if (qName == null && name.equals(Constants.ELEM_FAULT_DETAIL)) |
| return new SOAPFaultDetailsBuilder(this); |
| } |
| |
| if (qName != null) { |
| Deserializer currentDeser = context.getDeserializerForType(qName); |
| if (currentDeser != null) { |
| currentDeser.registerValueTarget(new CallbackTarget(this, new QName(namespace, name))); |
| } |
| retHandler = (SOAPHandler) currentDeser; |
| } |
| |
| return retHandler; |
| } |
| |
| public void onEndChild(String namespace, String localName, |
| DeserializationContext context) |
| throws SAXException { |
| if (Constants.ELEM_FAULT_DETAIL.equals(localName)) { |
| MessageElement el = context.getCurElement(); |
| List children = el.getChildren(); |
| if (children != null) { |
| Element [] elements = new Element [children.size()]; |
| for (int i = 0; i < elements.length; i++) { |
| try { |
| Node node = (Node) children.get(i); |
| if (node instanceof MessageElement) { |
| elements[i] = ((MessageElement) node).getAsDOM(); |
| } else if(node instanceof Text){ |
| Document tempDoc = XMLUtils.newDocument(); |
| elements[i] = tempDoc.createElement("text"); |
| elements[i].appendChild(tempDoc.importNode(node,true)); |
| } |
| } catch (Exception e) { |
| throw new SAXException(e); |
| } |
| } |
| faultDetails = elements; |
| } |
| } |
| } |
| |
| /* |
| * Defined by Callback. |
| * This method gets control when the callback is invoked. |
| * @param is the value to set. |
| * @param hint is an Object that provide additional hint information. |
| */ |
| public void setValue(Object value, Object hint) |
| { |
| String local = ((QName)hint).getLocalPart(); |
| if (((QName)hint).getNamespaceURI().equals(Constants.URI_SOAP12_ENV)) { |
| if (local.equals(Constants.ELEM_FAULT_ROLE_SOAP12)) { |
| faultActor = (String) value; |
| } else if (local.equals(Constants.ELEM_TEXT_SOAP12)) { |
| faultString = (String) value; |
| } else if (local.equals(Constants.ELEM_FAULT_NODE_SOAP12)) { |
| faultNode = (String) value; |
| } |
| } else { |
| if (local.equals(Constants.ELEM_FAULT_CODE)) { |
| faultCode = (QName)value; |
| } else if (local.equals(Constants.ELEM_FAULT_STRING)) { |
| faultString = (String) value; |
| } else if (local.equals(Constants.ELEM_FAULT_ACTOR)) { |
| faultActor = (String) value; |
| } |
| } |
| |
| } |
| |
| /** |
| * A simple map of holder objects and their primitive types |
| */ |
| private static HashMap TYPES = new HashMap(7); |
| |
| static { |
| TYPES.put(java.lang.Integer.class, int.class); |
| TYPES.put(java.lang.Float.class, float.class); |
| TYPES.put(java.lang.Boolean.class, boolean.class); |
| TYPES.put(java.lang.Double.class, double.class); |
| TYPES.put(java.lang.Byte.class, byte.class); |
| TYPES.put(java.lang.Short.class, short.class); |
| TYPES.put(java.lang.Long.class, long.class); |
| } |
| |
| /** |
| * Internal method to convert wrapper classes to their base class |
| */ |
| private Class ConvertWrapper(Class cls) { |
| Class ret = (Class) TYPES.get(cls); |
| if (ret != null) { |
| return ret; |
| } |
| return cls; |
| } |
| } |