[ERA-CVS] src/org/jdaemon/six AbstractBuilder.java,NONE,1.1
Brought to you by:
jessex
|
From: <je...@us...> - 2004-07-13 10:11:24
|
Update of /cvsroot/era/src/org/jdaemon/six In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7389 Added Files: AbstractBuilder.java Log Message: Abstract builder. Bit of a dead end for now. But interesting enough to keep it around. --- NEW FILE: AbstractBuilder.java --- /* * AbstractBuilder.java * * Created on July 12, 2004, 4:01 PM */ package org.jdaemon.six; import org.jdaemon.util.AttributeList; import java.util.Stack; import java.util.List; import java.util.ArrayList; import java.util.Collections; /** Abstract class for use as base for Builder implementations. * <P> * Lightweight base implemntation for builders that create custom object trees. Unbalanced * calls to startElement and endElement will generate an exception when endElement is * called. * </P><P> * Implement the getNamespace method and the consume method. * </P><P> * The consume method will get called once for each endElement call. Any object returned * by the consume method will be added to the content array passed to consume method when * the parent element's endElement is encountered. * </P> * <B>Note - as of this time, this class is completely untested</B> * @author Jonathan Essex. */ public abstract class AbstractBuilder implements Builder { private ArrayList objects; private Stack state; private Element current; private int ix_end; private Namespace default_ns; /** Inner class for entry in state stack */ public static class Element { private ElementType type; private AttributeList attributes; private int ix_start; public Element(ElementType type, AttributeList attributes, int ix_start) { this.type = type; this.attributes = attributes; this.ix_start = ix_start; } public ElementType getElementType() { return type; } public AttributeList getAttributeList() { return attributes; } } /** Provide read-only access to state. * * @return read-only list of the parents of the current element. */ public List getState() { return Collections.unmodifiableList(state); } /** Creates a new instance of AbstractBuilder. * * Note: the startElement(String, AttributeList) and endElement(String) methods * will not work properly until a default namespace is set. */ public AbstractBuilder() { objects = new ArrayList(); state = new Stack(); current = null; ix_end = 0; } /** End an element. * * Equivalent to endElement(getDefaultNamespace().getElementType(type)) * * @param type Name of the element type in the default namespace */ public void endElement(String type) throws BuildException { endElement(getDefaultNamespace().getElementType(type)); } /** End an element. * * Indicate to builder that the current element is complete. Will result in a call * to the consume method with parameters giving the type, attributes, and content * of the current element. * * @param type Type of the element to complete. */ public void endElement(ElementType type) throws BuildException { // -FIXME- make BuildException more descriptive if (current == null) throw new BuildException("Unbalanced element close"); if (!current.type.equals(type)) throw new BuildException("Wrong type"); if (state.isEmpty()) { current = null; } Object result = consume(current.type, current.attributes, objects.subList(current.ix_start, ix_end)); ix_end = current.ix_start; current = (Element)state.pop(); if (result != null) writeObject(result); } /** Process a completed element. * <P> * This is the interesting part. Any obejct returned by consume() will be added to the * content list passed to the consume method of it's parent element. So in this way we * can simply decide to keep around data or not... * </P> * @param type Type of element to process * @param attribtes Attributes of element to process * @param content Content of element to process */ public abstract Object consume(ElementType type, AttributeList attributes, List content); /** Get the current default namespace. * * The startElement(String, AttributeList) and endElemnt(String) methods use the current * default namespace to convert the given string into an element type. * * @return the current default namespace. */ public Namespace getDefaultNamespace() { return default_ns; } /** Get a namespace with the given attributes. * * @param attributes Implementation-depended way to specify a namespace. * @return a Namespace */ public abstract Namespace getNamespace(org.jdaemon.util.AttributeList attributes); /** Set the current default namespace. * * The startElement(String, AttributeList) and endElemnt(String) methods use the current * default namespace to convert the given string into an element type. * * @param namespace a new default namespace. */ public void setDefaultNamespace(Namespace namespace) { default_ns = namespace; } /** Start an element. * * Equivalent to startElement(getDefaultNamespace().getElementType(type), attributes) * * @param type Name of the element type in the default namespace * @param attributes Attributes of this element */ public void startElement(String type, org.jdaemon.util.AttributeList attributes) throws BuildException { startElement(getDefaultNamespace().getElementType(type), attributes); } /** End an element. * * Indicate to builder that a new element is started. This becomes the current element * until a matching endElement call. * * @param type Type of the element to start. * @param attributes Attributes of this element */ public void startElement(ElementType type, org.jdaemon.util.AttributeList attributes) throws BuildException { if (current != null) { state.push(current); } current = new Element(type, attributes, ix_end); } /** Add content to an element * * @param content Object contained by element */ public void writeObject(Object content) throws BuildException { objects.add(ix_end, content); ix_end++; } } |