Package com.enernoc.open.oadr2.xmpp

Source Code of com.enernoc.open.oadr2.xmpp.PullUnmarshaller$Worker

package com.enernoc.open.oadr2.xmpp;
// Original source can be found at:
// http://java.net/projects/jaxb/sources/version1/content/trunk/jaxb-ri/samples/samples-src/pull-parser/src/PullUnmarshaller.java?rev=203

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/*
* Use is subject to the license terms.
*/
import java.io.IOException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.UnmarshallerHandler;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;


/**
* Wraps {@link Unmarshaller} and provide a functionality to unmarshal
* from a {@link XmlPullParser}.
*
* <p>
* This is particularly useful to unmarshal just a part of a document
* into a JAXB object.
*
* <p>
* It is often the case that you don't need complete random access to
* the entire document. Instead, you usually just need random access
* to a limited region of XML.
*
* In this scenario, it is typically a waste of resources to bind the
* entire document into a single JAXB object tree. It will consume
* more memory, it will cause a greater latency.
*
* <p>
* In some cases, your interesting XML document is contained inside
* an "envelope", which you are not so interested in.
*
* In this scenario, this class can be used to just bind the real meat
* to a JAXB object. In this way, you don't need to compile a schema
* that corresponds to the envelope.
* <h2>Example</h2>
* <p>
* Consider the following address book XML:
* <pre><xmp>
* <addressBook>
*   <contact>
*     <name>John Doe</name>
*     <email>john@acme.com</email>
*   </contact>
*   <contact>
*     <name>Jane Smith</name>
*     <email>jane@acme.org</email>
*   </contact>
*   ...
* </addressBook>
* </xmp></pre>
*
* <p>
* Suppose the address book is very long and your program is just looking
* for the record of "Jane Smith". Unmarshalling the whole document
* is easy, but it  forces the entire document to be loaded, which
* consumes more memory.
*
* <p>
* This document can be processed in the following way:
*
* <pre><xmp>
* // set up a parser
* XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
* factory.setNamespaceAware(true);
* XmlPullParser xpp = factory.newPullParser();
*
* // create an unmarshaller
* PullUnmarshaller u = new PullUnmarshaller(jaxbContext);
*
* xpp.setInput( new FileInputStream("contact.xml"), null );
* xpp.nextTag();   // move to the root element
* xpp.require(XmlPullParser.START_TAG,"","addressBook"); // check the root tag name
* xpp.nextTag();   // move to the first <contact> element.
*
* while(xpp.getEventType()==XmlPullParser.START_TAG) {
*    // unmarshall one <contact> element into a JAXB Contact object
*    Contact contact = (Contact)u.unmarshalSubTree(xpp);
*    processContact(contact);
*    if( xpp.getEventType()==XmlPullParser.TEXT)
*       xpp.next();    // skip the whitespace between <contact>s.
* }
* </xmp></pre> 
*
* <p>
* Note that the unmarshaller will think that the &lt;contact> element
* is the root element of a document, so it is important for the
* &lt;contact> element to be declared as a global element.
*
* <p>
* It unmarshals one &lt;contact> at a time, then process it.
* The added benefit is that you can stop the processing as soon
* as you find the info you are looking for. This makes the program
* a lot (average of roughly 2x) faster.
*
* @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
*/
public final class PullUnmarshaller {
   
    private final Unmarshaller unmarshaller;

    /**
     * Constructs a {@link PullUnmarshaller} from a {@link JAXBContext}.
     * <p>
     * This is the equivalent of
     * <code>new PullUnmarshaller(context.createUnmarshaller());</code>
     */
    public PullUnmarshaller(JAXBContext context) throws JAXBException {
        this(context.createUnmarshaller());
    }
   
    /**
     * Constrcuts a {@link PullUnmarshaller} by wrapping an
     * Unmarshaller instance.
     * <p>
     * All the real work of unmarshalling is done through
     * the specified unmarshaller. So configure it appropriately
     * and don't reuse this unmarshaller instance while
     * this {@link PullUnmarshaller} is in use.
     */
    public PullUnmarshaller(Unmarshaller _unmarshaller) {
        if( _unmarshaller==null )
            throw new IllegalArgumentException();
        this.unmarshaller = _unmarshaller;
    }
   
    /**
     * Reads a XML sub-tree and unmarshals it into a JAXB object.
     * <p>
     * the parser must point to a start element. This method will read
     * the whole sub-tree, send it to the JAXB unmarshaller (which was
     * specfied to the constructor), then return the obtained object.
     * <p>
     * After the successful completion of this method, the parser will
     * point to the event next to the end element of the sub-tree.
     * <p>
     * If a processing fails, the parser will be left at somewhere
     * in the middle of the sub-tree.
     *
     *
     * @param parser
     *      A pull parser from which an object will be unmarshalled.
     *      The parser must be at the start element. IOW,
     *      <code>pp.getEventType() == XmlPullParser.START_TAG</code>
     *      has to be true.
     *
     * @return
     *      Always return a non-null valid object.
     *
     * @throws IllegalStateException
     *      If the parser is not set at a start element event,
     *      this exception will be thrown.
     *
     * @throws JAXBException
     *      In case of any XML wellformedness error, IO error, and
     *      JAXB unmarshalling errors. Before this exception is thrown,
     *      it is reported to the {@link javax.xml.bind.ValidationEventHandler}
     *      of the unmarshaller first.
     */
    public Object unmarshalSubTree( XmlPullParser parser ) throws IllegalStateException, JAXBException {
        UnmarshallerHandler handler = unmarshaller.getUnmarshallerHandler();
       
        try {
            new Worker(parser,handler).parse();
        } catch( XmlPullParserException e ) {
            throw new JAXBException(e);
        } catch( SAXException e ) {
            // forward the error  TODO:report to the error handler
            throw new JAXBException(e);
        } catch( IOException e ) {
            // forward the error  TODO:report to the error handler
            throw new JAXBException(e);
        }
       
        return handler.getResult();
    }
   
   
    class Worker {
        private final XmlPullParser pp;
        private final ContentHandler handler;
       
