org.jfree.xml.parser.RootXmlReadHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcommon Show documentation
Show all versions of jcommon Show documentation
JCommon is a free general purpose Java class library that is used in
several projects at www.jfree.org, including JFreeChart and
JFreeReport.
/* ========================================================================
* JCommon : a free general purpose class library for the Java(tm) platform
* ========================================================================
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -----------------------
* RootXmlReadHandler.java
* -----------------------
* (C)opyright 2003, 2004, by Thomas Morgner and Contributors.
*
* Original Author: Thomas Morgner;
* Contributor(s): David Gilbert (for Object Refinery Limited);
*
* $Id: RootXmlReadHandler.java,v 1.9 2008/09/10 09:20:16 mungady Exp $
*
* Changes (from 25-Nov-2003)
* --------------------------
* 25-Nov-2003 : Added Javadocs (DG);
* 22-Feb-2005 : Fixed a bug when ending nested tags with the same tagname.
*/
package org.jfree.xml.parser;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import java.util.Vector;
import org.jfree.util.ObjectUtilities;
import org.jfree.xml.FrontendDefaultHandler;
import org.jfree.xml.ParseException;
import org.jfree.xml.ElementDefinitionException;
import org.jfree.xml.parser.coretypes.BasicStrokeReadHandler;
import org.jfree.xml.parser.coretypes.ColorReadHandler;
import org.jfree.xml.parser.coretypes.FontReadHandler;
import org.jfree.xml.parser.coretypes.GenericReadHandler;
import org.jfree.xml.parser.coretypes.GradientPaintReadHandler;
import org.jfree.xml.parser.coretypes.InsetsReadHandler;
import org.jfree.xml.parser.coretypes.ListReadHandler;
import org.jfree.xml.parser.coretypes.Point2DReadHandler;
import org.jfree.xml.parser.coretypes.Rectangle2DReadHandler;
import org.jfree.xml.parser.coretypes.RenderingHintsReadHandler;
import org.jfree.xml.parser.coretypes.StringReadHandler;
import org.jfree.xml.util.ManualMappingDefinition;
import org.jfree.xml.util.MultiplexMappingDefinition;
import org.jfree.xml.util.MultiplexMappingEntry;
import org.jfree.xml.util.ObjectFactory;
import org.jfree.xml.util.SimpleObjectFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* A base root SAX handler.
*/
public abstract class RootXmlReadHandler extends FrontendDefaultHandler {
/** The current handlers. */
private Stack currentHandlers;
/** ??. */
private Stack outerScopes;
/** The root handler. */
private XmlReadHandler rootHandler;
/** The object registry. */
private HashMap objectRegistry;
/** Maps classes to handlers. */
private SimpleObjectFactory classToHandlerMapping;
private boolean rootHandlerInitialized;
/**
* Creates a new root SAX handler.
*/
public RootXmlReadHandler() {
this.objectRegistry = new HashMap();
this.classToHandlerMapping = new SimpleObjectFactory();
}
/**
* Adds the default mappings.
*/
protected void addDefaultMappings () {
final MultiplexMappingEntry[] paintEntries = new MultiplexMappingEntry[2];
paintEntries[0] = new MultiplexMappingEntry("color", Color.class.getName());
paintEntries[1] = new MultiplexMappingEntry("gradientPaint", GradientPaint.class.getName());
addMultiplexMapping(Paint.class, "type", paintEntries);
addManualMapping(Color.class, ColorReadHandler.class);
addManualMapping(GradientPaint.class, GradientPaintReadHandler.class);
final MultiplexMappingEntry[] point2DEntries = new MultiplexMappingEntry[2];
point2DEntries[0] = new MultiplexMappingEntry("float", Point2D.Float.class.getName());
point2DEntries[1] = new MultiplexMappingEntry("double", Point2D.Double.class.getName());
addMultiplexMapping(Point2D.class, "type", point2DEntries);
addManualMapping(Point2D.Float.class, Point2DReadHandler.class);
addManualMapping(Point2D.Double.class, Point2DReadHandler.class);
final MultiplexMappingEntry[] rectangle2DEntries = new MultiplexMappingEntry[2];
rectangle2DEntries[0] = new MultiplexMappingEntry(
"float", Rectangle2D.Float.class.getName()
);
rectangle2DEntries[1] = new MultiplexMappingEntry(
"double", Rectangle2D.Double.class.getName()
);
addMultiplexMapping(Rectangle2D.class, "type", rectangle2DEntries);
addManualMapping(Rectangle2D.Float.class, Rectangle2DReadHandler.class);
addManualMapping(Rectangle2D.Double.class, Rectangle2DReadHandler.class);
// Handle list types
final MultiplexMappingEntry[] listEntries = new MultiplexMappingEntry[4];
listEntries[0] = new MultiplexMappingEntry("array-list", ArrayList.class.getName());
listEntries[1] = new MultiplexMappingEntry("linked-list", LinkedList.class.getName());
listEntries[2] = new MultiplexMappingEntry("vector", Vector.class.getName());
listEntries[3] = new MultiplexMappingEntry("stack", Stack.class.getName());
addMultiplexMapping(List.class, "type", listEntries);
addManualMapping(LinkedList.class, ListReadHandler.class);
addManualMapping(Vector.class, ListReadHandler.class);
addManualMapping(ArrayList.class, ListReadHandler.class);
addManualMapping(Stack.class, ListReadHandler.class);
final MultiplexMappingEntry[] strokeEntries = new MultiplexMappingEntry[1];
strokeEntries[0] = new MultiplexMappingEntry("basic", BasicStroke.class.getName());
addMultiplexMapping(Stroke.class, "type", strokeEntries);
addManualMapping(BasicStroke.class, BasicStrokeReadHandler.class);
addManualMapping(Font.class, FontReadHandler.class);
addManualMapping(Insets.class, InsetsReadHandler.class);
addManualMapping(RenderingHints.class, RenderingHintsReadHandler.class);
addManualMapping(String.class, StringReadHandler.class);
}
/**
* Returns the object factory.
*
* @return The object factory.
*/
public abstract ObjectFactory getFactoryLoader();
/**
* Adds a mapping between a class and the handler for the class.
*
* @param classToRead the class.
* @param handler the handler class.
*/
protected void addManualMapping(final Class classToRead, final Class handler) {
if (handler == null) {
throw new NullPointerException("handler must not be null.");
}
if (classToRead == null) {
throw new NullPointerException("classToRead must not be null.");
}
if (!XmlReadHandler.class.isAssignableFrom(handler)) {
throw new IllegalArgumentException("The given handler is no XmlReadHandler.");
}
this.classToHandlerMapping.addManualMapping
(new ManualMappingDefinition(classToRead, handler.getName(), null));
}
/**
* Adds a multiplex mapping.
*
* @param baseClass the base class.
* @param typeAttr the type attribute.
* @param mdef the mapping entry.
*/
protected void addMultiplexMapping(final Class baseClass,
final String typeAttr,
final MultiplexMappingEntry[] mdef) {
this.classToHandlerMapping.addMultiplexMapping(
new MultiplexMappingDefinition(baseClass, typeAttr, mdef)
);
}
/**
* Adds an object to the registry.
*
* @param key the key.
* @param value the object.
*/
public void setHelperObject(final String key, final Object value) {
if (value == null) {
this.objectRegistry.remove(key);
}
else {
this.objectRegistry.put(key, value);
}
}
/**
* Returns an object from the registry.
*
* @param key the key.
*
* @return The object.
*/
public Object getHelperObject(final String key) {
return this.objectRegistry.get(key);
}
/**
* Creates a SAX handler for the specified class.
*
* @param classToRead the class.
* @param tagName the tag name.
* @param atts the attributes.
*
* @return a SAX handler.
*
* @throws XmlReaderException if there is a problem with the reader.
*/
public XmlReadHandler createHandler(final Class classToRead, final String tagName, final Attributes atts)
throws XmlReaderException {
final XmlReadHandler retval = findHandlerForClass(classToRead, atts, new ArrayList());
if (retval == null) {
throw new NullPointerException("Unable to find handler for class: " + classToRead);
}
retval.init(this, tagName);
return retval;
}
/**
* Finds a handler for the specified class.
*
* @param classToRead the class to be read.
* @param atts the attributes.
* @param history the history.
*
* @return A handler for the specified class.
*
* @throws XmlReaderException if there is a problem with the reader.
*/
private XmlReadHandler findHandlerForClass(final Class classToRead, final Attributes atts,
final ArrayList history)
throws XmlReaderException {
final ObjectFactory genericFactory = getFactoryLoader();
if (history.contains(classToRead)) {
throw new IllegalStateException("Circular reference detected: " + history);
}
history.add(classToRead);
// check the manual mappings ...
ManualMappingDefinition manualDefinition =
this.classToHandlerMapping.getManualMappingDefinition(classToRead);
if (manualDefinition == null) {
manualDefinition = genericFactory.getManualMappingDefinition(classToRead);
}
if (manualDefinition != null) {
// Log.debug ("Locating handler for " + manualDefinition.getBaseClass());
return loadHandlerClass(manualDefinition.getReadHandler());
}
// check whether a multiplexer is defined ...
// find multiplexer for this class...
MultiplexMappingDefinition mplex =
getFactoryLoader().getMultiplexDefinition(classToRead);
if (mplex == null) {
mplex = this.classToHandlerMapping.getMultiplexDefinition(classToRead);
}
if (mplex != null) {
final String attributeValue = atts.getValue(mplex.getAttributeName());
if (attributeValue == null) {
throw new XmlReaderException(
"Multiplexer type attribute is not defined: " + mplex.getAttributeName()
+ " for " + classToRead
);
}
final MultiplexMappingEntry entry =
mplex.getEntryForType(attributeValue);
if (entry == null) {
throw new XmlReaderException(
"Invalid type attribute value: " + mplex.getAttributeName() + " = "
+ attributeValue
);
}
final Class c = loadClass(entry.getTargetClass());
if (!c.equals(mplex.getBaseClass())) {
return findHandlerForClass(c, atts, history);
}
}
// check for generic classes ...
// and finally try the generic handler matches ...
if (this.classToHandlerMapping.isGenericHandler(classToRead)) {
return new GenericReadHandler
(this.classToHandlerMapping.getFactoryForClass(classToRead));
}
if (getFactoryLoader().isGenericHandler(classToRead)) {
return new GenericReadHandler
(getFactoryLoader().getFactoryForClass(classToRead));
}
return null;
}
/**
* Sets the root SAX handler.
*
* @param handler the SAX handler.
*/
protected void setRootHandler(final XmlReadHandler handler) {
this.rootHandler = handler;
this.rootHandlerInitialized = false;
}
/**
* Returns the root SAX handler.
*
* @return the root SAX handler.
*/
protected XmlReadHandler getRootHandler() {
return this.rootHandler;
}
/**
* Start a new handler stack and delegate to another handler.
*
* @param handler the handler.
* @param tagName the tag name.
* @param attrs the attributes.
*
* @throws XmlReaderException if there is a problem with the reader.
* @throws SAXException if there is a problem with the parser.
*/
public void recurse(final XmlReadHandler handler, final String tagName, final Attributes attrs)
throws XmlReaderException, SAXException {
this.outerScopes.push(this.currentHandlers);
this.currentHandlers = new Stack();
this.currentHandlers.push(handler);
handler.startElement(tagName, attrs);
}
/**
* Delegate to another handler.
*
* @param handler the new handler.
* @param tagName the tag name.
* @param attrs the attributes.
*
* @throws XmlReaderException if there is a problem with the reader.
* @throws SAXException if there is a problem with the parser.
*/
public void delegate(final XmlReadHandler handler, final String tagName, final Attributes attrs)
throws XmlReaderException, SAXException {
this.currentHandlers.push(handler);
handler.init(this, tagName);
handler.startElement(tagName, attrs);
}
/**
* Hand control back to the previous handler.
*
* @param tagName the tagname.
*
* @throws SAXException if there is a problem with the parser.
* @throws XmlReaderException if there is a problem with the reader.
*/
public void unwind(final String tagName) throws SAXException, XmlReaderException {
// remove current handler from stack ..
this.currentHandlers.pop();
if (this.currentHandlers.isEmpty() && !this.outerScopes.isEmpty()) {
// if empty, but "recurse" had been called, then restore the old handler stack ..
// but do not end the recursed element ..
this.currentHandlers = (Stack) this.outerScopes.pop();
}
else if (!this.currentHandlers.isEmpty()) {
// if there are some handlers open, close them too (these handlers must be delegates)..
getCurrentHandler().endElement(tagName);
}
}
/**
* Returns the current handler.
*
* @return The current handler.
*/
protected XmlReadHandler getCurrentHandler() {
return (XmlReadHandler) this.currentHandlers.peek();
}
/**
* Starts processing a document.
*
* @throws SAXException not in this implementation.
*/
public void startDocument() throws SAXException {
this.outerScopes = new Stack();
this.currentHandlers = new Stack();
this.currentHandlers.push(this.rootHandler);
}
/**
* Starts processing an element.
*
* @param uri the URI.
* @param localName the local name.
* @param qName the qName.
* @param attributes the attributes.
*
* @throws SAXException if there is a parsing problem.
*/
public void startElement(final String uri, final String localName,
final String qName, final Attributes attributes)
throws SAXException {
if (this.rootHandlerInitialized == false) {
this.rootHandler.init(this, qName);
this.rootHandlerInitialized = true;
}
try {
getCurrentHandler().startElement(qName, attributes);
}
catch (XmlReaderException xre) {
throw new ParseException(xre, getLocator());
}
}
/**
* Process character data.
*
* @param ch the character buffer.
* @param start the start index.
* @param length the length of the character data.
*
* @throws SAXException if there is a parsing error.
*/
public void characters(final char[] ch, final int start, final int length) throws SAXException {
try {
getCurrentHandler().characters(ch, start, length);
}
catch (SAXException se) {
throw se;
}
catch (Exception e) {
throw new ParseException(e, getLocator());
}
}
/**
* Finish processing an element.
*
* @param uri the URI.
* @param localName the local name.
* @param qName the qName.
*
* @throws SAXException if there is a parsing error.
*/
public void endElement(final String uri, final String localName, final String qName)
throws SAXException {
try {
getCurrentHandler().endElement(qName);
}
catch (XmlReaderException xre) {
throw new ParseException(xre, getLocator());
}
}
/**
* Loads the given class, and ignores all exceptions which may occur
* during the loading. If the class was invalid, null is returned instead.
*
* @param className the name of the class to be loaded.
* @return the class or null.
* @throws XmlReaderException if there is a reader error.
*/
protected XmlReadHandler loadHandlerClass(final String className)
throws XmlReaderException {
try {
final Class c = loadClass(className);
return (XmlReadHandler) c.newInstance();
}
catch (Exception e) {
// ignore buggy classes for now ..
throw new XmlReaderException("LoadHanderClass: Unable to instantiate " + className, e);
}
}
/**
* Loads the given class, and ignores all exceptions which may occur
* during the loading. If the class was invalid, null is returned instead.
*
* @param className the name of the class to be loaded.
* @return the class or null.
* @throws XmlReaderException if there is a reader error.
*/
protected Class loadClass(final String className)
throws XmlReaderException {
if (className == null) {
throw new XmlReaderException("LoadHanderClass: Class name not defined");
}
try {
final Class c = ObjectUtilities.getClassLoader(getClass()).loadClass(className);
return c;
}
catch (Exception e) {
// ignore buggy classes for now ..
throw new XmlReaderException("LoadHanderClass: Unable to load " + className, e);
}
}
/**
* Returns ???.
*
* @return ???.
*
* @throws SAXException ???.
*/
public Object getResult () throws SAXException
{
if (this.rootHandler != null) {
try
{
return this.rootHandler.getObject();
}
catch (XmlReaderException e)
{
throw new ElementDefinitionException(e);
}
}
return null;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy