*/
public class PersistenceParser extends DefaultHandler implements Context
{
- /** The ExceptionListener instance which is informed of non-critical parsing exceptions.
- */
- private ExceptionListener exceptionListener;
-
- /** When an element was not usable all elements inside it should be skipped.
- * This is done by skipping startElement() and endElement() invocations whenever
- * this value is above 0.
- */
- private int skipElement;
-
- /** Stores the Creator instances which can instantiate the appropriate handler implementation
- * for a given element.
- */
- private HashMap handlerCreators = new HashMap();
-
- /** Denotes the current ElementHandler. To avoid checking for null-values it is pre-assigned
- * with a DummyHandler instance which must not be used but acts as a root element.
- */
- private ElementHandler currentHandler;
-
- /** The real root element that stores all objects created during parsing.
- * Package-private to avoid an accessor method.
- */
- JavaHandler javaHandler;
-
- /** Stores the decoded objects. */
- private List objects = new LinkedList();
-
- /** The XMLDecoder instance that started this PersistenceParser */
- private XMLDecoder decoder;
-
- /** Creates a PersistenceParser which reads XML data from the given InputStream, reports
- * exceptions to ExceptionListener instance, stores resulting object in the DecoderContext
- * and uses the given ClassLoader to resolve classes.
- *
- * @param inputStream
- * @param exceptionListener
- * @param decoderContext
- * @param cl
- */
- public PersistenceParser(
- InputStream inputStream,
- ExceptionListener exceptionListener,
- ClassLoader cl,
- XMLDecoder decoder)
- {
-
- this.exceptionListener = exceptionListener;
- this.decoder = decoder;
-
- DummyHandler dummyHandler = new DummyHandler();
- currentHandler = dummyHandler;
- javaHandler = new JavaHandler(dummyHandler, this, cl);
-
- SAXParserFactory factory = SAXParserFactory.newInstance();
-
- SAXParser parser;
- try
- {
- parser = factory.newSAXParser();
- }
- catch (ParserConfigurationException pce)
- {
- // should not happen when a parser is available because we did
- // not request any requirements on the XML parser
- throw (InternalError) new InternalError(
- "No SAX Parser available.").initCause(
- pce);
- }
- catch (SAXException saxe)
- {
- // should not happen when a parser is available because we did
- // not request any requirements on the XML parser
- throw (InternalError) new InternalError(
- "No SAX Parser available.").initCause(
- saxe);
- }
-
- // prepares a map of Creator instances which can instantiate a handler which is
- // appropriate for the tag that is used as a key for the Creator
- handlerCreators.put("java", new JavaHandlerCreator());
-
- // calls methods (properties), constructors, access fields
- handlerCreators.put("object", new ObjectHandlerCreator());
- handlerCreators.put("void", new VoidHandlerCreator());
-
- handlerCreators.put("array", new ArrayHandlerCreator());
-
- // these handler directly create an Object (or null)
- handlerCreators.put("class", new ClassHandlerCreator());
- handlerCreators.put("null", new NullHandlerCreator());
-
- handlerCreators.put("char", new CharHandlerCreator());
- handlerCreators.put("string", new StringHandlerCreator());
- handlerCreators.put("boolean", new BooleanHandlerCreator());
- handlerCreators.put("byte", new ByteHandlerCreator());
- handlerCreators.put("short", new ShortHandlerCreator());
- handlerCreators.put("int", new IntHandlerCreator());
- handlerCreators.put("long", new LongHandlerCreator());
- handlerCreators.put("float", new FloatHandlerCreator());
- handlerCreators.put("double", new DoubleHandlerCreator());
-
- // parses the data and sends all exceptions to the ExceptionListener
- try
- {
- parser.parse(inputStream, this);
- }
- catch (SAXException saxe)
- {
- exceptionListener.exceptionThrown(
- new IllegalArgumentException("XML data not well-formed."));
- }
- catch (IOException ioe)
- {
- exceptionListener.exceptionThrown(ioe);
- }
- }
-
- public void startElement(
- String uri,
- String localName,
- String qName,
- Attributes attributes)
- throws SAXException
- {
- /* The element is skipped if
- * a) the current handler has already failed or a previous error occured
- * which makes all children obsolete
- */
- if (currentHandler.hasFailed() || skipElement > 0)
- {
- exceptionListener.exceptionThrown(
- new IllegalArgumentException(
- "Element unusable due to previous error: " + qName));
-
- skipElement++;
-
- return;
- }
-
- /* b) Subelements are not allowed within the current ElementHandler.
- */
- if (!currentHandler.isSubelementAllowed(qName))
- {
- exceptionListener.exceptionThrown(
- new IllegalArgumentException(
- "Element is not allowed here: " + qName));
-
- skipElement++;
-
- return;
- }
-
- /* c) The tag name is not a key in the map of Creator instances. This means that
- * either the XML data is of a newer version or simply contains a miss-spelled element.
- */
- if (!handlerCreators.containsKey(qName))
- {
- exceptionListener.exceptionThrown(
- new IllegalArgumentException(
- "Element unusable because tag is unknown: " + qName));
-
- skipElement++;
-
- return;
- }
-
- // creates a new handler for the new element
- AbstractElementHandler handler =
- ((Creator) handlerCreators.get(qName)).createHandler(
- currentHandler);
-
- // makes it the current handler to receive character data
- currentHandler = handler;
-
- // starts the handler
- currentHandler.start(attributes, exceptionListener);
- }
-
- public void endElement(String uri, String localName, String qName)
- throws SAXException
- {
- // skips processing the current handler if we are parsing an element
- // which was marked invalid (in startElement() )
- if (skipElement > 0)
- {
- skipElement--;
- return;
- }
-
- // invokes the handler's finishing method
- currentHandler.end(exceptionListener);
-
- // removes the current handler and reactivates its parent
- currentHandler = currentHandler.getParent();
- }
-
- /** Transfers character data to the current handler
- */
- public void characters(char[] ch, int start, int length)
- throws SAXException
- {
- // prevents sending character data of invalid elements
- if (skipElement > 0)
- return;
-
- currentHandler.characters(ch, start, length);
- }
-
- /** Creator interface provided a mechanism to instantiate ElementHandler instances
- * for the appropriate tag.
- *
- * @author Robert Schuster
- */
- interface Creator
- {
- /** Creates an ElementHandler instance using the given ElementHandler as its parent.
- *
- * @param parent The parent ElementHandler of the result.
- * @return A new ElementHandler instance.
- */
- AbstractElementHandler createHandler(ElementHandler parent);
- }
-
- class BooleanHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new BooleanHandler(parent);
- }
- }
-
- class ByteHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new ByteHandler(parent);
- }
- }
-
- class ShortHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new ShortHandler(parent);
- }
- }
-
- class IntHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new IntHandler(parent);
- }
- }
-
- class LongHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new LongHandler(parent);
- }
- }
-
- class FloatHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new FloatHandler(parent);
- }
- }
-
- class DoubleHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new DoubleHandler(parent);
- }
- }
-
- class CharHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new CharHandler(parent);
- }
- }
-
- class StringHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new StringHandler(parent);
- }
- }
-
- class JavaHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return javaHandler;
- }
- }
-
- class ObjectHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new ObjectHandler(parent);
- }
- }
-
- class VoidHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new VoidHandler(parent);
- }
- }
-
- class ClassHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new ClassHandler(parent);
- }
- }
-
- class NullHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new NullHandler(parent);
- }
- }
-
- class ArrayHandlerCreator implements Creator
- {
- public AbstractElementHandler createHandler(ElementHandler parent)
- {
- return new ArrayHandler(parent);
- }
- }
-
- /** Adds a decoded object to the Context. */
- public void addParameterObject(Object o) throws AssemblyException
- {
- objects.add(o);
- }
-
- public void notifyStatement(Context outerContext) throws AssemblyException
- {
- // can be ignored because theis Context does not react to statement and expressions
- // differently
- }
-
- public Object endContext(Context outerContext) throws AssemblyException
- {
- return null;
- }
-
- public boolean subContextFailed()
- {
- // failing of subcontexts is no problem for the mother of all contexts
- return false;
- }
-
- public void set(int index, Object o) throws AssemblyException
- {
- // not supported
- throw new AssemblyException(
- new IllegalArgumentException("Set method is not allowed in decoder context."));
- }
-
- public Object get(int index) throws AssemblyException
- {
- // not supported
- throw new AssemblyException(
- new IllegalArgumentException("Get method is not allowed in decoder context."));
- }
-
- public Object getResult()
- {
- // returns the XMLDecoder instance which is requested by child contexts this way.
- // That is needed to invoke methods on the decoder.
- return decoder;
- }
-
- public void setId(String id)
- {
- exceptionListener.exceptionThrown(new IllegalArgumentException("id attribute is not allowed for <java> tag."));
- }
-
- public String getId()
- {
- // appears to have no id
- return null;
- }
-
- public boolean isStatement()
- {
- // this context is a statement by definition because it never returns anything to a parent because
- // there is no such parent (DummyContext does not count!)
- return true;
- }
-
- public void setStatement(boolean b)
- {
- // ignores that because this Context is always a statement
- }
-
- /** Returns an Iterator instance which returns the decoded objects.
- *
- * This method is used by the XMLDecoder directly.
- */
- public Iterator iterator()
- {
- return objects.iterator();
- }
+ /** The ExceptionListener instance which is informed of non-critical parsing exceptions.
+ */
+ private ExceptionListener exceptionListener;
+
+ /** When an element was not usable all elements inside it should be skipped.
+ * This is done by skipping startElement() and endElement() invocations whenever
+ * this value is above 0.
+ */
+ private int skipElement;
+
+ /** Stores the Creator instances which can instantiate the appropriate handler implementation
+ * for a given element.
+ */
+ private HashMap handlerCreators = new HashMap();
+
+ /** Denotes the current ElementHandler. To avoid checking for null-values it is pre-assigned
+ * with a DummyHandler instance which must not be used but acts as a root element.
+ */
+ private ElementHandler currentHandler;
+
+ /** The real root element that stores all objects created during parsing.
+ * Package-private to avoid an accessor method.
+ */
+ JavaHandler javaHandler;
+
+ /** Stores the decoded objects. */
+ private List objects = new LinkedList();
+
+ /** The XMLDecoder instance that started this PersistenceParser */
+ private XMLDecoder decoder;
+
+ /** Creates a PersistenceParser which reads XML data from the given InputStream, reports
+ * exceptions to ExceptionListener instance, stores resulting object in the DecoderContext
+ * and uses the given ClassLoader to resolve classes.
+ *
+ * @param inputStream
+ * @param exceptionListener
+ * @param decoderContext
+ * @param cl
+ */
+ public PersistenceParser(
+ InputStream inputStream,
+ ExceptionListener exceptionListener,
+ ClassLoader cl,
+ XMLDecoder decoder)
+ {
+
+ this.exceptionListener = exceptionListener;
+ this.decoder = decoder;
+
+ DummyHandler dummyHandler = new DummyHandler();
+ currentHandler = dummyHandler;
+ javaHandler = new JavaHandler(dummyHandler, this, cl);
+
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+
+ SAXParser parser;
+ try
+ {
+ parser = factory.newSAXParser();
+ }
+ catch (ParserConfigurationException pce)
+ {
+ // should not happen when a parser is available because we did
+ // not request any requirements on the XML parser
+ throw (InternalError) new InternalError(
+ "No SAX Parser available.").initCause(
+ pce);
+ }
+ catch (SAXException saxe)
+ {
+ // should not happen when a parser is available because we did
+ // not request any requirements on the XML parser
+ throw (InternalError) new InternalError(
+ "No SAX Parser available.").initCause(
+ saxe);
+ }
+
+ // prepares a map of Creator instances which can instantiate a handler which is
+ // appropriate for the tag that is used as a key for the Creator
+ handlerCreators.put("java", new JavaHandlerCreator());
+
+ // calls methods (properties), constructors, access fields
+ handlerCreators.put("object", new ObjectHandlerCreator());
+ handlerCreators.put("void", new VoidHandlerCreator());
+
+ handlerCreators.put("array", new ArrayHandlerCreator());
+
+ // these handler directly create an Object (or null)
+ handlerCreators.put("class", new ClassHandlerCreator());
+ handlerCreators.put("null", new NullHandlerCreator());
+
+ handlerCreators.put("char", new CharHandlerCreator());
+ handlerCreators.put("string", new StringHandlerCreator());
+ handlerCreators.put("boolean", new BooleanHandlerCreator());
+ handlerCreators.put("byte", new ByteHandlerCreator());
+ handlerCreators.put("short", new ShortHandlerCreator());
+ handlerCreators.put("int", new IntHandlerCreator());
+ handlerCreators.put("long", new LongHandlerCreator());
+ handlerCreators.put("float", new FloatHandlerCreator());
+ handlerCreators.put("double", new DoubleHandlerCreator());
+
+ // parses the data and sends all exceptions to the ExceptionListener
+ try
+ {
+ parser.parse(inputStream, this);
+ }
+ catch (SAXException saxe)
+ {
+ exceptionListener.exceptionThrown(
+ new IllegalArgumentException("XML data not well-formed."));
+ }
+ catch (IOException ioe)
+ {
+ exceptionListener.exceptionThrown(ioe);
+ }
+ }
+
+ public void startElement(
+ String uri,
+ String localName,
+ String qName,
+ Attributes attributes)
+ throws SAXException
+ {
+ /* The element is skipped if
+ * a) the current handler has already failed or a previous error occured
+ * which makes all children obsolete
+ */
+ if (currentHandler.hasFailed() || skipElement > 0)
+ {
+ exceptionListener.exceptionThrown(
+ new IllegalArgumentException(
+ "Element unusable due to previous error: " + qName));
+
+ skipElement++;
+
+ return;
+ }
+
+ /* b) Subelements are not allowed within the current ElementHandler.
+ */
+ if (!currentHandler.isSubelementAllowed(qName))
+ {
+ exceptionListener.exceptionThrown(
+ new IllegalArgumentException(
+ "Element is not allowed here: " + qName));
+
+ skipElement++;
+
+ return;
+ }
+
+ /* c) The tag name is not a key in the map of Creator instances. This means that
+ * either the XML data is of a newer version or simply contains a miss-spelled element.
+ */
+ if (!handlerCreators.containsKey(qName))
+ {
+ exceptionListener.exceptionThrown(
+ new IllegalArgumentException(
+ "Element unusable because tag is unknown: " + qName));
+
+ skipElement++;
+
+ return;
+ }
+
+ // creates a new handler for the new element
+ AbstractElementHandler handler =
+ ((Creator) handlerCreators.get(qName)).createHandler(
+ currentHandler);
+
+ // makes it the current handler to receive character data
+ currentHandler = handler;
+
+ // starts the handler
+ currentHandler.start(attributes, exceptionListener);
+ }
+
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException
+ {
+ // skips processing the current handler if we are parsing an element
+ // which was marked invalid (in startElement() )
+ if (skipElement > 0)
+ {
+ skipElement--;
+ return;
+ }
+
+ // invokes the handler's finishing method
+ currentHandler.end(exceptionListener);
+
+ // removes the current handler and reactivates its parent
+ currentHandler = currentHandler.getParent();
+ }
+
+ /** Transfers character data to the current handler
+ */
+ public void characters(char[] ch, int start, int length)
+ throws SAXException
+ {
+ // prevents sending character data of invalid elements
+ if (skipElement > 0)
+ return;
+
+ currentHandler.characters(ch, start, length);
+ }
+
+ /** Creator interface provided a mechanism to instantiate ElementHandler instances
+ * for the appropriate tag.
+ *
+ * @author Robert Schuster
+ */
+ interface Creator
+ {
+ /** Creates an ElementHandler instance using the given ElementHandler as its parent.
+ *
+ * @param parent The parent ElementHandler of the result.
+ * @return A new ElementHandler instance.
+ */
+ AbstractElementHandler createHandler(ElementHandler parent);
+ }
+
+ class BooleanHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new BooleanHandler(parent);
+ }
+ }
+
+ class ByteHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new ByteHandler(parent);
+ }
+ }
+
+ class ShortHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new ShortHandler(parent);
+ }
+ }
+
+ class IntHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new IntHandler(parent);
+ }
+ }
+
+ class LongHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new LongHandler(parent);
+ }
+ }
+
+ class FloatHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new FloatHandler(parent);
+ }
+ }
+
+ class DoubleHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new DoubleHandler(parent);
+ }
+ }
+
+ class CharHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new CharHandler(parent);
+ }
+ }
+
+ class StringHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new StringHandler(parent);
+ }
+ }
+
+ class JavaHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return javaHandler;
+ }
+ }
+
+ class ObjectHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new ObjectHandler(parent);
+ }
+ }
+
+ class VoidHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new VoidHandler(parent);
+ }
+ }
+
+ class ClassHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new ClassHandler(parent);
+ }
+ }
+
+ class NullHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new NullHandler(parent);
+ }
+ }
+
+ class ArrayHandlerCreator implements Creator
+ {
+ public AbstractElementHandler createHandler(ElementHandler parent)
+ {
+ return new ArrayHandler(parent);
+ }
+ }
+
+ /** Adds a decoded object to the Context. */
+ public void addParameterObject(Object o) throws AssemblyException
+ {
+ objects.add(o);
+ }
+
+ public void notifyStatement(Context outerContext) throws AssemblyException
+ {
+ // can be ignored because theis Context does not react to statement and expressions
+ // differently
+ }
+
+ public Object endContext(Context outerContext) throws AssemblyException
+ {
+ return null;
+ }
+
+ public boolean subContextFailed()
+ {
+ // failing of subcontexts is no problem for the mother of all contexts
+ return false;
+ }
+
+ public void set(int index, Object o) throws AssemblyException
+ {
+ // not supported
+ throw new AssemblyException(
+ new IllegalArgumentException("Set method is not allowed in decoder context."));
+ }
+
+ public Object get(int index) throws AssemblyException
+ {
+ // not supported
+ throw new AssemblyException(
+ new IllegalArgumentException("Get method is not allowed in decoder context."));
+ }
+
+ public Object getResult()
+ {
+ // returns the XMLDecoder instance which is requested by child contexts this way.
+ // That is needed to invoke methods on the decoder.
+ return decoder;
+ }
+
+ public void setId(String id)
+ {
+ exceptionListener.exceptionThrown(new IllegalArgumentException("id attribute is not allowed for <java> tag."));
+ }
+
+ public String getId()
+ {
+ // appears to have no id
+ return null;
+ }
+
+ public boolean isStatement()
+ {
+ // this context is a statement by definition because it never returns anything to a parent because
+ // there is no such parent (DummyContext does not count!)
+ return true;
+ }
+
+ public void setStatement(boolean b)
+ {
+ // ignores that because this Context is always a statement
+ }
+
+ /** Returns an Iterator instance which returns the decoded objects.
+ *
+ * This method is used by the XMLDecoder directly.
+ */
+ public Iterator iterator()
+ {
+ return objects.iterator();
+ }
}