Package org.apache.axis.encoding

Source Code of org.apache.axis.encoding.SerializationContext

package org.apache.axis.encoding;

/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Axis" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

import java.io.*;
import java.util.*;
import org.xml.sax.*;
import org.xml.sax.helpers.AttributesImpl;
import org.w3c.dom.*;

import org.apache.axis.AxisEngine;
import org.apache.axis.Constants;
import org.apache.axis.message.*;
import org.apache.axis.utils.*;
import org.apache.axis.MessageContext;
import org.apache.axis.encoding.ServiceDescription;

/** Manage a serialization, including keeping track of namespace mappings
* and element stacks.
*
* WARNING : HIGHLY PRELIMINARY!!!
*
* @author Glen Daniels (gdaniels@macromedia.com)
*/
public class SerializationContext
{
    private static final boolean DEBUG_LOG = false;
   
    public NSStack nsStack = new NSStack();
                                       
    boolean writingStartTag = false;
    boolean onlyXML = true;
    int indent=0;
    boolean startOfDocument = true;
   
    Stack elementStack = new Stack();
    Writer writer;
   
    int lastPrefixIndex = 1;
   
    private MessageContext msgContext;
   
    /**
     * Should the XML be "pretty" printed on serialization?  If false, the
     * XML will be sent out verbatim.  If true, ignorable white space may be
     * inserted or removed.
     */
    private boolean pretty = false;

    public boolean getPretty() {
        return pretty;
    }

    public void setPretty(boolean pretty) {
        this.pretty = pretty;
    }

    /**
     * Should I write out objects as multi-refs?
     *
     * !!! For now, this is an all-or-nothing flag.  Either ALL objects will
     * be written in-place as hrefs with the full serialization at the end
     * of the body, or we'll write everything inline (potentially repeating
     * serializations of identical objects).
     */
    private boolean doMultiRefs = false;
   
    /**
     * Should I send an XML declaration?
     */
    private boolean sendXMLDecl = true;

    /**
     * Should I send xsi:type attributes?
     */
    private boolean sendXSIType = true;

    /**
     * A place to hold objects we cache for multi-ref serialization, and
     * remember the IDs we assigned them.
     */
    private HashMap multiRefValues = null;
    private int multiRefIndex = -1;
   
    /**
     * These two let us deal with multi-level object graphs for multi-ref
     * serialization.  Each time around the serialization loop, we'll fill
     * in any new objects into the secondLevelObjects vector, and then write
     * those out the same way the next time around.
     */
    private Object currentSer = null;
    private HashSet secondLevelObjects = null;
   
    public SerializationContext(Writer writer, MessageContext msgContext)
    {
        this.writer = writer;
        this.msgContext = msgContext;
        if (msgContext==null) throw new NullPointerException();
        AxisEngine engine = msgContext.getAxisEngine();
        Boolean shouldSendDecl = (Boolean)engine.getOption(
                                                  AxisEngine.PROP_XML_DECL);
        if (shouldSendDecl != null)
            sendXMLDecl = shouldSendDecl.booleanValue();
        Boolean shouldSendMultiRefs = (Boolean)engine.getOption(
                                                  AxisEngine.PROP_DOMULTIREFS);
        if (shouldSendMultiRefs != null)
            doMultiRefs = shouldSendMultiRefs.booleanValue();

        ServiceDescription sd = msgContext.getServiceDescription();
        if (sd != null) {
            sendXSIType = sd.getSendTypeAttr();
        }
    }
   
    public void setSendDecl(boolean sendDecl)
    {
        sendXMLDecl = sendDecl;
    }
   
    public boolean shouldSendXSIType() {
        return sendXSIType;
    }

    public ServiceDescription getServiceDescription()
    {
        return msgContext.getServiceDescription();
    }
   
    public TypeMappingRegistry getTypeMappingRegistry()
    {
        return msgContext.getTypeMappingRegistry();
    }
   
    public String getPrefixForURI(String uri)
    {
        return getPrefixForURI(uri, "ns" + lastPrefixIndex++);
    }
   
