Package org.codehaus.staxmate.in

Source Code of org.codehaus.staxmate.in.CursorBase

package org.codehaus.staxmate.in;

import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;

import org.codehaus.stax2.XMLStreamReader2;
import org.codehaus.stax2.typed.TypedXMLStreamException;

/**
* Abstract base class that contains non-public methods to be used by
* public sub-classes ({@link SMInputCursor} and its sub-classes).
*
* @author Tatu Saloranta
*/
abstract class CursorBase
{
    /*
    /**********************************************************************
    /* Constants, initial cursor state
    /**********************************************************************
     */

    // // // Constants for the cursor state

    /**
     * State constants are used for keeping track of state of individual
     * cursors.
     */
    public enum State {
        /**
         * Initial means that the cursor has been constructed, but hasn't
         * yet been advanced. No data can be accessed yet, but the cursor
         * can be advanced.
         */
        INITIAL,

        /**
         * Active means that cursor's data is valid and can be accessed;
         * plus it can be advanced as well.
         */
        ACTIVE,

        /**
         * Status that indicates that although cursor would be active, there
         * is a child cursor active which means that this cursor can not
         * be used to access data: only the innermost child cursor can.
         * It can still be advanced, however.
         */
        HAS_CHILD,

        /**
         * Closed cursors are ones that do not point to accessible data, nor
         * can be advanced any further.
         */
        CLOSED
    }

    /*
    /**********************************************************************
    /* Constants, other
    /**********************************************************************
     */

    /**
     * This is the mapping array, indexed by Stax 1.0 event type integer
     * code, value being matching {@link SMEvent} enumeration value.
     */
    private final static SMEvent[] EVENTS_BY_IDS =
        SMEvent.constructIdToEventMapping();

    /*
    /**********************************************************************
    /* Iteration state
    /**********************************************************************
     */

    protected final SMInputContext _context;

    /**
     * Underlying stream reader used. It will either be a native
     * {@link XMLStreamReader2} instance, or a regular (Stax 1.0)
     * {@link javax.xml.stream.XMLStreamReader} wrapped in an
     * adapter.
     */
    protected final XMLStreamReader2 _streamReader;

    /**
     * Depth the underlying stream reader had when this cursor was
     * created (which is the number of currently open parent elements).
     * 0 only for root cursor.
     */
    protected final int _baseDepth;

    /**
     * Current state of the cursor.
     */
    protected State _state = State.INITIAL;

    /**
     * Event that this cursor currently points to, if valid, or
     * it last pointed to if not (including null if cursor has not
     * yet been advanced).
     */
    protected SMEvent _currEvent = null;

    /**
     * Number of nodes iterated over by this cursor, including the
     * current one.
     */
    protected int _nodeCount = 0;

    /**
     * Number of start elements iterated over by this cursor, including the
     * current one.
     */
    protected int _elemCount = 0;

    /**
     * Element that was last "tracked"; element over which cursor was
     * moved, and of which state has been saved for further use. At this
     * point, it can be null if no elements have yet been iterater over.
     * Alternatively, if it's not null, it may be currently pointed to
     * or not; if it's not, either child cursor is active, or this
     * cursor points to a non-start-element node.
     */
    protected SMElementInfo _trackedElement = null;

    /**
     * Element that the parent of this cursor tracked (if any),
     * when this cursor was created.
     */
    protected SMElementInfo _parentTrackedElement = null;

    /**
     * Cursor that has been opened for iterating child nodes of the
     * start element node this cursor points to. Needed to keep
     * cursor hierarchy synchronized, independent of which ones are
     * traversed.
     */
    protected SMInputCursor _childCursor = null;

    /*
    /**********************************************************************
    /* Life-cycle
    /**********************************************************************
     */

    /**
     * @param baseDepth Base depth (number of enclosing open start elements)
     *   of the underlying stream at point when this cursor was instantiated
     */
    protected CursorBase(SMInputContext ctxt, int baseDepth)
    {
        _context = ctxt;
        _streamReader = ctxt.getStreamReader();
        _baseDepth = baseDepth;
    }

    /*
    /**********************************************************************
    /* Methods we need from sub-class
    /**********************************************************************
     */

    /**
     * @return Developer-readable description of the event this cursor
     *    currently points to.
     */
    protected abstract String getCurrEventDesc();

    /**
     * @return True if this cursor iterates over root level of
     *   the underlying stream reader
     */
    public abstract boolean isRootCursor();

    public abstract XMLStreamException constructStreamException(String msg);

    public abstract void throwStreamException(String msg)
        throws XMLStreamException;

    /*
    /**********************************************************************
    /* Methods sub-classes need or can override
    /* to customize behaviour:
    /**********************************************************************
     */

    /**
     * This method is needed by flattening cursors when they
     * have child cursors: if so, they can determine their
     * depth relative to child cursor's base parent count
     * (and can not check stream -- as it may have moved --
     * nor want to have separate field to track this information)
     */
    protected final int getBaseParentCount() {
        return _baseDepth;
    }

