/***************************************************************************** * Copyright (c) 2006-2013, Cloudsmith Inc. * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the copyright holder * listed above, as the Initial Contributor under such license. The text of * such license is available at www.eclipse.org. *****************************************************************************/ package org.eclipse.buckminster.sax; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; /** * This handler is the subclass of all handlers in the Tada SAX parser system * except the root handler. It defines a standard way to associate a handler * with an element using a static public string variable called <code>TAG</code> * . Handlers are cached and reused. The implementor of a * <code>ChildHandler</code> should implement the method * {@link #createHandler(String qName)} in order to create handlers for nested * elements and the method {@link #handleAttributes(Attributes)} to handle the * attributes for the element that the handler represents. A concrete subclass * of <code>ChildHandler</code> must also have a static String attribute called * <code>TAG</code>. * * @author Thomas Hallgren */ public abstract class ChildHandler extends AbstractHandler { private AbstractHandler parentHandler; protected ChildHandler(AbstractHandler parentHandler) { this.parentHandler = parentHandler; } /** * This method must be overridden by handlers that deals with nested * elements. * * @param uri * The namespace of the element for which a handler should be * created or <code>null</code> if namespace are not used. * @param localName * The unqualified name of the element. * @param attrs * The element attributes. May be <code>null</code>. * @return Derived methods returns a new handler that corresponds to * <code>qName</code>. * @throws UnrecognizedElementException * unless overridden. */ public ChildHandler createHandler(String uri, String localName, Attributes attrs) throws SAXException { throw new UnrecognizedElementException(this.getTAG(), localName, this.getDocumentLocator()); } /** * Pop this handler from the <code>TopHandler</code> handler stack. * * @param uri * The Namespace URI, ignored. * @param localName * The local name, ignored. * @param qName * The qualified name, ignored. */ @Override public void endElement(String uri, String localName, String qName) throws SAXException { this.popHandler(); ContentHandler parent = this.getParentHandler(); if (parent instanceof ChildPoppedListener) ((ChildPoppedListener) parent).childPopped(this); } public final AbstractHandler getParentHandler() { return parentHandler; } @Override public String getPrefixMapping(String prefix) { String uri = super.getPrefixMapping(prefix); return uri == null ? this.getParentHandler().getPrefixMapping(prefix) : uri; } /** * Return the value of the public static String TAG field declared for the * class of the receiver of the call. */ @Override public String getTAG() { try { Field idField = this.getClass().getDeclaredField("TAG"); //$NON-NLS-1$ int mods = idField.getModifiers(); if (!idField.isAccessible()) idField.setAccessible(true); return (Modifier.isStatic(mods)) ? (String) idField.get(null) : null; } catch (NoSuchFieldException e) { return this.getClass() + "(lacks TAG field)"; //$NON-NLS-1$ } catch (Exception e) { e.printStackTrace(); return e.getMessage(); } } /** * Returns the top element handler. * * @return the top element handler. */ @Override public final TopHandler getTopHandler() { return parentHandler.getTopHandler(); } /** * This method should be overridden by handlers that deals with element * attributes. By default, this method does nothing. * * @param attributes * The attributes as passed to the * {@link #startElement(String, String, String, Attributes)} * method. * @throws SAXException */ public void handleAttributes(Attributes attributes) throws SAXException { } /** * Push a handler that corresponds to the <code>qName</code>, cached or * created, on the handler stack so that it becomes the current * <code>ContentHandler</code> of the <code>TopHandler</code>. * * @param uri * The Namespace URI. * @param localName * The local name. * @param qName * The qualified name. * @param attributes * The attributes that will be sent to the * {@link #handleAttributes(Attributes)} method of the new * handler. * @exception org.xml.sax.SAXException * Any SAX exception, possibly wrapping another exception. */ @Override public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException { if (localName.length() == 0) localName = qName; if (uri.length() == 0) uri = null; this.pushHandler(this.createHandler(uri, localName, attrs), attrs); } /** * Returns the document locator. * * @return the document locator. */ @Override protected final Locator getDocumentLocator() { return parentHandler.getDocumentLocator(); } /** * Pop the current handler from the <code>TopHandler</code> handler stack. */ protected final void popHandler() { this.getTopHandler().popHandler(); } /** * Push a handler on the <code>TopHandler</code> handler stack so that it * becomes the active <code>ContentHandler</code>. * * @param handler * The handler to push. * @param attrs * Attributes to send to the * {@link #handleAttributes(Attributes)} method of the new * handler. * @throws SAXException */ protected final void pushHandler(ChildHandler handler, Attributes attrs) throws SAXException { this.getTopHandler().pushHandler(handler, attrs); } }