    public String getPrefixForURI(String uri, String defaultPrefix)
    {
        if ((uri == null) || (uri.equals("")))
            return null;
       
        String prefix = nsStack.getPrefix(uri);
       
        if (prefix == null && uri.equals(Constants.URI_SOAP_ENC)) {
            prefix = Constants.NSPREFIX_SOAP_ENC;
            registerPrefixForURI(prefix, uri);
        }
       
        if (prefix == null) {
            prefix = defaultPrefix;
            registerPrefixForURI(prefix, uri);
        }
       
        return prefix;
    }

    public void registerPrefixForURI(String prefix, String uri)
    {
        if (DEBUG_LOG) {
            System.out.println("register '" + prefix + "' - '" + uri + "'");
        }
       
        if ((uri != null) && (prefix != null)) {
            nsStack.add(uri, prefix);
        }
    }
   
    public void endPrefix(String prefix)
    {
        // Do we need to do anything here?
    }
   
    public String qName2String(QName qName)
    {
        String prefix = getPrefixForURI(qName.getNamespaceURI());
        return (((prefix != null)&&(!prefix.equals(""))) ? prefix + ":" : "") +
               qName.getLocalPart();
    }
   
    public QName getQNameForClass(Class cls)
    {
        return getTypeMappingRegistry().getTypeQName(cls);
    }
   
    /**
     * Classes which are known to not require multi-ref.  As multi-ref
     * requires additional parsing overhead and not all implementations
     * support this, only use this function when there is a possibility
     * of circular references.
     */
    public boolean isPrimitive(Object value)
    {
        if (value == null) return true;

        Class type = value.getClass();
        if (type.isArray()) type = type.getComponentType();

        if (String.class.isAssignableFrom(type)) return true;
        if (Number.class.isAssignableFrom(type)) return true;
        if (Boolean.class.isAssignableFrom(type)) return true;
        if (Date.class.isAssignableFrom(type)) return true;
        if (type.isPrimitive()) return true;
        return false;
    }
   
    public void serialize(QName qName, Attributes attributes, Object value)
        throws IOException
    {
        if (value == null) {
            AttributesImpl attrs = new AttributesImpl();
            if (attributes != null)
                attrs.setAttributes(attributes);
            attrs.addAttribute(Constants.URI_2001_SCHEMA_XSI, "nil", "xsi:nil",
                               "CDATA", "true");
            startElement(qName, attrs);
            endElement();
        }
       
        if (doMultiRefs && (value != currentSer) && !isPrimitive(value)) {
            if (multiRefIndex == -1)
                multiRefValues = new HashMap();
           
            String href = (String)multiRefValues.get(value);
            if (href == null) {
                multiRefIndex++;
                href = "id" + multiRefIndex;
                multiRefValues.put(value, href);
               
                /** Problem - if we're in the middle of writing out
                 * the multi-refs and hit another level of the
                 * object graph, we need to make sure this object
                 * will get written.  For now, add it to a list
                 * which we'll check each time we're done with
                 * outputMultiRefs().
                 */
                if (currentSer != null) {
                    if (secondLevelObjects == null)
                        secondLevelObjects = new HashSet();
                    secondLevelObjects.add(value);
                }
            }
           
            AttributesImpl attrs = new AttributesImpl();
            if (attributes != null)
                attrs.setAttributes(attributes);
            attrs.addAttribute("", Constants.ATTR_HREF, "href",
                               "CDATA", "#" + href);
           
            startElement(qName, attrs);
            endElement();
            return;
        }
       
        getTypeMappingRegistry().serialize(qName, attributes, value, this);
    }
   
    public void outputMultiRefs() throws IOException
    {
        if (!doMultiRefs || (multiRefValues == null))
            return;
       
        AttributesImpl attrs = new AttributesImpl();
        attrs.addAttribute("","","","","");
       
        Iterator i = ((HashMap)multiRefValues.clone()).keySet().iterator();
        while (i.hasNext()) {
            while (i.hasNext()) {
                Object val = i.next();
                String id = (String)multiRefValues.get(val);
                attrs.setAttribute(0, "", Constants.ATTR_ID, "id", "CDATA",
                                   id);
                currentSer = val;
                serialize(new QName("","multiRef"), attrs, val);
            }
           
            if (secondLevelObjects != null) {
                i = secondLevelObjects.iterator();
                secondLevelObjects = null;
            }
        }
        currentSer = null;
    }
   
