[jdom-interest] Adding a DocumentListener interface
Harry Evans
hevans at elite.com
Tue Jul 25 16:37:42 PDT 2000
I sent this originally with the full java files as attachments, but the list
said it was too big. If you get two, just ignore one. Here it is again
without the attachments:
> -----Original Message-----
> From: Harry Evans
> Sent: Tuesday, July 25, 2000 2:58 PM
> To: jdom-interest at jdom.org
> Subject: RE: [jdom-interest] Adding a DocumentListener interface
>
> Regarding Document Listeners:
>
> I think that it might be useful to make it possible to add listeners
> to the various JDOM core objects. However, I don't think that the actual
> listener code needs to be in the core objects. A slight modification to
> the builder classes would allow any level of JDOM data to be properly
> subclassed at build time. Following this same pattern, dynamically
> constructed documents could also use listeners.
> As an example, someone earlier suggested that the creation of
> Elements, Attributes, etc in SAXBuilder be moved to helper methods that
> could be overridden by subclasses to provide the particular implementation
> desired. I see this as not only being minimally invasive to the existing
> API, it adds a huge level of flexibility, with almost no overhead.
> Attached and enclosed are a few example classes showing how this
> could be done:
> SAXBuilder - added protected createElement and
> createAttribute
> methods, and modified build method to use
> these.
> ListenerElement - an example subclass of Element that
> supports
> listeners.
> ListenerBuilder - an example subclass of SAXBuilder that
> creates
> ListenerElements instead of regular
> elements.
> ElementListener - an example listener interface for
> ListenerElement.
> ElementEvent - an example event class for ListenerElement.
>
> The only changes I am actually proposing are those in SAXBuilder. The
> rest of these are just code samples showing an example of how these
> changes add a huge amount of flexibility to the API. Please note that the
> example classes are horribly incomplete(though they should be functional).
> Also note that the suggested pattern of core object creation in the
> builder would allow listeners, or many other things, at any level of the
> JDOM hierarchy.
>
> Harry Evans
>
> //org.jdom.input.SAXBuilder.java
> //only extracted relevant parts for brevity sake.
> public void startElement(String namespaceURI, String localName,
> String rawName, Attributes atts) throws
> SAXException {
> //snip<...>
> // Add this element and its definitions to the global mapping map
> namespaceDefinitions.put(rawName, elementDefinitions);
>
> int elementSplit;
> String prefix = "";
> String name = rawName;
> if ((elementSplit = rawName.indexOf(":")) != -1) {
> prefix = rawName.substring(0, elementSplit);
> name = rawName.substring(elementSplit + 1);
> }
> Element element =
> createElement(name, prefix, getNamespaceURI(prefix));
> //snip<...>
> if (!attName.startsWith("xmlns")) {
> name = attName;
> int attSplit;
> prefix = "";
> if ((attSplit = name.indexOf(":")) != -1) {
> prefix = name.substring(0, attSplit);
> name = name.substring(attSplit + 1);
> }
> // Only put attribute in namespace if there is a prefix
> if (prefix.equals("")) {
> element.addAttribute(
> createAttribute(name, atts.getValue(i)));
> } else {
> element.addAttribute(
> createAttribute(name,
> prefix,
> getNamespaceURI(prefix),
> atts.getValue(i)));
> }
> }
> }
> //snip<...>
> }
>
> /**
> * Method for creating an <code>org.jdom.Element</code>.
> * Subclasses may override this method to allow subclasses
> * of Element to be created instead, to provide
> * additional functionality.
> * @param name <code>String</code> name of element.
> * @param prefix <code>String</code> prefix for this element's
> <code>{@link Namespace}</code>.
> * @param uri <code>String</code> URI for <code>Namespace</code>
> element
> * should be in.
> */
> protected Element createElement(String name, String prefix, String
> uri)
> {
> return new Element(name, prefix, uri);
> }
>
> /**
> * Method for creating an <code>org.jdom.Attribute</code>.
> * Subclasses may override this method to allow subclasses
> * of Attribute to be created instead, to provide
> * additional functionality.
> * @param name <code>String</code> name of <code>Attribute</code>.
> * @param value <code>String</code> value for <code>Attribute</code>.
> */
> protected Attribute createAttribute(String name, String value)
> {
> return new Attribute(name, value);
> }
>
> /**
> * Method for creating an <code>org.jdom.Attribute</code>.
> * Subclasses may override this method to allow subclasses
> * of Attribute to be created instead, to provide
> * additional functionality.
> * @param name <code>String</code> name of <code>Attribute</code>.
> * @param prefix <code>String</code> prefix for
> <code>Attribute</code>.
> * @param uri <code>String</code> URI for namespace this
> * <code>Attribute</code> is in.
> * @param value <code>String</code> value for new attribute.
> */
> protected Attribute createAttribute(String name, String prefix,
> String uri, String value)
> {
> return new Attribute(name, prefix, uri, value);
> }
>
> //ListenerBuilder.java
> //sample Builder subclassing SAXBuilder and overriding
> //the createElement method proposed.
> import org.jdom.Element;
> import org.jdom.input.SAXBuilder; //the modified version
>
> public class ListenerBuilder extends SAXBuilder
> {
> public ListenerBuilder() {
> super();
> }
>
> /**
> * Method for creating an
> <code>org.jdom.contrib.ListenerElement</code>.
> * @param name <code>String</code> name of element.
> * @param prefix <code>String</code> prefix for this element's
> <code>{@link Namespace}</code>.
> * @param uri <code>String</code> URI for <code>Namespace</code>
> element
> * should be in.
> */
> protected Element createElement(String name, String prefix, String
> uri)
> {
> return new ListenerElement(name, prefix, uri);
> }
> }
>
> //ListenerElement.java
> //sample Element subclass containing a listener interface
> import org.jdom.Element;
> import org.jdom.Namespace;
> import java.util.ArrayList;
> import java.util.Iterator;
> import java.util.List;
> public class ListenerElement extends Element
> {
> private List listeners;
> //set up the same constructors
> public ListenerElement(String name, Namespace namespace) {
> super(name, namespace);
> }
> public ListenerElement(String name) {
> super(name);
> }
> public ListenerElement(String name, String uri) {
> super(name, uri);
> }
> public ListenerElement(String name, String prefix, String uri) {
> super(name, prefix, uri);
> }
> //should probably implement getCopy methods,
> //but this is an example.
>
> public void addListener(ElementListener listener) {
> if(listeners == null)
> listeners = new ArrayList();//lazy initialize
> listeners.add(listener);
> }
> //removeListener etc. should be here
>
> //example usage
> public Element addChild(Element element) {
> Element returnValue = super.addChild(element);
> fireEvent(new ElementEvent(ElementEvent.CHILD_ADDED, this,
> element));
> return returnValue;
> }
>
> protected void fireEvent(ElementEvent event) {
> if(listeners != null && listeners.size() > 0) {
> for(Iterator it = listeners.iterator();
> it.hasNext();) {
>
> ((ElementListener)it.next()).processEvent(event);
> }
> }
> }
> }
>
> //ElementListener.java
> //sample ListenerInterface
> public interface ElementListener
> {
> public void processEvent(ElementEvent e);
> }
>
> //ElementEvent.java
> //sample EventClass
> import org.jdom.Element;
> public class ElementEvent
> {
> public static int CHILD_ADDED = 0;
> public static int CHILD_REMOVED = 1;
>
> private Element parent;
> private Element child;
> private int type;
>
> public ElementEvent(int aType, Element aParent, Element aChild) {
> type = aType;
> parent = aParent;
> child = aChild;
> }
>
> public int getType() { return type; }
> public Element getParentElement() { return parent; }
> public Element getChildElement() { return child; }
> }
>
More information about the jdom-interest
mailing list