mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			486 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			486 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Java
		
	
	
	
/* gnu.java.beans.PersistenceParser
 | 
						|
   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath 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
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
package gnu.java.beans.decoder;
 | 
						|
 | 
						|
import java.beans.ExceptionListener;
 | 
						|
import java.beans.XMLDecoder;
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.InputStream;
 | 
						|
import java.util.HashMap;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.LinkedList;
 | 
						|
import java.util.List;
 | 
						|
 | 
						|
import javax.xml.parsers.ParserConfigurationException;
 | 
						|
import javax.xml.parsers.SAXParser;
 | 
						|
import javax.xml.parsers.SAXParserFactory;
 | 
						|
 | 
						|
import org.xml.sax.Attributes;
 | 
						|
import org.xml.sax.SAXException;
 | 
						|
import org.xml.sax.helpers.DefaultHandler;
 | 
						|
 | 
						|
/** The PersistenceParser parses an XML data stream and delegates actions to ElementHandler
 | 
						|
 * instances. The parser catches and recovers from all exception which reside from wrong usage
 | 
						|
 * of attributes and tags.
 | 
						|
 *
 | 
						|
 * @author Robert Schuster
 | 
						|
 */
 | 
						|
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();
 | 
						|
	}
 | 
						|
 | 
						|
}
 |