mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			317 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			317 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* gnu.java.beans.decoder.AbstractElementHandler
 | |
|    Copyright (C) 2004 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 org.xml.sax.Attributes;
 | |
| 
 | |
| /** ElementHandler manages a Context instance and interacts with
 | |
|  * its parent and child handlers.
 | |
|  *
 | |
|  * @author Robert Schuster
 | |
|  */
 | |
| abstract class AbstractElementHandler implements ElementHandler
 | |
| {
 | |
|   /** The Context instance of this handler. The instance is available after the startElement()
 | |
|    * method was called. Otherwise the handler is marked as failed.
 | |
|    */
 | |
|   private Context context;
 | |
| 
 | |
|   /** The parent handler. */
 | |
|   private ElementHandler parent;
 | |
| 
 | |
|   /** Stores whether this handler is marked as failed. */
 | |
|   private boolean hasFailed;
 | |
| 
 | |
|   /** Stores the character data which is contained in the body of the XML tag. */
 | |
|   private StringBuffer buffer = new StringBuffer();
 | |
| 
 | |
|   /** Stores whether this ElementHandler can have subelements. The information for this is taken from
 | |
|    * javabeans.dtd which can be found here:
 | |
|    * <a href="http://java.sun.com/products/jfc/tsc/articles/persistence3/">Java Persistence Article</a>
 | |
|    */
 | |
|   private boolean allowsSubelements;
 | |
| 
 | |
|   /** Creates a new ElementHandler with the given ElementHandler instance
 | |
|    * as parent.
 | |
|    *
 | |
|    * @param parentHandler The parent handler.
 | |
|    */
 | |
|   protected AbstractElementHandler(ElementHandler parentHandler,
 | |
|                                    boolean allowsSubs)
 | |
|   {
 | |
|     parent = parentHandler;
 | |
|     allowsSubelements = allowsSubs;
 | |
|   }
 | |
| 
 | |
|   /** Evaluates the attributes and creates a Context instance.
 | |
|    * If the creation of the Context instance fails the ElementHandler
 | |
|    * is marked as failed which may affect the parent handler other.
 | |
|    *
 | |
|    * @param attributes Attributes of the XML tag.
 | |
|    */
 | |
|   public final void start(Attributes attributes,
 | |
|                           ExceptionListener exceptionListener)
 | |
|   {
 | |
|     try
 | |
|       {
 | |
|         // lets the subclass create the appropriate Context instance
 | |
|         context = startElement(attributes, exceptionListener);
 | |
|       }
 | |
|     catch (AssemblyException pe)
 | |
|       {
 | |
|         Throwable t = pe.getCause();
 | |
| 
 | |
|         if (t instanceof Exception)
 | |
|           exceptionListener.exceptionThrown((Exception) t);
 | |
|         else
 | |
|           throw new InternalError("Unexpected Throwable type in AssemblerException. Please file a bug report.");
 | |
| 
 | |
|         notifyContextFailed();
 | |
| 
 | |
|         return;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /** Analyses the content of the Attributes instance and creates a Context
 | |
|    * object accordingly.
 | |
|    * An AssemblerException is thrown when the Context instance could not
 | |
|    * be created.
 | |
|    *
 | |
|    * @param attributes Attributes of the XML tag.
 | |
|    * @return A Context instance.
 | |
|    * @throws AssemblerException when Context instance could not be created.
 | |
|    */
 | |
|   protected abstract Context startElement(Attributes attributes, ExceptionListener exceptionListener)
 | |
|     throws AssemblyException;
 | |
| 
 | |
|   /** Post-processes the Context.
 | |
|    */
 | |
|   public final void end(ExceptionListener exceptionListener)
 | |
|   {
 | |
|     // skips processing if the handler is marked as failed (because the Context
 | |
|     // is then invalid or may not exist at all)
 | |
|     if (!hasFailed)
 | |
|       {
 | |
|         try
 | |
|           {
 | |
|             // note: the order of operations is very important here
 | |
|             // sends the stored character data to the Context
 | |
|             endElement(buffer.toString());
 | |
| 
 | |
|             // reports to the parent handler if this handler's Context is a
 | |
|             // statement (returning no value BACK to the parent's Context)
 | |
|             if (context.isStatement())
 | |
|               {
 | |
|                 // This may create a valid result in the parent's Context
 | |
|                 // or let it fail
 | |
|                 parent.notifyStatement(exceptionListener);
 | |
| 
 | |
|                 // skips any further processing if the parent handler is now marked
 | |
|                 // as failed
 | |
|                 if (parent.hasFailed())
 | |
|                   return;
 | |
|               }
 | |
| 
 | |
|             // processes the Context and stores the result
 | |
|             putObject(context.getId(), context.endContext(parent.getContext()));
 | |
| 
 | |
|             // transfers the Context's results to the parent's Context
 | |
|             // if it is an expression (rather than a statement)
 | |
|             if (! context.isStatement())
 | |
|               parent.getContext().addParameterObject(context.getResult());
 | |
|           }
 | |
|         catch (AssemblyException pe)
 | |
|           {
 | |
|             // notifies that an exception was thrown in this handler's Context
 | |
|             Throwable t = pe.getCause();
 | |
| 
 | |
|             if (t instanceof Exception)
 | |
|               exceptionListener.exceptionThrown((Exception) t);
 | |
|             else
 | |
|               throw (InternalError) new InternalError("Severe problem while decoding XML data.")
 | |
|                     .initCause(t);
 | |
| 
 | |
|             // marks the handler as failed
 | |
|             notifyContextFailed();
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /** Notifies the handler's Context that its child Context will not return
 | |
|    * a value back. Some Context variants need this information to know when
 | |
|    * a method or a constructor call can be made.
 | |
|    *
 | |
|    * This method is called by a child handler.
 | |
|    */
 | |
|   public void notifyStatement(ExceptionListener exceptionListener)
 | |
|   {
 | |
|     try
 | |
|       {
 | |
| 
 | |
|         // propagates to parent handler first to generate objects
 | |
|         // needed by this Context instance
 | |
|         if(context.isStatement())
 | |
|         {
 | |
|                 parent.notifyStatement(exceptionListener);
 | |
|         }
 | |
| 
 | |
|         // Some Context instances do stuff which can fail now. If that
 | |
|         // happens this handler is marked as failed.
 | |
|         context.notifyStatement(parent.getContext());
 | |
|       }
 | |
|     catch (AssemblyException ae)
 | |
|       {
 | |
|         // notifies that an exception was thrown in this handler's Context
 | |
|         Throwable t = ae.getCause();
 | |
| 
 | |
|         if (t instanceof Exception)
 | |
|           exceptionListener.exceptionThrown((Exception) t);
 | |
|         else
 | |
|           throw (InternalError) new InternalError("Severe problem while decoding XML data.")
 | |
|                 .initCause(t);
 | |
| 
 | |
|         // marks the handler as failed
 | |
|         notifyContextFailed();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /** Marks this and any depending parent handlers as failed. Which means that on their end
 | |
|    * no result is calculated.
 | |
|    *
 | |
|    * When a handler has failed no more handlers are accepted within it.
 | |
|    */
 | |
|   public final void notifyContextFailed()
 | |
|   {
 | |
|     hasFailed = true;
 | |
| 
 | |
|     // marks the parent handler as failed if its Context
 | |
|     // is affected by the failure of this handler's Context
 | |
|     if (parent.getContext().subContextFailed())
 | |
|       parent.notifyContextFailed();
 | |
|   }
 | |
| 
 | |
|   /** Returns whether this handler has failed.
 | |
|    *
 | |
|    * This is used to skip child elements.
 | |
|    *
 | |
|    * @return Whether this handler has failed.
 | |
|    */
 | |
|   public final boolean hasFailed()
 | |
|   {
 | |
|     return hasFailed;
 | |
|   }
 | |
| 
 | |
|   /** Processes the character data when the element ends.
 | |
|    *
 | |
|    * The default implementation does nothing for convenience.
 | |
|    *
 | |
|    * @param characters
 | |
|    * @throws AssemblerException
 | |
|    */
 | |
|   protected void endElement(String characters) throws AssemblyException
 | |
|   {
 | |
|     // XXX: throw an exception when unexpected character data is available?
 | |
|   }
 | |
| 
 | |
|   /** Adds characters from the body of the XML tag to the buffer.
 | |
|    *
 | |
|    * @param ch
 | |
|    * @param start
 | |
|    * @param length
 | |
|    * @throws SAXException
 | |
|    */
 | |
|   public final void characters(char[] ch, int start, int length)
 | |
|   {
 | |
|     // simply appends character data
 | |
|     buffer.append(ch, start, length);
 | |
|   }
 | |
| 
 | |
|   /** Stores an object globally under a unique id. If the id is
 | |
|    * null the object is not stored.
 | |
|    *
 | |
|    * @param objectId
 | |
|    * @param o
 | |
|    */
 | |
|   public void putObject(String objectId, Object o)
 | |
|   {
 | |
|     if (objectId != null)
 | |
|       parent.putObject(objectId, o);
 | |
|   }
 | |
| 
 | |
|   /** Returns a previously stored object. If the id is null the
 | |
|    * result is null, too.
 | |
|    *
 | |
|    * @param objectId
 | |
|    * @return Returns a previously stored object or null.
 | |
|    */
 | |
|   public Object getObject(String objectId) throws AssemblyException
 | |
|   {
 | |
|     return objectId == null ? null : parent.getObject(objectId);
 | |
|   }
 | |
| 
 | |
|   /** Returns the Class instance as if called Class.forName() but
 | |
|    * uses a ClassLoader given by the user.
 | |
|    *
 | |
|    * @param className
 | |
|    * @return
 | |
|    * @throws ClassNotFoundException
 | |
|    */
 | |
|   public Class instantiateClass(String className)
 | |
|     throws ClassNotFoundException
 | |
|   {
 | |
|     return parent.instantiateClass(className);
 | |
|   }
 | |
| 
 | |
|   public final boolean isSubelementAllowed(String subElementName)
 | |
|   {
 | |
|     return allowsSubelements && ! subElementName.equals("java");
 | |
|   }
 | |
| 
 | |
|   public final Context getContext()
 | |
|   {
 | |
|     return context;
 | |
|   }
 | |
| 
 | |
|   public final ElementHandler getParent()
 | |
|   {
 | |
|     return parent;
 | |
|   }
 | |
| }
 |