Package org.apache.axis.message

Source Code of org.apache.axis.message.MessageElement

/*
* 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.SerializationContext;
import org.apache.axis.enum.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.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 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.
*/
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()
    {
    }

    public MessageElement(String namespace, String localPart)
    {
        namespaceURI = namespace;
        name = localPart;
    }

    public MessageElement(String localPart, String prefix, String namespace)
    {
        this.namespaceURI = namespace;
        this.name = localPart;
        this.prefix = prefix;
        addMapping(new Mapping(namespace, prefix));
    }

    public MessageElement(Name eltName)
    {
        this(eltName.getLocalName(),eltName.getPrefix(), eltName.getURI());
    }

    public MessageElement(String namespace, String localPart, Object value)
    {
        this(namespace, localPart);
        objectValue = value;
    }

    public MessageElement(QName name)
    {
        this(name.getNamespaceURI(), name.getLocalPart());
    }

    public MessageElement(QName name, Object value)
    {
        this(name.getNamespaceURI(), name.getLocalPart());
        objectValue = value;
    }

    public MessageElement(Element elem)
    {
        namespaceURI = elem.getNamespaceURI();
        name = elem.getLocalName();
        copyNode(elem);
    }

    public MessageElement(CharacterData text)
    {
        textRep = text;
        namespaceURI = text.getNamespaceURI();
        name = text.getLocalName();
    }

    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;

            typeQName = context.getTypeFromAttributes(namespace,
                                                      localPart,
                                                      attributes);

            String rootVal = attributes.getValue(Constants.URI_DEFAULT_SOAP_ENC, Constants.ATTR_ROOT);
            if (rootVal != null)
                _isRoot = rootVal.equals("1");

            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
     */
    Deserializer fixupDeserializer;

    public void setFixupDeserializer(Deserializer dser)
    {
        // !!! Merge targets here if already set?
        fixupDeserializer = dser;
    }

    public Deserializer getFixupDeserializer()
    {
        return fixupDeserializer;
    }

    public void setEndIndex(int endIndex)
    {
        endEventIndex = endIndex;
        //context.setRecorder(null);
    }

    public boolean isRoot() { return _isRoot; }
    public String getID() { return id; }

    public String getHref() { return href; }

    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) clonning();

            if(deep == true){
                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(soapPart);
                        }
                    }
                }
            }
            return clonedSelf;
        }
        catch(Exception e){
            return null;
        }
    }
    /**
     *  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 clonning() 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(new String(encodingStyle));
            }
            return clonedME;
        }catch(Exception ex){
            return null;
        }
    }

    // called in MESerialaizationContext
    public void setAllAttributes(Attributes attrs){
        attributes = attrs;
    }

    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;
    }

    public String getName() { return( name ); }
    public void setName(String name) { this.name = name; }

    public QName getQName() { return new QName(namespaceURI, name); }
    public void setQName(QName qName) {
        this.name = qName.getLocalPart();
        this.namespaceURI = qName.getNamespaceURI();
    }

    public void setNamespaceURI(String nsURI) { namespaceURI = nsURI; }

    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;
    }

    public void setType(QName qname) {
        typeQName = qname;
    }

    public SAX2EventRecorder getRecorder() { return recorder; }
    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;
    }

    public void removeContents() {
        // unlink
        if(children != null) {
            for(int i = 0; i < children.size(); i++){
                try{
                    ((NodeImpl)children.get(i)).setParent(null);
                }catch(Exception e){
                }
            }
            // empty the collection
            children.clear();
            setDirty(true);
        }
    }

    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) {
            SOAPException exc =
                new SOAPException(Messages.getMessage("valuePresent"));
            log.error(Messages.getMessage("valuePresent"), exc);
            throw exc;
        }
        initializeChildren();
        children.add(el);
        el.parent = this;
    }

    public List getChildren()
    {
        return children;
    }

    public void setContentsIndex(int index)
    {
        startContentsIndex = index;
    }

    public void setNSMappings(ArrayList namespaces)
    {
        this.namespaces = namespaces;
    }

    public String getPrefix(String namespaceURI) {
        if ((namespaceURI == null) || (namespaceURI.equals("")))
            return null;

        if (href != null && getRealElement() != null) {
            return getRealElement().getPrefix(namespaceURI);
        }

        for (int i = 0; namespaces != null && i < namespaces.size(); i++) {
            Mapping map = (Mapping)namespaces.get(i);
            if (map.getNamespaceURI().equals(namespaceURI))
                return map.getPrefix();
        }

        if (parent != null)
            return ((MessageElement)parent).getPrefix(namespaceURI);

        return null;
    }

    public String getNamespaceURI(String prefix) {
        if (prefix == null)
            prefix = "";

        if (href != null && getRealElement() != null) {
            return getRealElement().getNamespaceURI(prefix);
        }

        for (int i = 0; namespaces != null && i < namespaces.size(); i++) {
            Mapping map = (Mapping)namespaces.get(i);
            if (map.getPrefix().equals(prefix)) {
                return map.getNamespaceURI();
            }
        }

        if (parent != null)
            return ((MessageElement)parent).getNamespaceURI(prefix);

        if (log.isDebugEnabled()) {
            log.debug(Messages.getMessage("noPrefix00", "" + this, prefix));
        }

        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);
    }

    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();
    }

    protected static class QNameAttr {
        QName name;
        QName 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!
    }

    public void addAttribute(String namespace, String localName,
                             String value)
    {
        AttributesImpl attributes = makeAttributesEditable();
        attributes.addAttribute(namespace, localName, "", "CDATA",
                                value);
    }

    public void addAttribute(String prefix, String namespace, String localName,
                             String value)
    {
        AttributesImpl attributes = makeAttributesEditable();
        String attrName = localName;
        if (prefix != null && prefix.length() > 0) {
            attrName = prefix + ":" + 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);
    }

    public String getAttributeValue(String localName)
    {
        if (attributes == null) {
           return null;
        }
        return attributes.getValue(localName);
    }

    public void setEnvelope(SOAPEnvelope env)
    {
        env.setDirty(true);
        message = env;
    }

    public SOAPEnvelope getEnvelope()
    {
        return message;
    }

    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;
    }

    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;
    }

    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);
        output(serializeContext);
        writer.close();

        return writer.getBuffer().toString();
    }

    public Element getAsDOM() throws Exception
    {
        return getAsDocument().getDocumentElement();
    }

    public void publishToHandler(ContentHandler handler) throws SAXException
    {
        if (recorder == null)
            throw new SAXException(Messages.getMessage("noRecorder00"));

        recorder.replay(startEventIndex, endEventIndex, handler);
    }

    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 context the SerializationContext we will write to.
     */
    public final void output(SerializationContext context) throws Exception
    {
        if ((recorder != null) && (!_isDirty)) {
            recorder.replay(startEventIndex,
                            endEventIndex,
                            new SAXOutputter(context));
            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(),
                             context.qName2String(attr.value));
            }
        }

        /**
         * Write the encoding style attribute IF it's different from
         * whatever encoding style is in scope....
         */
        if (encodingStyle != null) {
            MessageContext mc = context.getMessageContext();
            SOAPConstants soapConstants = (mc != null) ?
                                            mc.getSOAPConstants() :
                                            SOAPConstants.SOAP11_CONSTANTS;
            if (parent == null) {
                // don't emit an encoding style if its "" (literal)
                if (!encodingStyle.equals("")) {
                    setAttribute(soapConstants.getEnvelopeURI(),
                                 Constants.ATTR_ENCODING_STYLE,
                                 encodingStyle);
                }
            } else if (!encodingStyle.equals(((MessageElement)parent).getEncodingStyle())) {
                setAttribute(soapConstants.getEnvelopeURI(),
                             Constants.ATTR_ENCODING_STYLE,
                             encodingStyle);
            }
        }

        outputImpl(context);
    }

    /** Subclasses can override
     */
    protected void outputImpl(SerializationContext context) throws Exception
    {
        if (textRep != null) {
            boolean oldPretty = context.getPretty();
            context.setPretty(false);
            if (textRep instanceof CDATASection) {
                context.writeString("<![CDATA[");
                context.writeString(((Text)textRep).getData());
                context.writeString("]]>");
            } else if (textRep instanceof Comment) {
                context.writeString("<!--");
                context.writeString(((CharacterData)textRep).getData());
                context.writeString("-->");
            } else if (textRep instanceof Text) {
                context.writeSafeString(((Text)textRep).getData());
            }
            context.setPretty(oldPretty);
            return;
        }

        if (prefix != null)
            context.registerPrefixForURI(prefix, namespaceURI);

        if (namespaces != null) {
            for (Iterator i = namespaces.iterator(); i.hasNext();) {
                Mapping mapping = (Mapping) i.next();
                context.registerPrefixForURI(mapping.getPrefix(), mapping.getNamespaceURI());
            }
        }

        if (objectValue != null) {
            context.serialize(new QName(namespaceURI, name),
                              attributes,
                              objectValue, null, false, null);
            return;
        }

        context.startElement(new QName(namespaceURI, name), attributes);
        if (children != null) {
            for (Iterator it = children.iterator(); it.hasNext();) {
                ((NodeImpl)it.next()).output(context);
            }
        }
        context.endElement();
    }

    public String toString() {
        try {
            return getAsString();
        }
        catch( Exception exp ) {
            log.error(Messages.getMessage("exception00"), exp);
            return null;
        }
    }

    public void addMapping(Mapping map) {
        if (namespaces == null)
            namespaces = new ArrayList();
        namespaces.add(map);
    }

    // JAXM SOAPElement methods...

    public SOAPElement addChildElement(Name name) throws SOAPException {
        MessageElement child = new MessageElement(name.getLocalName(),
                                                  name.getPrefix(),
                                                  name.getURI());
        addChild(child);
        return child;
    }

    public SOAPElement addChildElement(String localName) throws SOAPException {
        // Inherit parent's namespace
        MessageElement child = new MessageElement(getNamespaceURI(),
                                                  localName);
        addChild(child);
        return child;
    }

    public SOAPElement addChildElement(String localName,
                                       String prefix) throws SOAPException {
        MessageElement child = new MessageElement(getNamespaceURI(prefix),
                                                  localName);
        child.setPrefix(prefix);
        addChild(child);
        return child;
    }

    public SOAPElement addChildElement(String localName,
                                       String prefix,
                                       String uri) throws SOAPException {
        MessageElement child = new MessageElement(uri, localName);
        child.setPrefix(prefix);
        child.addNamespaceDeclaration(prefix, 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.
     */
    public SOAPElement addChildElement(SOAPElement element)
        throws SOAPException {
        try {
            addChild((MessageElement)element);
            setDirty(true);
            return element;
        } catch (ClassCastException e) {
            throw new SOAPException(e);
        }
    }

    /**
     * Text nodes are not supported.
     */
    public SOAPElement addTextNode(String s) throws SOAPException {
        Text text = null;
        if (context != null && context.getEnvelope() != null &&
                context.getEnvelope().getOwnerDocument() != null) {
            Document doc = context.getEnvelope().getOwnerDocument();
            text = doc.createTextNode(s);
        }
        if (text == null) {
            text = new org.apache.axis.message.Text(s);
        }
        try {
             appendChild(text);
            return this;
        } catch (ClassCastException e) {
            throw new SOAPException(e);
        }
    }

    public SOAPElement addAttribute(Name name, String value)
        throws SOAPException {
        try {
            addAttribute(name.getPrefix(), name.getURI(), name.getLocalName(), value);
        } catch (RuntimeException t) {
            throw new SOAPException(t);
        }
        return this;
    }

    public SOAPElement addNamespaceDeclaration(String prefix,
                                               String uri)
        throws SOAPException {
        try {
            Mapping map = new Mapping(uri, prefix);
            addMapping(map);
        } catch (RuntimeException t) {
            throw new SOAPException(t);
        }
        return this;
    }

    public String getAttributeValue(Name name) {
        return attributes.getValue(name.getURI(), name.getLocalName());
    }

    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

    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();
    }

    public Name getElementName() {
        return new PrefixedQName(getNamespaceURI(), getName(), getPrefix());
    }

    public boolean removeAttribute(Name name) {
        AttributesImpl attributes = makeAttributesEditable();
        boolean removed = false;

        for (int i = 0; i < attributes.getLength() && !removed; i++) {
            if (attributes.getURI(i).equals(name.getURI()) &&
                attributes.getLocalName(i).equals(name.getLocalName())) {
                attributes.removeAttribute(i);
                removed = true;
            }
        }
        return removed;
    }

    public boolean removeNamespaceDeclaration(String prefix) {
        makeAttributesEditable();
        boolean removed = false;

        for (int i = 0; namespaces != null && i < namespaces.size() && !removed; i++) {
            if (((Mapping)namespaces.get(i)).getPrefix().equals(prefix)) {
                namespaces.remove(i);
                removed = true;
            }
        }
        return removed;
    }

    public Iterator getChildElements() {
        initializeChildren();
        return children.iterator();
    }

    /**
     * Convenience method to get the first matching child for a given QName.
     *
     * @param qname
     * @return
     */
    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;
    }

    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();
    }

    public Iterator getChildElements(Name name) {
        return getChildElements(new QName(name.getURI(), name.getLocalName()));
    }

    public String getTagName() {
        return prefix == null ? name : prefix + ":" + name;
    }

    public void removeAttribute(String name) throws DOMException {
        AttributesImpl impl =  (AttributesImpl)attributes;
        int index = impl.getIndex(name);
        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;
        }
    }

    public boolean hasAttribute(String name) {
        if(name == null// Do I have to send an exception?
            name = "";

        for(int i = 0; i < attributes.getLength(); i++){
            if(name.equals(attributes.getQName(i)))
                return true;
        }
        return false;
    }

    public String getAttribute(String name) {
        return attributes.getValue(name);
    }

    public void removeAttributeNS(String namespaceURI, String localName) throws DOMException {
        makeAttributesEditable();
        Name name =  new PrefixedQName(namespaceURI, localName, null);
        removeAttribute(name);
    }

    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);
        }
    }

    public boolean hasAttributeNS(String namespaceURI, String localName) {
        if(namespaceURI == null)
            namespaceURI ="";
        if(localName == null// Do I have to send an exception? or just return false
            localName = "";

        for(int i = 0; i < attributes.getLength(); i++){
            if( namespaceURI.equals(attributes.getURI(i))
                    && localName.equals(attributes.getLocalName(i)))
                return true;
        }
        return false;
    }

    public Attr getAttributeNode(String name) {
        return null//TODO: Fix this for SAAJ 1.2 Implementation
    }

    public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
        makeAttributesEditable();
        Name name =  new PrefixedQName(oldAttr.getNamespaceURI(), oldAttr.getLocalName(), oldAttr.getPrefix());
        removeAttribute(name);
        return oldAttr;
    }

    public Attr setAttributeNode(Attr newAttr) throws DOMException {
        return newAttr;
    }

    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;
    }

    public NodeList getElementsByTagName(String name) {
        //use this MessageElement class for Nodelist store
        MessageElement nodelist = new MessageElement();

        try{
            if(children != null){
                // add 2nd Generation
                for(int i =0; i < children.size(); i++){
                    nodelist.addChild((MessageElement)children.get(i));
                }
                // add 3rd Generation
                for(int i =0; i < children.size(); i++){
                    MessageElement child = (MessageElement)children.get(i);
                    NodeList grandsons = child.getElementsByTagName(name);
                    for(int j =0; j < children.size(); j++){
                        nodelist.addChild((MessageElement)grandsons.item(j));
                    }
                }
            }
        }catch(SOAPException se){
            // Shame on me
        }
        return nodelist;
    }

    public String getAttributeNS(String namespaceURI, String localName) {
        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;
    }

    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);
    }

    public Attr getAttributeNodeNS(String namespaceURI, String localName) {
        return null//TODO: Fix this for SAAJ 1.2 Implementation
    }

    public NodeList getElementsByTagNameNS(String namespaceURI,
                                           String localName)
    {
        return getElementsNS(this,namespaceURI,localName);
    }

    /**
     * helper method for recusively getting the element that has namespace URI and localname
     */
    protected NodeList getElementsNS(org.w3c.dom.Element parent,
                                     String namespaceURI, String localName)
    {
        NodeList children = parent.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 (namespaceURI.equals(child.getNamespaceURI()) &&
                    localName.equals(child.getLocalName())) {
                matches.addNode(child);
            }
            // search the grand-children.
            matches.addNodeList(child.getElementsByTagNameNS(namespaceURI,
                    localName));
        }
        return matches;
    }

    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.
     *
     * @since SAAJ 1.2 : Nodelist Interface
     */
    public int getLength()
    {
        return (children == null) ? 0 : children.size();
    }

    // setEncodingStyle implemented above

    // getEncodingStyle() implemented above

    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;
    }

    public boolean equals(Object obj)
    {
        if (obj == null || !(obj instanceof MessageElement))
            return false;
        return toString().equals(obj.toString());
    }

    private void copyNode(org.w3c.dom.Node element) {
        copyNode(this, element);
    }

    private void copyNode(MessageElement parent, org.w3c.dom.Node element)
    {
        parent.setPrefix(element.getPrefix());
        if(element.getLocalName() != null) {
            parent.setQName(new QName(element.getNamespaceURI(), element.getLocalName()));
        }

        org.w3c.dom.NamedNodeMap attrs = element.getAttributes();
        for(int i = 0; i < attrs.getLength(); i++){
            org.w3c.dom.Node att = attrs.item(i);
        if (att.getNamespaceURI() != null &&
                att.getPrefix() != null &&
                att.getNamespaceURI().equals(Constants.NS_URI_XMLNS) &&
                att.getPrefix().equals("xmlns")) {
                Mapping map = new Mapping(att.getNodeValue(), att.getLocalName());
                addMapping(map);
            }
            if(att.getLocalName() != null) {
                parent.addAttribute(att.getPrefix(),
                        att.getNamespaceURI(),
                        att.getLocalName(),
                        att.getNodeValue());
            } else if (att.getNodeName() != null) {
                parent.addAttribute(att.getPrefix(),
                        att.getNamespaceURI(),
                        att.getNodeName(),
                        att.getNodeValue());
            }
        }

        org.w3c.dom.NodeList children = element.getChildNodes();
        for(int i = 0; i < children.getLength(); i++){
            org.w3c.dom.Node child = children.item(i);
            if(child.getNodeType()==TEXT_NODE ||
               child.getNodeType()==CDATA_SECTION_NODE ||
               child.getNodeType()==COMMENT_NODE ) {
                MessageElement childElement = new MessageElement((CharacterData)child);
                parent.appendChild(childElement);
            } else {
                PrefixedQName qname = new PrefixedQName(child.getNamespaceURI(),
                        child.getLocalName(),
                        child.getPrefix());
                MessageElement childElement = new MessageElement(qname);
                parent.appendChild(childElement);
                copyNode(childElement, child);
            }
        }
    }

    public String getValue() {
        try {
            Element element = getAsDOM();
            if(element.hasChildNodes()){
                org.w3c.dom.Node node = element.getFirstChild();
                if(node.getNodeType()==org.w3c.dom.Node.TEXT_NODE){
                    return node.getNodeValue();
                }
            }
        } catch (Exception t){
            log.debug("getValue()", t);
        }
        return null;
    }
}
TOP

Related Classes of org.apache.axis.message.MessageElement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.