com.feilong.lib.xstream.io.StatefulWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of feilong Show documentation
Show all versions of feilong Show documentation
feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.
/*
* Copyright (C) 2006 Joe Walnes.
* Copyright (C) 2006, 2007 XStream Committers.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
* style license a copy of which has been included with this distribution in
* the LICENSE.txt file.
*
* Created on 15. March 2006 by Joerg Schaible
*/
package com.feilong.lib.xstream.io;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import com.feilong.lib.xstream.core.util.FastStack;
/**
* An wrapper for all {@link HierarchicalStreamWriter} implementations, that keeps the state.
* Writing in a wrong state will throw a {@link StreamException}, that wraps either an
* {@link IOException} (writing to a closed writer) or an {@link IllegalStateException}. The
* implementation will also track unbalanced nodes or multiple attributes with the same name.
*
* @author Jörg Schaible
* @since 1.2
*/
public class StatefulWriter extends WriterWrapper{
/**
* STATE_OPEN
is the initial value of the writer.
*
* @since 1.2
*/
public static int STATE_OPEN = 0;
/**
* STATE_NODE_START
is the state of a new node has been started.
*
* @since 1.2
*/
public static int STATE_NODE_START = 1;
/**
* STATE_VALUE
is the state if the value of a node has been written.
*
* @since 1.2
*/
public static int STATE_VALUE = 2;
/**
* STATE_NODE_END
is the state if a node has ended
*
* @since 1.2
*/
public static int STATE_NODE_END = 3;
/**
* STATE_CLOSED
is the state if the writer has been closed.
*
* @since 1.2
*/
public static int STATE_CLOSED = 4;
private transient int state = STATE_OPEN;
private transient int balance;
private transient FastStack attributes;
/**
* Constructs a StatefulWriter.
*
* @param wrapped
* the wrapped writer
* @since 1.2
*/
public StatefulWriter(final HierarchicalStreamWriter wrapped){
super(wrapped);
attributes = new FastStack(16);
}
@Override
public void startNode(final String name){
startNodeCommon();
super.startNode(name);
}
@Override
public void startNode(final String name,final Class clazz){
startNodeCommon();
super.startNode(name, clazz);
}
private void startNodeCommon(){
checkClosed();
if (state == STATE_VALUE){
// legal XML, but not in XStream ... ?
throw new StreamException(new IllegalStateException("Opening node after writing text"));
}
state = STATE_NODE_START;
++balance;
attributes.push(new HashSet());
}
@Override
public void addAttribute(String name,String value){
checkClosed();
if (state != STATE_NODE_START){
throw new StreamException(new IllegalStateException("Writing attribute '" + name + "' without an opened node"));
}
Set currentAttributes = (Set) attributes.peek();
if (currentAttributes.contains(name)){
throw new StreamException(new IllegalStateException("Writing attribute '" + name + "' twice"));
}
currentAttributes.add(name);
super.addAttribute(name, value);
}
@Override
public void setValue(String text){
checkClosed();
if (state != STATE_NODE_START){
// STATE_NODE_END is legal XML, but not in XStream ... ?
throw new StreamException(new IllegalStateException("Writing text without an opened node"));
}
state = STATE_VALUE;
super.setValue(text);
}
@Override
public void endNode(){
checkClosed();
if (balance-- == 0){
throw new StreamException(new IllegalStateException("Unbalanced node"));
}
attributes.popSilently();
state = STATE_NODE_END;
super.endNode();
}
@Override
public void flush(){
checkClosed();
super.flush();
}
@Override
public void close(){
if (state != STATE_NODE_END && state != STATE_OPEN){
// calling close in a finally block should not throw again
// throw new StreamException(new IllegalStateException("Closing with unbalanced tag"));
}
state = STATE_CLOSED;
super.close();
}
private void checkClosed(){
if (state == STATE_CLOSED){
throw new StreamException(new IOException("Writing on a closed stream"));
}
}
/**
* Retrieve the state of the writer.
*
* @return one of the states
* @see #STATE_OPEN
* @see #STATE_NODE_START
* @see #STATE_VALUE
* @see #STATE_NODE_END
* @see #STATE_CLOSED
* @since 1.2
*/
public int state(){
return state;
}
private Object readResolve(){
attributes = new FastStack(16);
return this;
}
}