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 jtstand-common Show documentation
Show all versions of jtstand-common Show documentation
jtstand-common is a library derived from jcommon, used by jtstand-chart, which is derived from jfreechart
/*
* Copyright (c) 2009 Albert Kurucz.
*
* This file, RootXmlReadHandler.java is part of JTStand.
*
* JTStand 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 3 of the License, or
* (at your option) any later version.
*
* JTStand 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 GTStand. If not, see .
*/
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