    /**
     * Method called to skim through the content that the child
     * cursor(s) are pointing to, end return once next call to
     * XMLStreamReader2.next() will return the next event
     * this cursor should see.
     */
    protected final void rewindPastChild()
        throws XMLStreamException
    {
        final SMInputCursor child = _childCursor;
        _childCursor = null;

        child.invalidate();

        /* Base depth to match is always known by the child in question,
         * so let's ask it (hierarchic cursor parent also knows it)
         */
        final int endDepth = child.getBaseParentCount();
        final XMLStreamReader2 sr = _streamReader;

        for (int type = sr.getEventType(); true; type = sr.next()) {
            if (type == XMLStreamConstants.END_ELEMENT) {
                int depth = sr.getDepth();
                if (depth > endDepth) {
                    continue;
                }
                if (depth != endDepth) { // sanity check
                    _throwWrongEndElem(endDepth, depth);
                }
                break;
            } else if (type == XMLStreamConstants.END_DOCUMENT) {
                /* 18-Nov-2010, This check causes unit test failures, esp. 3 for "TestTyped",
                 *    for "non-stax2-native" parser (Sjsxp).
                 *    It should not; but commenting out following check can help...
                 */
                /*
                if (this.isRootCursor()) {
                    break;
                }
                */
                _throwUnexpectedEndDoc();
            }
        }
    }


    /**
     * Method called by the parent cursor, to indicate it has to
     * traverse over xml content and that child cursor as well
     * as all of its descendant cursors (if any) are to be
     * considered invalid.
     */
    protected void invalidate()
        throws XMLStreamException
    {
        _state = State.CLOSED;
        _currEvent = null;

        // child cursor(s) to delegate skipping to?
        if (_childCursor != null) {
            _childCursor.invalidate();
            _childCursor = null;
        }
    }

    /*
    /**********************************************************************
    /* Package methods
    /**********************************************************************
     */

    /**
     * Internal method (but available to sub-classes) that allows
     * access to the underlying stream reader.
     */
    protected final XMLStreamReader2 _getStreamReader() {
        return _streamReader;
    }

    /**
     *<p>
     * Note: no checks are done regarding validity of passed-in
     * type.
     *
     * @return {@link SMEvent} matching given type
     */
    protected final static SMEvent eventObjectByEventId(int type)
    {
        return EVENTS_BY_IDS[type];
    }

    /**
     * Internal method for throwing a stream exception that indicates
     * that given method can not be called because the cursor does
     * not point to event of expected type. This can be either because
     * cursor is invalid (doesn't point to any event), or because
     * it points to "wrong" event type. Distinction is reflected
     * in the exception message.
     */
    protected XMLStreamException _notAccessible(String method)
        throws XMLStreamException
    {
        if (_childCursor != null) {
            return constructStreamException("Can not call '"+method+"(): cursor does not point to a valid node, as it has an active open child cursor.");
        }
        return constructStreamException("Can not call '"+method+"(): cursor does not point to a valid node (curr event "+getCurrEventDesc()+"; cursor state "
                                        +getStateDesc()+")");
    }

    protected XMLStreamException _wrongState(String method, SMEvent expState)
        throws XMLStreamException
    {
        return constructStreamException("Can not call '"+method+"()' when cursor is not positioned over "+expState+" but "+currentEventStr());
    }

    protected String getStateDesc() {
        return _state.toString();
    }

    /**
     * Method for constructing human-readable description of the event
     * this cursor points to (if cursor valid) or last pointed to (if
     * not valid; possibly null if cursor has not yet been advanced).
     *
     * @return Human-readable description of the underlying Stax event
     *   this cursor points to.
     */
    protected String currentEventStr()
    {
        return (_currEvent == null) ? "null" : _currEvent.toString();
    }

    void _throwUnexpectedEndDoc()
        throws XMLStreamException
    {
        throw new IllegalStateException("Unexpected END_DOCUMENT encountered (root = "+isRootCursor()
                +"; reader impl "+_getStreamReader().getClass().getName()+"); location: "
                +_streamReader.getLocation());
    }

    void _throwWrongEndElem(int expDepth, int actDepth)
        throws IllegalStateException
    {
        throw new IllegalStateException("Expected to encounter END_ELEMENT with depth >= "+expDepth+", got "+actDepth);
    }

    TypedXMLStreamException _constructTypedException(String value, IllegalArgumentException rootCause, String msg)
    {
        return new TypedXMLStreamException(value, msg, _getStreamReader().getLocation(), rootCause);
    }

    @Override
    public String toString() {
        return "{" + getClass().getName()+": "+_state+", curr evt: "
            +_currEvent+"}";
    }
}
TOP

Related Classes of org.codehaus.staxmate.in.CursorBase

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.