Java tutorial
/* * 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.MessageContext; import org.apache.axis.components.logger.LogFactory; import org.apache.axis.encoding.DeserializationContext; import org.apache.axis.encoding.Deserializer; import org.apache.axis.encoding.SerializationContext; import org.apache.axis.encoding.TextSerializationContext; import org.apache.axis.constants.Style; import org.apache.axis.soap.SOAPConstants; import org.apache.axis.utils.Mapping; import org.apache.axis.utils.Messages; import org.apache.axis.utils.XMLUtils; import org.apache.commons.logging.Log; import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; import org.w3c.dom.CharacterData; import org.w3c.dom.Comment; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.w3c.dom.NamedNodeMap; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; import javax.xml.namespace.QName; import javax.xml.rpc.encoding.TypeMapping; import javax.xml.soap.Name; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPException; import javax.xml.parsers.ParserConfigurationException; import java.io.Reader; import java.io.Serializable; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Vector; /** * MessageElement is the base type of nodes of the SOAP message parse tree. * * Note: it was made Serializable to help users of Apache SOAP who had * exploited the serializability of the DOM tree to migrate to Axis. * @todo implement the NodeList methods properly, with tests. */ public class MessageElement extends NodeImpl implements SOAPElement, Serializable, org.w3c.dom.NodeList, // ADD Nodelist Interfaces for SAAJ 1.2 Cloneable { protected static Log log = LogFactory.getLog(MessageElement.class.getName()); private static final Mapping enc11Mapping = new Mapping(Constants.URI_SOAP11_ENC, "SOAP-ENC"); private static final Mapping enc12Mapping = new Mapping(Constants.URI_SOAP12_ENC, "SOAP-ENC"); protected String id; protected String href; protected boolean _isRoot = true; protected SOAPEnvelope message = null; protected transient DeserializationContext context; protected transient QName typeQName = null; protected Vector qNameAttrs = null; // Some message representations - as recorded SAX events... protected transient SAX2EventRecorder recorder = null; protected int startEventIndex = 0; protected int startContentsIndex = 0; protected int endEventIndex = -1; public ArrayList namespaces = null; /** Our encoding style, if any */ protected String encodingStyle = null; /** Object value, possibly supplied by subclass */ private Object objectValue = null; /** No-arg constructor for building messages? */ public MessageElement() { } /** * constructor * @param namespace namespace of element * @param localPart local name */ public MessageElement(String namespace, String localPart) { namespaceURI = namespace; name = localPart; } /** * constructor. Automatically adds a namespace-prefix mapping to the mapping table * @param localPart local name * @param prefix prefix * @param namespace namespace */ public MessageElement(String localPart, String prefix, String namespace) { this.namespaceURI = namespace; this.name = localPart; this.prefix = prefix; addMapping(new Mapping(namespace, prefix)); } /** * construct using a {@link javax.xml.soap.Name} implementation, * @see #MessageElement(String, String, String) * @param eltName */ public MessageElement(Name eltName) { this(eltName.getLocalName(), eltName.getPrefix(), eltName.getURI()); } /** * constructor binding the internal object value field to the * value parameter * @param namespace namespace of the element * @param localPart local name * @param value value of the node */ public MessageElement(String namespace, String localPart, Object value) { this(namespace, localPart); objectValue = value; } /** * constructor declaring the qualified name of the node * @param name naming information */ public MessageElement(QName name) { this(name.getNamespaceURI(), name.getLocalPart()); } /** * constructor declaring the qualified name of the node * and its value * @param name naming information * @param value value of the node */ public MessageElement(QName name, Object value) { this(name.getNamespaceURI(), name.getLocalPart()); objectValue = value; } /** * create a node through a deep copy of the passed in element. * @param elem name to copy from */ public MessageElement(Element elem) { namespaceURI = elem.getNamespaceURI(); name = elem.getLocalName(); copyNode(elem); } /** * construct a text element. * @param text text data. This is <i>not</i> copied; it is referred to in the MessageElement. */ public MessageElement(CharacterData text) { textRep = text; namespaceURI = text.getNamespaceURI(); name = text.getLocalName(); } /** * Advanced constructor used for deserialization. * <ol> * <li>The context provides the mappings and Sax event recorder * <li>The soap messaging style is determined from the current message context, defaulting * to SOAP1.1 if there is no current context. * <li>if there is an id attribute (any namespace), then the ID is registered * with {@link DeserializationContext#registerElementByID(String, MessageElement)} ;a new recorder is * created if needed. * <li>If there is an attribute "root" in the default SOAP namespace, then it is examined * to see if it marks the element as root (value=="1" or not) * <li>If there is an arrayType attribute then we assume we are an array and set our * {@link #typeQName} field appropriately. * <li>The {@link #href} field is set if there is a relevant href value * </ol> * * @param namespace namespace namespace of element * @param localPart local name local name of element * @param prefix prefix prefix of element * @param attributes attributes to save as our attributes * @param context deserialization context for this message element * @throws AxisFault if the encoding style is not recognized/supported */ public MessageElement(String namespace, String localPart, String prefix, Attributes attributes, DeserializationContext context) throws AxisFault { if (log.isDebugEnabled()) { log.debug(Messages.getMessage("newElem00", super.toString(), "{" + prefix + "}" + localPart)); for (int i = 0; attributes != null && i < attributes.getLength(); i++) { log.debug(" " + attributes.getQName(i) + " = '" + attributes.getValue(i) + "'"); } } this.namespaceURI = namespace; this.name = localPart; this.prefix = prefix; this.context = context; this.startEventIndex = context.getStartOfMappingsPos(); setNSMappings(context.getCurrentNSMappings()); this.recorder = context.getRecorder(); if (attributes != null && attributes.getLength() > 0) { this.attributes = attributes; this.typeQName = context.getTypeFromAttributes(namespace, localPart, attributes); String rootVal = attributes.getValue(Constants.URI_DEFAULT_SOAP_ENC, Constants.ATTR_ROOT); if (rootVal != null) { _isRoot = "1".equals(rootVal); } id = attributes.getValue(Constants.ATTR_ID); // Register this ID with the context..... if (id != null) { context.registerElementByID(id, this); if (recorder == null) { recorder = new SAX2EventRecorder(); context.setRecorder(recorder); } } // Set the encoding style to the attribute value. If null, // we just automatically use our parent's (see getEncodingStyle) MessageContext mc = context.getMessageContext(); SOAPConstants sc = (mc != null) ? mc.getSOAPConstants() : SOAPConstants.SOAP11_CONSTANTS; href = attributes.getValue(sc.getAttrHref()); // If there's an arrayType attribute, we can pretty well guess that we're an Array??? if (attributes.getValue(Constants.URI_DEFAULT_SOAP_ENC, Constants.ATTR_ARRAY_TYPE) != null) { typeQName = Constants.SOAP_ARRAY; } encodingStyle = attributes.getValue(sc.getEncodingURI(), Constants.ATTR_ENCODING_STYLE); // if no-encoding style was defined, we don't define as well if (Constants.URI_SOAP12_NOENC.equals(encodingStyle)) encodingStyle = null; // If we have an encoding style, and are not a MESSAGE style // operation (in other words - we're going to do some data // binding), AND we're SOAP 1.2, check the encoding style against // the ones we've got type mappings registered for. If it isn't // registered, throw a DataEncodingUnknown fault as per the // SOAP 1.2 spec. if (encodingStyle != null && sc.equals(SOAPConstants.SOAP12_CONSTANTS) && (mc.getOperationStyle() != Style.MESSAGE)) { TypeMapping tm = mc.getTypeMappingRegistry().getTypeMapping(encodingStyle); if (tm == null || (tm.equals(mc.getTypeMappingRegistry().getDefaultTypeMapping()))) { AxisFault badEncodingFault = new AxisFault(Constants.FAULT_SOAP12_DATAENCODINGUNKNOWN, "bad encoding style", null, null); throw badEncodingFault; } } } } /** * Retrieve the DeserializationContext associated with this MessageElement * * @return The DeserializationContext associated with this MessageElement */ public DeserializationContext getDeserializationContext() { return context; } /** !!! TODO : Make sure this handles multiple targets */ protected Deserializer fixupDeserializer; public void setFixupDeserializer(Deserializer dser) { // !!! Merge targets here if already set? fixupDeserializer = dser; } public Deserializer getFixupDeserializer() { return fixupDeserializer; } /** * record the end index of the SAX recording. * @param endIndex end value */ public void setEndIndex(int endIndex) { endEventIndex = endIndex; //context.setRecorder(null); } /** * get the is-root flag * @return true if the element is considered a document root. */ public boolean isRoot() { return _isRoot; } /** * get a saved ID * @return ID or null for no ID */ public String getID() { return id; } /** * get a saved href * @return href or null */ public String getHref() { return href; } /** * get the attributes * @return attributes. If this equals {@link NullAttributes.singleton} it is null * */ public Attributes getAttributesEx() { return attributes; } /** * Returns a duplicate of this node, i.e., serves as a generic copy * constructor for nodes. The duplicate node has no parent; ( * <code>parentNode</code> is <code>null</code>.). * <br>Cloning an <code>Element</code> copies all attributes and their * values, including those generated by the XML processor to represent * defaulted attributes, but this method does not copy any text it * contains unless it is a deep clone, since the text is contained in a * child <code>Text</code> node. Cloning an <code>Attribute</code> * directly, as opposed to be cloned as part of an <code>Element</code> * cloning operation, returns a specified attribute ( * <code>specified</code> is <code>true</code>). Cloning any other type * of node simply returns a copy of this node. * <br>Note that cloning an immutable subtree results in a mutable copy, * but the children of an <code>EntityReference</code> clone are readonly * . In addition, clones of unspecified <code>Attr</code> nodes are * specified. And, cloning <code>Document</code>, * <code>DocumentType</code>, <code>Entity</code>, and * <code>Notation</code> nodes is implementation dependent. * * @param deep If <code>true</code>, recursively clone the subtree under * the specified node; if <code>false</code>, clone only the node * itself (and its attributes, if it is an <code>Element</code>). * @return The duplicate node. */ public Node cloneNode(boolean deep) { try { MessageElement clonedSelf = (MessageElement) cloning(); if (deep) { if (children != null) { for (int i = 0; i < children.size(); i++) { NodeImpl child = (NodeImpl) children.get(i); if (child != null) { // why child can be null? NodeImpl clonedChild = (NodeImpl) child.cloneNode(deep); // deep == true clonedChild.setParent(clonedSelf); clonedChild.setOwnerDocument(getOwnerDocument()); clonedSelf.childDeepCloned(child, clonedChild); } } } } return clonedSelf; } catch (Exception e) { return null; } } // Called when a child is cloned from cloneNode(). // // This is used by sub-classes to update internal state when specific elements // are cloned. protected void childDeepCloned(NodeImpl oldNode, NodeImpl newNode) { } /** * protected clone method (not public) * * copied status * ------------------- * protected String name ; Y * protected String prefix ; Y * protected String namespaceURI ; Y * protected transient Attributes attributes Y * protected String id; Y? * protected String href; Y? * protected boolean _isRoot = true; Y? * protected SOAPEnvelope message = null; N? * protected transient DeserializationContext context; Y? * protected transient QName typeQName = null; Y? * protected Vector qNameAttrs = null; Y? * protected transient SAX2EventRecorder recorder = null; N? * protected int startEventIndex = 0; N? * protected int startContentsIndex = 0; N? * protected int endEventIndex = -1; N? * protected CharacterData textRep = null; Y? * protected MessageElement parent = null; N * public ArrayList namespaces = null; Y * protected String encodingStyle = null; N? * private Object objectValue = null; N? * * @return * @throws CloneNotSupportedException */ protected Object cloning() throws CloneNotSupportedException { try { MessageElement clonedME = null; clonedME = (MessageElement) this.clone(); clonedME.setName(name); clonedME.setNamespaceURI(namespaceURI); clonedME.setPrefix(prefix); // new AttributesImpl will copy all data not set referencing only clonedME.setAllAttributes(new AttributesImpl(attributes)); // clonedME.addNamespaceDeclaration((namespaces.clone()); // cannot do this. since we cannot access the namepace arraylist clonedME.namespaces = new ArrayList(); if (namespaces != null) { for (int i = 0; i < namespaces.size(); i++) { // jeus.util.Logger.directLog( " Debug : namspace.size() = " + namespaces.size()); Mapping namespace = (Mapping) namespaces.get(i); clonedME.addNamespaceDeclaration(namespace.getPrefix(), namespace.getNamespaceURI()); // why exception here!! } } clonedME.children = new ArrayList(); // clear parents relationship to old parent clonedME.parent = null; // clonedME.setObjectValue(objectValue); // how to copy this??? clonedME.setDirty(this._isDirty); if (encodingStyle != null) { clonedME.setEncodingStyle(encodingStyle); } return clonedME; } catch (Exception ex) { return null; } } /** * set all the attributes of this instance * @param attrs a new attributes list */ public void setAllAttributes(Attributes attrs) { attributes = attrs; } /** * remove all children. */ public void detachAllChildren() { removeContents(); } /** * Obtain an Attributes collection consisting of all attributes * for this MessageElement, including namespace declarations. * * @return Attributes collection */ public Attributes getCompleteAttributes() { if (namespaces == null) { return attributes; } AttributesImpl attrs = null; if (attributes == NullAttributes.singleton) { attrs = new AttributesImpl(); } else { attrs = new AttributesImpl(attributes); } for (Iterator iterator = namespaces.iterator(); iterator.hasNext();) { Mapping mapping = (Mapping) iterator.next(); String prefix = mapping.getPrefix(); String nsURI = mapping.getNamespaceURI(); attrs.addAttribute(Constants.NS_URI_XMLNS, prefix, "xmlns:" + prefix, nsURI, "CDATA"); } return attrs; } /** * get the local name of this element * @return name */ public String getName() { return name; } /** * set the local part of this element's name * @param name */ public void setName(String name) { this.name = name; } /** * get the fully qualified name of this element * @return a QName describing the name of thsi element */ public QName getQName() { return new QName(namespaceURI, name); } /** * set the name and namespace of this element * @param qName qualified name */ public void setQName(QName qName) { this.name = qName.getLocalPart(); this.namespaceURI = qName.getNamespaceURI(); } /** * set the namespace URI of the element * @param nsURI new namespace URI */ public void setNamespaceURI(String nsURI) { namespaceURI = nsURI; } /** * get the element's type. * If we are a reference, we look up our target in the context and * return (and cache) its type. * @return */ public QName getType() { // Try to get the type from our target if we're a reference... if (typeQName == null && href != null && context != null) { MessageElement referent = context.getElementByID(href); if (referent != null) { typeQName = referent.getType(); } } return typeQName; } /** * set the element's type * @param qname */ public void setType(QName qname) { typeQName = qname; } /** * get the event recorder * @return recorder or null */ public SAX2EventRecorder getRecorder() { return recorder; } /** * set the event recorder * @param rec */ public void setRecorder(SAX2EventRecorder rec) { recorder = rec; } /** * Get the encoding style. If ours is null, walk up the hierarchy * and use our parent's. Default if we're the root is "". * * @return the currently in-scope encoding style */ public String getEncodingStyle() { if (encodingStyle == null) { if (parent == null) { return ""; } return ((MessageElement) parent).getEncodingStyle(); } return encodingStyle; } /** * remove all chidlren. * All SOAPExceptions which can get thrown in this process are ignored. */ public void removeContents() { // unlink if (children != null) { for (int i = 0; i < children.size(); i++) { try { ((NodeImpl) children.get(i)).setParent(null); } catch (SOAPException e) { log.debug("ignoring", e); } } // empty the collection children.clear(); setDirty(); } } /** * get an iterator over visible prefixes. This includes all declared in * parent elements * @return an iterator. */ public Iterator getVisibleNamespacePrefixes() { Vector prefixes = new Vector(); // Add all parents namespace definitions if (parent != null) { Iterator parentsPrefixes = ((MessageElement) parent).getVisibleNamespacePrefixes(); if (parentsPrefixes != null) { while (parentsPrefixes.hasNext()) { prefixes.add(parentsPrefixes.next()); } } } Iterator mine = getNamespacePrefixes(); if (mine != null) { while (mine.hasNext()) { prefixes.add(mine.next()); } } return prefixes.iterator(); } /** * Sets the encoding style for this <CODE>SOAPElement</CODE> * object to one specified. The semantics of a null value, * as above in getEncodingStyle() are to just use the parent's value, * but null here means set to "". * * @param encodingStyle a <CODE>String</CODE> * giving the encoding style * @throws java.lang.IllegalArgumentException if * there was a problem in the encoding style being set. * @see #getEncodingStyle() getEncodingStyle() */ public void setEncodingStyle(String encodingStyle) throws SOAPException { if (encodingStyle == null) { encodingStyle = ""; } this.encodingStyle = encodingStyle; // Wherever we set the encoding style, map the SOAP-ENC prefix // just for fun (if it's a known style) if (encodingStyle.equals(Constants.URI_SOAP11_ENC)) { addMapping(enc11Mapping); } else if (encodingStyle.equals(Constants.URI_SOAP12_ENC)) { addMapping(enc12Mapping); } } /** * Note that this method will log a error and no-op if there is * a value (set using setObjectValue) in the MessageElement. */ public void addChild(MessageElement el) throws SOAPException { if (objectValue != null) { IllegalStateException exc = new IllegalStateException(Messages.getMessage("valuePresent")); log.error(Messages.getMessage("valuePresent"), exc); throw exc; } initializeChildren(); children.add(el); el.parent = this; } /** * get a list of children * @return a list, or null if there are no children */ public List getChildren() { return children; } /** * set the index point of our content's starting in the * event recording * @param index index value of the first event of our recorder. */ public void setContentsIndex(int index) { startContentsIndex = index; } /** * set a new namespace mapping list * @param namespaces */ public void setNSMappings(ArrayList namespaces) { this.namespaces = namespaces; } /** * get the prefix for a given namespace URI * @param searchNamespaceURI namespace * @return null for null or emtpy uri, null for no match, and the prefix iff there is a match */ public String getPrefix(String searchNamespaceURI) { if ((searchNamespaceURI == null) || ("".equals(searchNamespaceURI))) return null; if (href != null && getRealElement() != null) { return getRealElement().getPrefix(searchNamespaceURI); } for (int i = 0; namespaces != null && i < namespaces.size(); i++) { Mapping map = (Mapping) namespaces.get(i); if (map.getNamespaceURI().equals(searchNamespaceURI)) { return map.getPrefix(); } } if (parent != null) { return ((MessageElement) parent).getPrefix(searchNamespaceURI); } return null; } /** * map from a prefix to a namespace. * Will recurse <i>upward the element tree</i> until we get a match * @param searchPrefix * @return the prefix, or null for no match */ public String getNamespaceURI(String searchPrefix) { if (searchPrefix == null) { searchPrefix = ""; } if (href != null && getRealElement() != null) { return getRealElement().getNamespaceURI(searchPrefix); } for (int i = 0; namespaces != null && i < namespaces.size(); i++) { Mapping map = (Mapping) namespaces.get(i); if (map.getPrefix().equals(searchPrefix)) { return map.getNamespaceURI(); } } if (parent != null) { return ((MessageElement) parent).getNamespaceURI(searchPrefix); } if (log.isDebugEnabled()) { log.debug(Messages.getMessage("noPrefix00", "" + this, searchPrefix)); } return null; } /** * Returns value of the node as an object of registered type. * @return Object of proper type, or null if no mapping could be found. */ public Object getObjectValue() { Object obj = null; try { obj = getObjectValue(null); } catch (Exception e) { log.debug("getValue()", e); } return obj; } /** * Returns value of the node as an object of registered type. * @param cls Class that contains top level deserializer metadata * @return Object of proper type, or null if no mapping could be found. */ public Object getObjectValue(Class cls) throws Exception { if (objectValue == null) { objectValue = getValueAsType(getType(), cls); } return objectValue; } /** * Sets value of this node to an Object. * A serializer needs to be registered for this object class for proper * operation. * <p> * Note that this method will log an error and no-op if there are * any children in the MessageElement or if the MessageElement was * constructed from XML. * @param newValue node's value or null. */ public void setObjectValue(Object newValue) throws SOAPException { if (children != null && !children.isEmpty()) { SOAPException exc = new SOAPException(Messages.getMessage("childPresent")); log.error(Messages.getMessage("childPresent"), exc); throw exc; } if (textRep != null) { SOAPException exc = new SOAPException(Messages.getMessage("xmlPresent")); log.error(Messages.getMessage("xmlPresent"), exc); throw exc; } this.objectValue = newValue; } public Object getValueAsType(QName type) throws Exception { return getValueAsType(type, null); } /** * This is deserialization logic mixed in to our element class. * It is only valid we have a deserializer, which means that we were created * using {@link MessageElement#MessageElement(String, String, String, org.xml.sax.Attributes, org.apache.axis.encoding.DeserializationContext)} * @param type type to look up a deserializer for. * @param cls class to use for looking up the deserializer. This takes precedence over the type field. * @return the value of the deserializer * @throws Exception */ public Object getValueAsType(QName type, Class cls) throws Exception { if (context == null) { throw new Exception(Messages.getMessage("noContext00")); } Deserializer dser = null; if (cls == null) { dser = context.getDeserializerForType(type); } else { dser = context.getDeserializerForClass(cls); } if (dser == null) { throw new Exception(Messages.getMessage("noDeser00", "" + type)); } boolean oldVal = context.isDoneParsing(); context.deserializing(true); context.pushElementHandler(new EnvelopeHandler((SOAPHandler) dser)); publishToHandler((org.xml.sax.ContentHandler) context); context.deserializing(oldVal); return dser.getValue(); } /** * class that represents a qname in a the qNameAttrs vector. */ protected static class QNameAttr { public QName name; public QName value; } /** * add an attribute to the qname vector. This is a separate vector from the * main attribute list. * @param namespace * @param localName * @param value */ public void addAttribute(String namespace, String localName, QName value) { if (qNameAttrs == null) { qNameAttrs = new Vector(); } QNameAttr attr = new QNameAttr(); attr.name = new QName(namespace, localName); attr.value = value; qNameAttrs.addElement(attr); // !!! Add attribute to attributes! } /** * add a normal CDATA/text attribute. * There is no check whether or not the attribute already exists. * @param namespace namespace URI * @param localName local anme * @param value value */ public void addAttribute(String namespace, String localName, String value) { AttributesImpl attributes = makeAttributesEditable(); attributes.addAttribute(namespace, localName, "", "CDATA", value); } /** * add an attribute. * Note that the prefix is not added to our mapping list. * Also, there is no check whether or not the attribute already exists. * @param attrPrefix prefix. * @param namespace namespace URI * @param localName * @param value */ public void addAttribute(String attrPrefix, String namespace, String localName, String value) { AttributesImpl attributes = makeAttributesEditable(); String attrName = localName; if (attrPrefix != null && attrPrefix.length() > 0) { attrName = attrPrefix + ":" + localName; } attributes.addAttribute(namespace, localName, attrName, "CDATA", value); } /** * Set an attribute, adding the attribute if it isn't already present * in this element, and changing the value if it is. Passing null as the * value will cause any pre-existing attribute by this name to go away. */ public void setAttribute(String namespace, String localName, String value) { AttributesImpl attributes = makeAttributesEditable(); int idx = attributes.getIndex(namespace, localName); if (idx > -1) { // Got it, so replace it's value. if (value != null) { attributes.setValue(idx, value); } else { attributes.removeAttribute(idx); } return; } addAttribute(namespace, localName, value); } /** * get the value of an attribute * @param localName * @return the value or null */ public String getAttributeValue(String localName) { if (attributes == null) { return null; } return attributes.getValue(localName); } /** * bind a a new soap envelope. sets the dirty bit. * @param env */ public void setEnvelope(SOAPEnvelope env) { env.setDirty(); message = env; } /** * get our current envelope * @return envelope or null. */ public SOAPEnvelope getEnvelope() { return message; } /** * get the 'real' element -will follow hrefs. * @return the message element or null if there is a href to something * that is not a MessageElemeent. */ public MessageElement getRealElement() { if (href == null) { return this; } Object obj = context.getObjectByRef(href); if (obj == null) { return null; } if (!(obj instanceof MessageElement)) { return null; } return (MessageElement) obj; } /** * get the message element as a document. * This serializes the element to a string and then parses it. * @see #getAsString() * @return * @throws Exception */ public Document getAsDocument() throws Exception { String elementString = getAsString(); Reader reader = new StringReader(elementString); Document doc = XMLUtils.newDocument(new InputSource(reader)); if (doc == null) { throw new Exception(Messages.getMessage("noDoc00", elementString)); } return doc; } /** * get the message element as a string. * This is not a cheap operation, as we have to serialise the * entire message element to the current context, then * convert it to a string. * Nor is it cached; repeated calls repeat the operation. * @return an XML fragment in a string. * @throws Exception if anything went wrong */ public String getAsString() throws Exception { SerializationContext serializeContext = null; StringWriter writer = new StringWriter(); MessageContext msgContext; if (context != null) { msgContext = context.getMessageContext(); } else { msgContext = MessageContext.getCurrentContext(); } serializeContext = new SerializationContext(writer, msgContext); serializeContext.setSendDecl(false); setDirty(false); output(serializeContext); writer.close(); return writer.getBuffer().toString(); } /** * create a DOM from the message element, by * serializing and deserializing the element * @see #getAsString() * @see #getAsDocument() * @return the root document element of the element * @throws Exception */ public Element getAsDOM() throws Exception { return getAsDocument().getDocumentElement(); } /** * replay the sax events to a handler * @param handler * @throws SAXException */ public void publishToHandler(ContentHandler handler) throws SAXException { if (recorder == null) { throw new SAXException(Messages.getMessage("noRecorder00")); } recorder.replay(startEventIndex, endEventIndex, handler); } /** * replay the sax events to a SAX content handles * @param handler * @throws SAXException */ public void publishContents(ContentHandler handler) throws SAXException { if (recorder == null) { throw new SAXException(Messages.getMessage("noRecorder00")); } recorder.replay(startContentsIndex, endEventIndex - 1, handler); } /** This is the public output() method, which will always simply use * the recorded SAX stream for this element if it is available. If * not, this method calls outputImpl() to allow subclasses and * programmatically created messages to serialize themselves. * * @param outputContext the SerializationContext we will write to. */ public final void output(SerializationContext outputContext) throws Exception { if ((recorder != null) && (!_isDirty)) { recorder.replay(startEventIndex, endEventIndex, new SAXOutputter(outputContext)); return; } // Turn QName attributes into strings if (qNameAttrs != null) { for (int i = 0; i < qNameAttrs.size(); i++) { QNameAttr attr = (QNameAttr) qNameAttrs.get(i); QName attrName = attr.name; setAttribute(attrName.getNamespaceURI(), attrName.getLocalPart(), outputContext.qName2String(attr.value)); } } /** * Write the encoding style attribute IF it's different from * whatever encoding style is in scope.... */ if (encodingStyle != null) { MessageContext mc = outputContext.getMessageContext(); SOAPConstants soapConstants = (mc != null) ? mc.getSOAPConstants() : SOAPConstants.SOAP11_CONSTANTS; if (parent == null) { // don't emit an encoding style if its "" (literal) if (!"".equals(encodingStyle)) { setAttribute(soapConstants.getEnvelopeURI(), Constants.ATTR_ENCODING_STYLE, encodingStyle); } } else if (!encodingStyle.equals(((MessageElement) parent).getEncodingStyle())) { setAttribute(soapConstants.getEnvelopeURI(), Constants.ATTR_ENCODING_STYLE, encodingStyle); } } outputImpl(outputContext); } /** * override point -output to a serialization context. * @param outputContext destination. * @throws Exception if something went wrong. */ protected void outputImpl(SerializationContext outputContext) throws Exception { if (textRep != null) { boolean oldPretty = outputContext.getPretty(); outputContext.setPretty(false); if (textRep instanceof CDATASection) { outputContext.writeString("<![CDATA["); outputContext.writeString(textRep.getData()); outputContext.writeString("]]>"); } else if (textRep instanceof Comment) { outputContext.writeString("<!--"); outputContext.writeString(textRep.getData()); outputContext.writeString("-->"); } else if (textRep instanceof Text) { outputContext.writeSafeString(textRep.getData()); } outputContext.setPretty(oldPretty); return; } if (prefix != null) outputContext.registerPrefixForURI(prefix, namespaceURI); if (namespaces != null) { for (Iterator i = namespaces.iterator(); i.hasNext();) { Mapping mapping = (Mapping) i.next(); outputContext.registerPrefixForURI(mapping.getPrefix(), mapping.getNamespaceURI()); } } if (objectValue != null) { outputContext.serialize(new QName(namespaceURI, name), attributes, objectValue); return; } outputContext.startElement(new QName(namespaceURI, name), attributes); if (children != null) { for (Iterator it = children.iterator(); it.hasNext();) { ((NodeImpl) it.next()).output(outputContext); } } outputContext.endElement(); } /** * Generate a string representation by serializing our contents * This is not a lightweight operation, and is repeated whenever * you call this method. * If the serialization fails, an error is logged and the classic * {@link Object#toString()} operation invoked instead. * @return a string representing the class */ public String toString() { try { return getAsString(); } catch (Exception exp) { //couldn't turn to a string. //log it log.error(Messages.getMessage("exception00"), exp); //then hand off to our superclass, which is probably object return super.toString(); } } /** * add a new namespace/prefix mapping * @param map new mapping to add * @todo: this code does not verify that the mapping does not exist already; it * is possible to create duplicate mappings. */ public void addMapping(Mapping map) { if (namespaces == null) { namespaces = new ArrayList(); } namespaces.add(map); } // JAXM SOAPElement methods... /** * add the child element * @param childName uri, prefix and local name of the element to add * @return the child element * @throws SOAPException * @see javax.xml.soap.SOAPElement#addChildElement(javax.xml.soap.Name) */ public SOAPElement addChildElement(Name childName) throws SOAPException { MessageElement child = new MessageElement(childName.getLocalName(), childName.getPrefix(), childName.getURI()); addChild(child); return child; } /** * add a child element in the message element's own namespace * @param localName * @return the child element * @throws SOAPException * @see javax.xml.soap.SOAPElement#addChildElement(String) */ public SOAPElement addChildElement(String localName) throws SOAPException { // Inherit parent's namespace MessageElement child = new MessageElement(getNamespaceURI(), localName); addChild(child); return child; } /** * add a child element * @param localName * @param prefixName * @return the child element * @throws SOAPException * @see javax.xml.soap.SOAPElement#addChildElement(String, String) */ public SOAPElement addChildElement(String localName, String prefixName) throws SOAPException { MessageElement child = new MessageElement(getNamespaceURI(prefixName), localName); child.setPrefix(prefixName); addChild(child); return child; } /** * add a child element * @param localName * @param childPrefix * @param uri * @return the child element * @throws SOAPException * @see javax.xml.soap.SOAPElement#addChildElement(String, String, String) */ public SOAPElement addChildElement(String localName, String childPrefix, String uri) throws SOAPException { MessageElement child = new MessageElement(uri, localName); child.setPrefix(childPrefix); child.addNamespaceDeclaration(childPrefix, uri); addChild(child); return child; } /** * The added child must be an instance of MessageElement rather than * an abitrary SOAPElement otherwise a (wrapped) ClassCastException * will be thrown. * @see javax.xml.soap.SOAPElement#addChildElement(javax.xml.soap.SOAPElement) */ public SOAPElement addChildElement(SOAPElement element) throws SOAPException { try { addChild((MessageElement) element); setDirty(); return element; } catch (ClassCastException e) { throw new SOAPException(e); } } /** * add a text node to the document. * @return ourselves * @see javax.xml.soap.SOAPElement#addTextNode(String) */ public SOAPElement addTextNode(String s) throws SOAPException { try { Text text = getOwnerDocument().createTextNode(s); ((org.apache.axis.message.Text) text).setParentElement(this); return this; } catch (java.lang.IncompatibleClassChangeError e) { Text text = new org.apache.axis.message.Text(s); this.appendChild(text); return this; } catch (ClassCastException e) { throw new SOAPException(e); } } /** * add a new attribute * @param attrName name of the attribute * @param value a string value * @return ourselves * @throws SOAPException * @see javax.xml.soap.SOAPElement#addAttribute(javax.xml.soap.Name, String) */ public SOAPElement addAttribute(Name attrName, String value) throws SOAPException { try { addAttribute(attrName.getPrefix(), attrName.getURI(), attrName.getLocalName(), value); } catch (RuntimeException t) { throw new SOAPException(t); } return this; } /** * create a {@link Mapping} mapping and add to our namespace list. * @param prefix * @param uri * @return * @throws SOAPException for any {@link RuntimeException} caught * @todo for some reason this logic catches all rutime exceptions and * rethrows them as SOAPExceptions. This is unusual behavio, and should * be looked at closely. * @see javax.xml.soap.SOAPElement#addNamespaceDeclaration(String, String) */ public SOAPElement addNamespaceDeclaration(String prefix, String uri) throws SOAPException { try { Mapping map = new Mapping(uri, prefix); addMapping(map); } catch (RuntimeException t) { //TODO: why is this here? Nowhere else do we turn runtimes into SOAPExceptions. throw new SOAPException(t); } return this; } /** * Get the value of an attribute whose namespace and local name are described. * @param attrName qualified name of the attribute * @return the attribute or null if there was no match * @see SOAPElement#getAttributeValue(javax.xml.soap.Name) */ public String getAttributeValue(Name attrName) { return attributes.getValue(attrName.getURI(), attrName.getLocalName()); } /** * Get an interator to all the attributes of the node. * The iterator is over a static snapshot of the node names; if attributes * are added or deleted during the iteration, this iterator will be not * be updated to follow the changes. * @return an iterator of the attributes. * @see javax.xml.soap.SOAPElement#getAllAttributes() */ public Iterator getAllAttributes() { int num = attributes.getLength(); Vector attrs = new Vector(num); for (int i = 0; i < num; i++) { String q = attributes.getQName(i); String prefix = ""; if (q != null) { int idx = q.indexOf(":"); if (idx > 0) { prefix = q.substring(0, idx); } else { prefix = ""; } } attrs.add(new PrefixedQName(attributes.getURI(i), attributes.getLocalName(i), prefix)); } return attrs.iterator(); } // getNamespaceURI implemented above /** * get an iterator of the prefixes. The iterator * does not get updated in response to changes in the namespace list. * @return an iterator over a vector of prefixes * @see javax.xml.soap.SOAPElement#getNamespacePrefixes() */ public Iterator getNamespacePrefixes() { Vector prefixes = new Vector(); for (int i = 0; namespaces != null && i < namespaces.size(); i++) { prefixes.add(((Mapping) namespaces.get(i)).getPrefix()); } return prefixes.iterator(); } /** * get the full name of the element * @return * @see javax.xml.soap.SOAPElement#getElementName() */ public Name getElementName() { return new PrefixedQName(getNamespaceURI(), getName(), getPrefix()); } /** * remove an element * @param attrName name of the element * @return true if the attribute was found and removed. * @see javax.xml.soap.SOAPElement#removeAttribute(javax.xml.soap.Name) */ public boolean removeAttribute(Name attrName) { AttributesImpl attributes = makeAttributesEditable(); boolean removed = false; for (int i = 0; i < attributes.getLength() && !removed; i++) { if (attributes.getURI(i).equals(attrName.getURI()) && attributes.getLocalName(i).equals(attrName.getLocalName())) { attributes.removeAttribute(i); removed = true; } } return removed; } /** * remove a namespace declaration. * @param namespacePrefix * @return true if the prefix was found and removed. * @see javax.xml.soap.SOAPElement#removeNamespaceDeclaration(String) */ public boolean removeNamespaceDeclaration(String namespacePrefix) { makeAttributesEditable(); boolean removed = false; for (int i = 0; namespaces != null && i < namespaces.size() && !removed; i++) { if (((Mapping) namespaces.get(i)).getPrefix().equals(namespacePrefix)) { namespaces.remove(i); removed = true; } } return removed; } /** * get an iterator over the children * This iterator <i>may</i> get confused if changes are made to the * children while the iteration is in progress. * @return an iterator over child elements. * @see javax.xml.soap.SOAPElement#getChildElements() */ public Iterator getChildElements() { initializeChildren(); return children.iterator(); } /** * Convenience method to get the first matching child for a given QName. * * @param qname * @return child element or null * @see javax.xml.soap.SOAPElement#getChildElements() */ public MessageElement getChildElement(QName qname) { if (children != null) { for (Iterator i = children.iterator(); i.hasNext();) { MessageElement child = (MessageElement) i.next(); if (child.getQName().equals(qname)) return child; } } return null; } /** * get an iterator over child elements * @param qname namespace/element name of parts to find. * This iterator is not (currently) susceptible to change in the element * list during its lifetime, though changes in the contents of the elements * are picked up. * @return an iterator. */ public Iterator getChildElements(QName qname) { initializeChildren(); int num = children.size(); Vector c = new Vector(num); for (int i = 0; i < num; i++) { MessageElement child = (MessageElement) children.get(i); Name cname = child.getElementName(); if (cname.getURI().equals(qname.getNamespaceURI()) && cname.getLocalName().equals(qname.getLocalPart())) { c.add(child); } } return c.iterator(); } /** * get an iterator over child elements * @param childName namespace/element name of parts to find. * This iterator is not (currently) susceptible to change in the element * list during its lifetime, though changes in the contents of the elements * are picked up. * @return an iterator. * @see javax.xml.soap.SOAPElement#getChildElements(javax.xml.soap.Name) */ public Iterator getChildElements(Name childName) { return getChildElements(new QName(childName.getURI(), childName.getLocalName())); } //DOM methods /** * @see org.w3c.dom.Element#getTagName() * @return the name of the element */ public String getTagName() { return prefix == null ? name : prefix + ":" + name; } /** * remove a named attribute. * @see org.w3c.dom.Element#removeAttribute(String) * @param attrName name of the attributes * @throws DOMException */ public void removeAttribute(String attrName) throws DOMException { AttributesImpl impl = (AttributesImpl) attributes; int index = impl.getIndex(attrName); if (index >= 0) { AttributesImpl newAttrs = new AttributesImpl(); // copy except the removed attribute for (int i = 0; i < impl.getLength(); i++) { // shift after removal if (i != index) { String uri = impl.getURI(i); String local = impl.getLocalName(i); String qname = impl.getQName(i); String type = impl.getType(i); String value = impl.getValue(i); newAttrs.addAttribute(uri, local, qname, type, value); } } // replace it attributes = newAttrs; } } /** * test for an attribute existing * @param attrName name of attribute (or null) * @return true if it exists * Note that the behaviour for a null parameter (returns false) is not guaranteed in future * @see org.w3c.dom.Element#hasAttribute(String) */ public boolean hasAttribute(String attrName) { if (attrName == null) // Do I have to send an exception? attrName = ""; for (int i = 0; i < attributes.getLength(); i++) { if (attrName.equals(attributes.getQName(i))) return true; } return false; } /** * get an attribute by name * @param attrName of attribute * @return the attribute value or null * @see org.w3c.dom.Element#getAttribute(String) */ public String getAttribute(String attrName) { return attributes.getValue(attrName); } /** * Remove an attribute. If the removed * attribute has a default value it is immediately replaced. The * replacing attribute has the same namespace URI and local name, as * well as the original prefix. * If there is no matching attribute, the operation is a no-op. * @see org.w3c.dom.Element#removeAttributeNS(String, String) * @param namespace namespace of attr * @param localName local name * @throws DOMException */ public void removeAttributeNS(String namespace, String localName) throws DOMException { makeAttributesEditable(); Name name = new PrefixedQName(namespace, localName, null); removeAttribute(name); } /** * set or update an attribute. * @see org.w3c.dom.Element#setAttribute(String, String) * @param name attribute name * @param value attribute value * @throws DOMException */ public void setAttribute(String name, String value) throws DOMException { AttributesImpl impl = makeAttributesEditable(); int index = impl.getIndex(name); if (index < 0) { // not found String uri = ""; String localname = name; String qname = name; String type = "CDDATA"; impl.addAttribute(uri, localname, qname, type, value); } else { // found impl.setLocalName(index, value); } } /** * Test for an attribute * @see org.w3c.dom.Element#hasAttributeNS(String, String) * @param namespace * @param localName * @return */ public boolean hasAttributeNS(String namespace, String localName) { if (namespace == null) { namespace = ""; } if (localName == null) // Do I have to send an exception? or just return false { localName = ""; } for (int i = 0; i < attributes.getLength(); i++) { if (namespace.equals(attributes.getURI(i)) && localName.equals(attributes.getLocalName(i))) return true; } return false; } /** * This unimplemented operation is meand to return an attribute as a node * @see org.w3c.dom.Element#getAttributeNode(String) * @param attrName * @return null, always. * @todo Fix this for SAAJ 1.2 Implementation. marked as deprecated to warn people * it is broken * @deprecated this is not implemented */ public Attr getAttributeNode(String attrName) { return null; } /** * remove a an attribue * @param oldAttr * @return oldAttr * @throws DOMException */ public Attr removeAttributeNode(Attr oldAttr) throws DOMException { makeAttributesEditable(); Name name = new PrefixedQName(oldAttr.getNamespaceURI(), oldAttr.getLocalName(), oldAttr.getPrefix()); removeAttribute(name); return oldAttr; } /** * set the attribute node. * @see org.w3c.dom.Element#setAttributeNode(org.w3c.dom.Attr) * @param newAttr * @return newAttr * @throws DOMException * @deprecated this is not implemented * @todo implement */ public Attr setAttributeNode(Attr newAttr) throws DOMException { return newAttr; } /** * set an attribute as a node * @see org.w3c.dom.Element#setAttributeNodeNS(org.w3c.dom.Attr) * @todo implement properly. * @param newAttr * @return null * @throws DOMException */ public Attr setAttributeNodeNS(Attr newAttr) throws DOMException { //attributes. AttributesImpl attributes = makeAttributesEditable(); // how to convert to DOM ATTR attributes.addAttribute(newAttr.getNamespaceURI(), newAttr.getLocalName(), newAttr.getLocalName(), "CDATA", newAttr.getValue()); return null; } /** * @see org.w3c.dom.Element#getElementsByTagName(String) * @param tagName tag to look for. * @return a list of elements */ public NodeList getElementsByTagName(String tagName) { NodeListImpl nodelist = new NodeListImpl(); for (int i = 0; children != null && i < children.size(); i++) { if (children.get(i) instanceof Node) { Node el = (Node) children.get(i); if (el.getLocalName() != null && el.getLocalName().equals(tagName)) nodelist.addNode(el); if (el instanceof Element) { NodeList grandchildren = ((Element) el).getElementsByTagName(tagName); for (int j = 0; j < grandchildren.getLength(); j++) { nodelist.addNode(grandchildren.item(j)); } } } } return nodelist; } /** * get the attribute with namespace/local name match. * @see org.w3c.dom.Element#getAttributeNS(String, String) * @param namespaceURI namespace * @param localName name * @return string value or null if not found * @todo: this could be refactored to use getAttributeValue() */ public String getAttributeNS(String namespaceURI, String localName) { if (namespaceURI == null) { namespaceURI = ""; } for (int i = 0; i < attributes.getLength(); i++) { if (attributes.getURI(i).equals(namespaceURI) && attributes.getLocalName(i).equals(localName)) { return attributes.getValue(i); } } return null; } /** * set an attribute or alter an existing one * @see org.w3c.dom.Element#setAttributeNS(String, String, String) * @param namespaceURI namepsace * @param qualifiedName qualified name of the attribue * @param value value * @throws DOMException */ public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException { AttributesImpl attributes = makeAttributesEditable(); String localName = qualifiedName.substring(qualifiedName.indexOf(":") + 1, qualifiedName.length()); if (namespaceURI == null) { namespaceURI = "intentionalNullURI"; } attributes.addAttribute(namespaceURI, localName, qualifiedName, "CDATA", value); } /** * @see org.w3c.dom.Element#getAttributeNS(String, String) * @deprecated not implemented! * @param namespace namespace * @param localName local name * @return null */ public Attr getAttributeNodeNS(String namespace, String localName) { return null; //TODO: Fix this for SAAJ 1.2 Implementation } /** * @see org.w3c.dom.Element#getElementsByTagNameNS(String, String) * @param namespace namespace * @param localName local name of element * @return (potentially empty) list of elements that match the (namespace,localname) tuple */ public NodeList getElementsByTagNameNS(String namespace, String localName) { return getElementsNS(this, namespace, localName); } /** * helper method for recusively getting the element that has namespace URI and localname * @param parentElement parent element * @param namespace namespace * @param localName local name of element * @return (potentially empty) list of elements that match the (namespace,localname) tuple */ protected NodeList getElementsNS(org.w3c.dom.Element parentElement, String namespace, String localName) { NodeList children = parentElement.getChildNodes(); NodeListImpl matches = new NodeListImpl(); for (int i = 0; i < children.getLength(); i++) { if (children.item(i) instanceof Text) { continue; } Element child = (Element) children.item(i); if (namespace.equals(child.getNamespaceURI()) && localName.equals(child.getLocalName())) { matches.addNode(child); } // search the grand-children. matches.addNodeList(child.getElementsByTagNameNS(namespace, localName)); } return matches; } /** * get a child node * @param index index value * @return child or null for out of range value * @see org.w3c.dom.NodeList#item(int) */ public Node item(int index) { if (children != null && children.size() > index) { return (Node) children.get(index); } else { return null; } } /** * The number of nodes in the list. The range of valid child node indices * is 0 to <code>length-1</code> inclusive. * @return number of children * @since SAAJ 1.2 : Nodelist Interface * @see org.w3c.dom.NodeList#getLength() */ public int getLength() { return (children == null) ? 0 : children.size(); } // setEncodingStyle implemented above // getEncodingStyle() implemented above protected MessageElement findElement(Vector vec, String namespace, String localPart) { if (vec.isEmpty()) { return null; } QName qname = new QName(namespace, localPart); Enumeration e = vec.elements(); MessageElement element; while (e.hasMoreElements()) { element = (MessageElement) e.nextElement(); if (element.getQName().equals(qname)) { return element; } } return null; } /** * equality test. Does a string match of the two message elements, * so is fairly brute force. * @see #toString() * @param obj * @return */ public boolean equals(Object obj) { if (obj == null || !(obj instanceof MessageElement)) { return false; } if (this == obj) { return true; } if (!this.getLocalName().equals(((MessageElement) obj).getLocalName())) { return false; } return toString().equals(obj.toString()); } /** * recursively copy. * Note that this does not reset many of our fields, and must be used with caution. * @param element */ private void copyNode(org.w3c.dom.Node element) { copyNode(this, element); } /** * recursive copy * @param dest element to copy into * @param source child element */ private void copyNode(MessageElement dest, org.w3c.dom.Node source) { dest.setPrefix(source.getPrefix()); if (source.getLocalName() != null) { dest.setQName(new QName(source.getNamespaceURI(), source.getLocalName())); } else { dest.setQName(new QName(source.getNamespaceURI(), source.getNodeName())); } NamedNodeMap attrs = source.getAttributes(); for (int i = 0; i < attrs.getLength(); i++) { Node att = attrs.item(i); if (att.getNamespaceURI() != null && att.getPrefix() != null && att.getNamespaceURI().equals(Constants.NS_URI_XMLNS) && "xmlns".equals(att.getPrefix())) { Mapping map = new Mapping(att.getNodeValue(), att.getLocalName()); dest.addMapping(map); } if (att.getLocalName() != null) { dest.addAttribute(att.getPrefix(), (att.getNamespaceURI() != null ? att.getNamespaceURI() : ""), att.getLocalName(), att.getNodeValue()); } else if (att.getNodeName() != null) { dest.addAttribute(att.getPrefix(), (att.getNamespaceURI() != null ? att.getNamespaceURI() : ""), att.getNodeName(), att.getNodeValue()); } } NodeList children = source.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if (child.getNodeType() == TEXT_NODE || child.getNodeType() == CDATA_SECTION_NODE || child.getNodeType() == COMMENT_NODE) { org.apache.axis.message.Text childElement = new org.apache.axis.message.Text((CharacterData) child); dest.appendChild(childElement); } else { MessageElement childElement = new MessageElement(); dest.appendChild(childElement); copyNode(childElement, child); } } } /** * Get the value of the doc as a string. * This uses {@link #getAsDOM()} so is a heavyweight operation. * @return the value of any child node, or null if there is no node/something went * wrong during serialization. If the first child is text, the return value * is the text itself. * @see javax.xml.soap.Node#getValue() ; */ public String getValue() { /*--- Fix for AXIS-1817 if ((recorder != null) && (!_isDirty)) { StringWriter writer = new StringWriter(); TextSerializationContext outputContext = new TextSerializationContext(writer); try { recorder.replay(startEventIndex, endEventIndex, new SAXOutputter(outputContext)); } catch (Exception t) { log.debug("getValue()", t); return null; } String value = writer.toString(); return (value.length() == 0) ? null : value; } ---*/ if (textRep != null) { // weird case: error? return textRep.getNodeValue(); } if (objectValue != null) { return getValueDOM(); } for (Iterator i = getChildElements(); i.hasNext();) { org.apache.axis.message.NodeImpl n = (org.apache.axis.message.NodeImpl) i.next(); if (n instanceof org.apache.axis.message.Text) { org.apache.axis.message.Text textNode = (org.apache.axis.message.Text) n; return textNode.getNodeValue(); } } return null; } protected String getValueDOM() { try { Element element = getAsDOM(); if (element.hasChildNodes()) { Node node = element.getFirstChild(); if (node.getNodeType() == Node.TEXT_NODE) { return node.getNodeValue(); } } } catch (Exception t) { log.debug("getValue()", t); } return null; } public void setValue(String value) { // if possible, get objectValue in sync with Node value if (children == null) { try { setObjectValue(value); } catch (SOAPException soape) { log.debug("setValue()", soape); } } super.setValue(value); } public Document getOwnerDocument() { Document doc = null; if (context != null && context.getEnvelope() != null && context.getEnvelope().getOwnerDocument() != null) { doc = context.getEnvelope().getOwnerDocument(); } if (doc == null) { doc = super.getOwnerDocument(); } if (doc == null) { doc = new SOAPDocumentImpl(null); } return doc; } }