        Worker(XmlPullParser _pp, ContentHandler _handler) {
            this.pp = _pp;
            this.handler = _handler;
        }
       
        public void parse() throws SAXException, XmlPullParserException, IOException {
            if( pp.getEventType() != XmlPullParser.START_TAG )
                throw new IllegalStateException("a parser has to be at the start element event");
           
            handler.setDocumentLocator(locator);
            handler.startDocument();
           
            int nsc = pp.getNamespaceCount(pp.getDepth()-1);
           
            declareNamespace0,nsc);
            parseElement();
            undeclareNamespace(0,nsc);
           
            // skips the last end element.
//            pp.next(); // Don't do this - it breaks smack's XPP traversal logic - TMN
           
            handler.endDocument();
        }

        /**
         * Declares namespace bindings between indices [i,j).
         */
        private void declareNamespace(int i, int j) throws SAXException, XmlPullParserException {
            for( ; i<j; i++ ) {
                String prefix = pp.getNamespacePrefix(i);
                if(prefix==null)    prefix="";
                handler.startPrefixMapping( prefix, pp.getNamespaceUri(i) );
            }
        }

        /**
         * Undeclares namespace bindings between indices [i,j).
         */
        private void undeclareNamespace(int i, int j) throws SAXException, XmlPullParserException {
            for( j--; j>=i; j-- ) {
                String prefix = pp.getNamespacePrefix(j);
                if(prefix==null)    prefix="";
                handler.endPrefixMapping( prefix );
            }
        }
       
        // used by the parseElement method as if it is a local variable.
        private final int[] startAndLen = new int[2];
       
        /**
         * Parses an element and its subordinates recursively.
         *
         * A parser has to be at the START_TAG event, and when
         * this method leaves, the parser is at the corresponding END_TAG
         * event.
         */
        private void parseElement() throws XmlPullParserException, IOException, SAXException {
           
            int nss = pp.getNamespaceCount(pp.getDepth()-1);
            int nse = pp.getNamespaceCount(pp.getDepth()  );
           
            String qname;
            String prefix = pp.getPrefix();
            if(prefix==null)    qname = pp.getName();
            else                qname = prefix + ':' + pp.getName();
           
            declareNamespace(nss,nse);
            handler.startElement( pp.getNamespace(), pp.getName(), qname, attributes );
           
            outer:
            while(true) {
                switch(pp.next()) {
                case XmlPullParser.TEXT:
                    char[] buf = pp.getTextCharacters(startAndLen);
                    handler.characters(buf, startAndLen[0], startAndLen[1] );
                    break;
           
                case XmlPullParser.START_TAG:
                    parseElement();
                    break;
                   
                case XmlPullParser.END_TAG:
                    handler.endElement( pp.getNamespace(), pp.getName(), qname );
                    undeclareNamespace(nss,nse);
                    return;
                }
            }
        }
   

   
        /**
         * {@link Attributes} implementation that uses the
         * {@link XmlPullParser} as the real data storage.
         */       
        private final Attributes attributes = new Attributes() {
           
            public int getLength() {
                return pp.getAttributeCount();
            }
   
            public String getURI(int idx) {
                return pp.getAttributeNamespace(idx);
            }
   
            public String getLocalName(int idx) {
                return pp.getAttributeName(idx);
            }
   
            public String getQName(int idx) {
                String prefix = pp.getAttributePrefix(idx);
                if(prefix==null)    return pp.getAttributeName(idx);
                else    return prefix+':'+pp.getAttributeName(idx);
            }
   
            public String getType(int idx) {
                return pp.getAttributeType(idx);
            }
   
            public String getValue(int idx) {
                return pp.getAttributeValue(idx);
            }
   
            public int getIndex(String uri, String local) {
                for( int i=getLength()-1; i>=0; i-- ) {
                    if( getURI(i).equals(uri) && getLocalName(i).equals(local) )
                        return i;
                }
                return -1;
            }
   
            public int getIndex(String qname) {
                for( int i=getLength()-1; i>=0; i-- ) {
                    if( getQName(i).equals(qname) )
                        return i;
                }
                return -1;
            }
   
            public String getType(String uri, String local) {
                int idx = getIndex(uri,local);
                if(idx==-1) return null;
                else        return getType(idx);
            }
   
            public String getType(String qname) {
                int idx = getIndex(qname);
                if(idx==-1) return null;
                else        return getType(idx);
            }
   
            public String getValue(String uri, String local) {
                int idx = getIndex(uri,local);
                if(idx==-1) return null;
                else        return getValue(idx);
            }
   
            public String getValue(String qname) {
                int idx = getIndex(qname);
                if(idx==-1) return null;
                else        return getValue(idx);
            }
        };
       
        /**
         * {@link Locator} implementation that uses the
         * {@link XmlPullParser} as the real data storage.
         */       
        private final Locator locator = new Locator() {
            public String getPublicId() {
                return null;
            }
   
            public String getSystemId() {
                return null;
            }
   
            public int getLineNumber() {
                return pp.getLineNumber();
            }
   
            public int getColumnNumber() {
                return pp.getColumnNumber();
            }
        };
    }
}
TOP

Related Classes of com.enernoc.open.oadr2.xmpp.PullUnmarshaller$Worker

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.