org.codehaus.staxmate.out.SMBufferedFragment Maven / Gradle / Ivy
Go to download
StaxMate is a light-weight framework that adds convenience to streaming XML-processing without significant additional overhead.
It builds on top of a Stax (JSR-173) compliant XML processors such as Woodstox or Sjsxp (default Stax implementation of JDK 1.6) and offers two basic abstractions: Cursors, which build on XMLStreamReaders and Output objects, which build on XMLStreamWriters.
The newest version!
package org.codehaus.staxmate.out;
import javax.xml.stream.XMLStreamException;
/**
* Buffered fragment; starts its life buffered,
* so that its content are not automatically written to the underlying
* stream, but only when buffered instance is released. Once released,
* can not be buffered again.
*/
public final class SMBufferedFragment
extends SMOutputContainer
implements SMBufferable
{
/* These are the distinct states:
*
* BUFFERED_AND_BLOCKED: initial state, where output is blocked both
* by this fragment being buffered, AND parent being blocked by
* some other buffering.
* BUFFERED: initial state, where output is only blocked due to the
* fragment itself being buffered.
* BLOCKED: optional state; will be moved here if fragment is unbuffered
* but parent has not yet indicate it is ready to be unblocked
* OPEN: state in which we can freely output children
* CLOSED: state during which no children can be added any more
*/
protected final static int STATE_BUFFERED_AND_BLOCKED = 1;
protected final static int STATE_BUFFERED = 2;
protected final static int STATE_BLOCKED = 3;
protected final static int STATE_OPEN = 4;
protected final static int STATE_CLOSED = 5;
protected final static int LAST_BUFFERED = STATE_BUFFERED;
protected final static int LAST_BLOCKED = STATE_BLOCKED;
/**
* All instances are initially buffered; state will be changed when
* instance is released (and further on with other changes)
*/
protected int _state = STATE_BUFFERED;
protected SMBufferedFragment(SMOutputContext ctxt)
{
super(ctxt);
}
/*
///////////////////////////////////////////////////////////
// SMBufferable implementation
///////////////////////////////////////////////////////////
*/
public boolean isBuffered() {
return (_state <= LAST_BUFFERED);
}
public void linkParent(SMOutputContainer parent, boolean blocked)
throws XMLStreamException
{
if (_parent != null) {
_throwRelinking();
}
_parent = parent;
// Ok, which state should we move to?
if (isBuffered()) { // still buffered
_state = blocked ? STATE_BUFFERED_AND_BLOCKED : STATE_BUFFERED;
} else {
if (blocked) {
_state = STATE_BLOCKED;
} else {
_state = STATE_OPEN;
/* Ok; now, we also need to try to output as much as we can,
* since we are neither buffered nor blocked by parent (may
* still be blocked by a child). However, we are not to be
* closed as of yet.
*/
_output(_context, false);
}
}
}
public void release()
throws XMLStreamException
{
// Should we complain about duplicate calls?
if (!isBuffered()) {
return;
}
if (_parent != null) {
/* May need to update the state first, as parent is likely
* to call _output() when being notified
*/
_state = (_state == STATE_BUFFERED_AND_BLOCKED) ?
STATE_BLOCKED : STATE_OPEN;
_parent._childReleased(this);
} else {
// Will be blocked by the fact we haven't yet been linked...
_state = STATE_BLOCKED;
}
}
/*
///////////////////////////////////////////////////////////
// Abstract method implementations
///////////////////////////////////////////////////////////
*/
protected void _childReleased(SMOutputtable child)
throws XMLStreamException
{
// First, if we are buffered, no need to do anything more...
if (_state <= LAST_BLOCKED) {
return;
}
/* Otherwise, the only significant child is the first one, as it's
* the only one that may have blocked output:
*/
if (child == _firstChild) {
// If so, parent can (and should) deal with it... if we have one
if (_parent != null) {
_parent._childReleased(this);
}
}
}
protected boolean _output(SMOutputContext ctxt, boolean canClose)
throws XMLStreamException
{
// No outputting if still buffered...
if (_state <= LAST_BLOCKED) {
return false;
}
// And it's an error to get it called after being closed
if (_state == STATE_CLOSED) {
_throwClosed();
}
// Should we try to fully close?
if (canClose) {
boolean success = _closeAndOutputChildren();
if (success) { // yup, can indeed fully close
_state = STATE_CLOSED;
}
return success;
}
return _closeAllButLastChild();
}
protected void _forceOutput(SMOutputContext ctxt)
throws XMLStreamException
{
_state = STATE_OPEN; // just in case we get a callback from children
_forceChildOutput();
_state = STATE_CLOSED;
}
public boolean _canOutputNewChild()
throws XMLStreamException
{
// Can not just output if we are buffered...
if (_state <= LAST_BLOCKED) {
return false;
}
/* Plus, if we are fully closed, we are not to allow even trying to
* add anything:
*/
if (_state == STATE_CLOSED) {
_throwClosed();
}
return _closeAndOutputChildren();
}
public void getPath(StringBuilder sb)
{
if (_parent != null) {
_parent.getPath(sb);
}
/* Although fragments are "invisible", let's add an indicator
* of some sort, since this path is used for trouble-shooting
*/
sb.append("/{buffered-fragment}");
}
}