    public void startElement(QName qName, Attributes attributes)
        throws IOException
    {
        if (DEBUG_LOG) {
            System.out.println("Out: Starting element [" + qName.getNamespaceURI() + "]:" + qName.getLocalPart());
        }

        if (startOfDocument && sendXMLDecl) {
            writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
            startOfDocument = false;
        }
       
        if (writingStartTag) {
            writer.write(">");
            if (pretty) writer.write("\n");
            indent++;
        }
       
        if (pretty) for (int i=0; i<indent; i++) writer.write(' ');
        String elementQName = qName2String(qName);
        writer.write("<");
       
        writer.write(elementQName);
       
        if (attributes != null) {
            for (int i = 0; i < attributes.getLength(); i++) {
                writer.write(" ");
                writer.write(attributes.getQName(i));
                writer.write("=\"");
                writer.write(attributes.getValue(i));
                writer.write("\"");
            }
        }
       
        ArrayList currentMappings = nsStack.peek();
        for (int i = 0; i < currentMappings.size(); i++) {
            Mapping map = (Mapping)currentMappings.get(i);
            writer.write(" xmlns");
            if (!map.getPrefix().equals("")) {
                writer.write(":");
                writer.write(map.getPrefix());
            }
            writer.write("=\"");
            writer.write(map.getNamespaceURI());
            writer.write("\"");
        }

        writingStartTag = true;
       
        elementStack.push(elementQName);
        nsStack.push();

        writer.flush();
        onlyXML=true;
    }
   
    public void endElement()
        throws IOException
    {
        String elementQName = (String)elementStack.pop();
       
        if (DEBUG_LOG) {
            System.out.println("Out: Ending element " + elementQName);
        }
       
        nsStack.pop();
        nsStack.peek().clear();

        if (writingStartTag) {
            writer.write("/>");
            if (pretty) writer.write("\n");
            writingStartTag = false;
            return;
        }
       
        if (onlyXML) {
          indent--;
          if (pretty) for (int i=0; i<indent; i++) writer.write(' ');
        }
        writer.write("</");
        writer.write(elementQName);
        writer.write('>');
        if (pretty) if (indent>0) writer.write('\n');
        writer.flush();
        onlyXML=true;
    }
   
    public void writeChars(char [] p1, int p2, int p3)
        throws IOException
    {
        if (writingStartTag) {
            writer.write(">");
            writingStartTag = false;
        }
        writer.write(p1, p2, p3);
        writer.flush();
        onlyXML=false;
    }

    public void writeString(String string)
        throws IOException
    {
        if (writingStartTag) {
            writer.write(">");
            writingStartTag = false;
        }
        writer.write(string);
        writer.flush();
        onlyXML=false;
    }

    public void writeSafeString(String string)
        throws IOException
    {
        writeString(XMLUtils.xmlEncodeString(string));
    }

    /** Output a DOM representation to a SerializationContext
     */
    public void writeDOMElement(Element el)
        throws IOException
    {
        AttributesImpl attributes = null;
        NamedNodeMap attrMap = el.getAttributes();
       
        if (attrMap.getLength() > 0) {
            attributes = new AttributesImpl();
            for (int i = 0; i < attrMap.getLength(); i++) {
              Attr attr = (Attr)attrMap.item(i);
                           
              attributes.addAttribute(attr.getNamespaceURI(),
                                      attr.getName(),
                                      attr.getName(),
                                      "CDATA", attr.getValue());
            }
        }
       
        QName qName = new QName(el.getNamespaceURI(), el.getTagName());
       
        startElement(qName, attributes);
       
        NodeList children = el.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node child = children.item(i);
            if (child instanceof Element) {
                writeDOMElement((Element)child);
            } else if (child instanceof Text) {
                writeString(((Text)child).getData());
            }
        }
       
        endElement();
    }
   
}
TOP

Related Classes of org.apache.axis.encoding.SerializationContext

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.