Author: skitching Date: Tue Feb 8 18:40:19 2005 New Revision: 152977 URL: http://svn.apache.org/viewcvs?view=rev&rev=152977 Log: Major rework.
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/AbstractObjectFactory.java - copied, changed from r151291, jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/AbstractObjectCreationFactory.java jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/ObjectFactory.java - copied, changed from r151291, jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/ObjectCreationFactory.java Removed: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/AbstractObjectCreationFactory.java jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/ObjectCreationFactory.java Modified: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/CreateObjectWithFactoryAction.java (contents, props changed) Copied: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/AbstractObjectFactory.java (from r151291, jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/AbstractObjectCreationFactory.java) URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/AbstractObjectFactory.java?view=diff&rev=152977&p1=jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/AbstractObjectCreationFactory.java&r1=151291&p2=jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/AbstractObjectFactory.java&r2=152977 ============================================================================== --- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/AbstractObjectCreationFactory.java (original) +++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/AbstractObjectFactory.java Tue Feb 8 18:40:19 2005 @@ -1,6 +1,6 @@ -/* $Id: $ +/* $Id$ * - * Copyright 2001-2004 The Apache Software Foundation. + * Copyright 2001-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,22 +21,31 @@ import org.apache.commons.digester2.ParseException; /** - * <p>Abstract base class for <code>ObjectCreationFactory</code> - * implementations.</p> + * Abstract base class for <code>ObjectFactory</code> implementations. + * <p> + * Note that extending this abstract class rather than directly implementing + * the ObjectFactory interface provides much better "forward compatibility". + * Digester minor releases (2.x -> 2.y) guarantee not to break any classes that + * subclass this abstract class. However no such guarantee exists for classes + * that directly implement the ObjectFactory interface. */ -abstract public class AbstractObjectCreationFactory implements ObjectCreationFactory { - // --------------------------------------------------------- Public Methods +abstract public class AbstractObjectFactory implements ObjectFactory { /** * <p>Factory method called by [EMAIL PROTECTED] CreateObjectWithFactoryAction} to - * supply an object based on the element's attributes. + * supply an object based.</p> * - * @param attributes the element's attributes + * <p>Note in particular that implementations of this method have the + * option of inspecting the element's attributes to determine what kind + * of object to create.</p> * - * @throws Exception any exception thrown will be propagated upwards + * @param context is the current parsing context. + * @param attributes is the current element's set of xml attributes. + * + * @throws ParseException if a problem of any sort occurs. Any such + * exception will terminate parsing. */ public abstract Object createObject(Context context, Attributes attributes) throws ParseException; - } Modified: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/CreateObjectWithFactoryAction.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/CreateObjectWithFactoryAction.java?view=diff&r1=152976&r2=152977 ============================================================================== --- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/CreateObjectWithFactoryAction.java (original) +++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/CreateObjectWithFactoryAction.java Tue Feb 8 18:40:19 2005 @@ -1,19 +1,19 @@ -/* $Id: $ +/* $Id$ + * + * Copyright 2001-2005 The Apache Software Foundation. * - * Copyright 2001-2004 The Apache Software Foundation. - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ + */ package org.apache.commons.digester2.actions; @@ -28,51 +28,95 @@ import org.apache.commons.digester2.ArrayStack; /** - * <p>Rule implementation that uses an [EMAIL PROTECTED] ObjectCreationFactory} to create - * a new object which it pushes onto the object stack. When the element is - * complete, the object will be popped.</p> + * <p>An Action that uses an [EMAIL PROTECTED] ObjectFactory} to create a new object + * which it pushes onto the object stack. When the element is complete, the + * object is popped from that stack.</p> + * + * <p>This action is intended in situations where instances of different classes + * may be created and the CreateObjectAction is not sufficiently flexible. It + * does require a custom ObjectFactory implementation to be written in order to + * implement the logic which decides what class the new instance is created + * from.</p> * - * <p>This rule is intended in situations where the element's attributes are - * needed before the object can be created. A common scenario is for the - * ObjectCreationFactory implementation to use the attributes as parameters - * in a call to either a factory method or to a non-empty constructor. + * <p>A common scenario is for the ObjectFactory implementation to use the + * xml attributes of the matched xml element as parameters in a call to either + * a factory method or to a non-empty constructor.</p> */ public class CreateObjectWithFactoryAction extends AbstractAction { - // ----------------------------------------------------------- Fields - - /** Should exceptions thrown by the factory be ignored? */ - private boolean ignoreCreateExceptions; - /** Stock to manage */ - private ArrayStack exceptionIgnoredStack; + // ----------------------------------------------------- + // Instance Variables + // ----------------------------------------------------- - // ----------------------------------------------------------- Constructors + /** + * The object creation factory (if any) explicitly provided to a + * constructor. Note that (as per Action requirements) this value + * never changes during parsing; if this is initially null, and + * an ObjectFactory is later created, then that object is stored + * on the Context, not here. + */ + protected ObjectFactory objectFactory = null; /** - * <p>Construct a factory create rule that will use the specified - * class name to create an [EMAIL PROTECTED] ObjectCreationFactory} which will - * then be used to create an object and push it on the stack.</p> + * The Java class name of the ObjectCreationFactory to be created. + * This class must have a no-arguments constructor. Not relevant + * if creationFactory is non-null. + */ + protected String factoryClassName = null; + + /** + * The attribute containing an override class name if it is present. + */ + protected String attributeName = null; + + // ----------------------------------------------------------- + // Constructors + // ----------------------------------------------------------- + + /** + * Construct a factory create rule using the given [EMAIL PROTECTED] ObjectFactory}. + * <p> + * Exceptions thrown during the object creation process will be propagated. + * + * @param factory called on to create the object. + */ + public CreateObjectWithFactoryAction(ObjectFactory factory) { + this.objectFactory = factory; + } + + /** + * <p>Create an object that will use the specified class name to create + * an [EMAIL PROTECTED] ObjectFactory} which will then be used to create an object + * and push it on the stack.</p> + * + * <p>The SAXHandler.getClassLoader method will be used to obtain a + * classloader to load the specified class through.</p> * * <p>Exceptions thrown during the object creation process will be propagated.</p> * * @param className Java class name of the object creation factory class */ public CreateObjectWithFactoryAction(String className) { - this(className, false); + this.factoryClassName = className; } /** - * <p>Construct a factory create rule that will use the specified - * class to create an [EMAIL PROTECTED] ObjectCreationFactory} which will - * then be used to create an object and push it on the stack.</p> + * <p>Create an object that will use the specified class name to create + * an [EMAIL PROTECTED] ObjectFactory} which will then be used to create an object + * and push it on the stack.</p> * * <p>Exceptions thrown during the object creation process will be propagated.</p> * + * <p>Note that this is equivalent to calling + * <code>CreateObjectWithFactoryAction(clazz.getName())</code>. + * In particular, the classloader associated with the clazz parameter + * is ignored.</p> + * * @param clazz Java class name of the object creation factory class */ public CreateObjectWithFactoryAction(Class clazz) { - this(clazz, false); + this.factoryClassName = clazz.getName(); } /** @@ -88,15 +132,21 @@ * override of the class name of the object creation factory to create. */ public CreateObjectWithFactoryAction(String className, String attributeName) { - this(className, attributeName, false); + this.factoryClassName = className; + this.attributeName = attributeName; } /** * <p>Construct a factory create rule that will use the specified * class (possibly overridden by the specified attribute if present) - * to create an [EMAIL PROTECTED] ObjectCreationFactory}, which will then be used + * to create an [EMAIL PROTECTED] ObjectFactory}, which will then be used * to instantiate an object instance and push it onto the stack.</p> * + * <p>Note that this is equivalent to calling + * <code>CreateObjectWithFactoryAction(clazz.getName(), attributeName)</code>. + * In particular, the classloader associated with the clazz parameter + * is ignored.</p> + * * <p>Exceptions thrown during the object creation process will be propagated.</p> * * @param clazz Default Java class name of the factory class @@ -104,137 +154,13 @@ * override of the class name of the object creation factory to create. */ public CreateObjectWithFactoryAction(Class clazz, String attributeName) { - this(clazz, attributeName, false); - } - - /** - * <p>Construct a factory create rule using the given, already instantiated, - * [EMAIL PROTECTED] ObjectCreationFactory}.</p> - * - * <p>Exceptions thrown during the object creation process will be propagated.</p> - * - * @param creationFactory called on to create the object. - */ - public CreateObjectWithFactoryAction(ObjectCreationFactory creationFactory) { - this(creationFactory, false); - } - - /** - * Construct a factory create rule that will use the specified - * class name to create an [EMAIL PROTECTED] ObjectCreationFactory} which will - * then be used to create an object and push it on the stack. - * - * @param className Java class name of the object creation factory class - * @param ignoreCreateExceptions if true, exceptions thrown by the object - * creation factory - * will be ignored. - */ - public CreateObjectWithFactoryAction(String className, boolean ignoreCreateExceptions) { - this(className, null, ignoreCreateExceptions); - } - - /** - * Construct a factory create rule that will use the specified - * class to create an [EMAIL PROTECTED] ObjectCreationFactory} which will - * then be used to create an object and push it on the stack. - * - * @param clazz Java class name of the object creation factory class - * @param ignoreCreateExceptions if true, exceptions thrown by the - * object creation factory - * will be ignored. - */ - public CreateObjectWithFactoryAction(Class clazz, boolean ignoreCreateExceptions) { - this(clazz, null, ignoreCreateExceptions); - } - - /** - * Construct a factory create rule that will use the specified - * class name (possibly overridden by the specified attribute if present) - * to create an [EMAIL PROTECTED] ObjectCreationFactory}, which will then be used - * to instantiate an object instance and push it onto the stack. - * - * @param className Default Java class name of the factory class - * @param attributeName Attribute name which, if present, contains an - * override of the class name of the object creation factory to create. - * @param ignoreCreateExceptions if true, exceptions thrown by the object - * creation factory will be ignored. - */ - public CreateObjectWithFactoryAction( - String className, - String attributeName, - boolean ignoreCreateExceptions) { - - this.className = className; + this.factoryClassName = clazz.getName(); this.attributeName = attributeName; - this.ignoreCreateExceptions = ignoreCreateExceptions; - - } - - - /** - * Construct a factory create rule that will use the specified - * class (possibly overridden by the specified attribute if present) - * to create an [EMAIL PROTECTED] ObjectCreationFactory}, which will then be used - * to instantiate an object instance and push it onto the stack. - * - * @param clazz Default Java class name of the factory class - * @param attributeName Attribute name which, if present, contains an - * override of the class name of the object creation factory to create. - * @param ignoreCreateExceptions if true, exceptions thrown by the object - * creation factory will be ignored. - */ - public CreateObjectWithFactoryAction( - Class clazz, - String attributeName, - boolean ignoreCreateExceptions) { - - this(clazz.getName(), attributeName, ignoreCreateExceptions); - } - - /** - * Construct a factory create rule using the given, already instantiated, - * [EMAIL PROTECTED] ObjectCreationFactory}. - * - * @param creationFactory called on to create the object. - * @param ignoreCreateExceptions if true, exceptions thrown by the object - * creation factory will be ignored. - */ - public CreateObjectWithFactoryAction( - ObjectCreationFactory creationFactory, - boolean ignoreCreateExceptions) { - - this.creationFactory = creationFactory; - this.ignoreCreateExceptions = ignoreCreateExceptions; - } - - // ----------------------------------------------------- Instance Variables - - - /** - * The attribute containing an override class name if it is present. - */ - protected String attributeName = null; - - - /** - * The Java class name of the ObjectCreationFactory to be created. - * This class must have a no-arguments constructor. - */ - protected String className = null; - - - /** - * The object creation factory we will use to instantiate objects - * as required based on the attributes specified in the matched XML - * element. - */ - protected ObjectCreationFactory creationFactory = null; - - - // --------------------------------------------------------- Public Methods - + // --------------------------------------------------------- + // Public Methods + // --------------------------------------------------------- /** * Process the beginning of this element. @@ -242,156 +168,123 @@ * @param attributes The attribute list of this element */ public void begin( - Context context, String namespace, String name, Attributes attributes) + Context context, + String namespace, String name, Attributes attributes) throws ParseException { - Log log = context.getLogger(); - - if (ignoreCreateExceptions) { - - if (exceptionIgnoredStack == null) { - exceptionIgnoredStack = new ArrayStack(); - } - - try { - Object instance = - getFactory(context, attributes).createObject(context, attributes); - - if (log.isDebugEnabled()) { - log.debug("[CreateObjectWithFactoryAction]{" + context.getMatchPath() + - "} New " + instance.getClass().getName()); - } - context.push(instance); - exceptionIgnoredStack.push(Boolean.FALSE); - - } catch (Exception e) { - // log message and error - if (log.isInfoEnabled()) { - log.info("[CreateObjectWithFactoryAction] Create exception ignored: " + - ((e.getMessage() == null) ? e.getClass().getName() : e.getMessage())); - if (log.isDebugEnabled()) { - log.debug("[CreateObjectWithFactoryAction] Ignored exception:", e); - } - } - exceptionIgnoredStack.push(Boolean.TRUE); - } - - } else { - Object instance = getFactory(context, attributes).createObject(context, attributes); - - if (log.isDebugEnabled()) { - log.debug("[CreateObjectWithFactoryAction]{" + context.getMatchPath() + - "} New " + instance.getClass().getName()); - } - context.push(instance); + + ObjectFactory factory = getFactory(context, attributes); + Object instance = factory.createObject(context, attributes); + + if (log.isDebugEnabled()) { + log.debug("[CreateObjectWithFactoryAction]{" + context.getMatchPath() + + "} New " + instance.getClass().getName()); } + context.push(instance); } - /** * Process the end of this element. */ public void end( - Context context, String namespace, String name) + Context context, String namespace, String name) throws ParseException { - Log log = context.getLogger(); - // check if object was created - // this only happens if an exception was thrown and we're ignoring them - if ( - ignoreCreateExceptions && - exceptionIgnoredStack != null && - !(exceptionIgnoredStack.empty())) { - - if (((Boolean) exceptionIgnoredStack.pop()).booleanValue()) { - // creation exception was ignored - // nothing was put onto the stack - if (log.isTraceEnabled()) { - log.trace("[CreateObjectWithFactoryAction] No creation so no push so no pop"); - } - return; - } - } - Object top = context.pop(); if (log.isDebugEnabled()) { log.debug("[CreateObjectWithFactoryAction]{" + context.getMatchPath() + "} Pop " + top.getClass().getName()); } - - } - - - /** - * Clean up after parsing is complete. - */ - public void finishParse() throws ParseException { - if (attributeName != null) { - creationFactory = null; - } } /** * Render a printable version of this Rule. */ public String toString() { - StringBuffer sb = new StringBuffer("CreateObjectWithFactoryAction["); - sb.append("className="); - sb.append(className); - sb.append(", attributeName="); - sb.append(attributeName); - if (creationFactory != null) { - sb.append(", creationFactory="); - sb.append(creationFactory); + if (objectFactory != null) { + sb.append(", objectFactory="); + sb.append(objectFactory); + } else { + sb.append("className="); + sb.append(factoryClassName); + sb.append(", attributeName="); + sb.append(attributeName); } sb.append("]"); return (sb.toString()); - } - - // ------------------------------------------------------ Protected Methods + // ------------------------------------------------------ + // Protected Methods + // ------------------------------------------------------ /** - * Return an instance of our associated object creation factory, - * creating one if necessary. + * Return an instance of our associated object factory, + * creating one if necessary. Factory instances created here are + * cached for future reuse by this Action instance (but other instances + * of this same class will create their own ObjectFactory instances). * * @param attributes Attributes passed to our factory creation element * * @exception Exception if any error occurs */ - protected ObjectCreationFactory getFactory( + protected ObjectFactory getFactory( Context context, Attributes attributes) throws ParseException { + + if (objectFactory != null) { + // if objectFactory is set, then className and attributeName + // will always be null... + return objectFactory; + } Log log = context.getLogger(); - if (creationFactory == null) { - String realClassName = className; - if (attributeName != null) { - String value = attributes.getValue(attributeName); - if (value != null) { - realClassName = value; - } + String realClassName = factoryClassName; + if (attributeName != null) { + String overrideClassName = attributes.getValue(attributeName); + if (overrideClassName != null) { + realClassName = overrideClassName; } + } + + // now retrieve the cached ObjectFactory for this classname + ObjectFactory factory = + (ObjectFactory) context.getInstanceData(this, "objectFactory"); + + if (factory == null) { + // this rule instance has never created a factory of this class if (log.isDebugEnabled()) { log.debug("[CreateObjectWithFactoryAction]{" + context.getMatchPath() + "} New factory " + realClassName); } + try { - Class clazz = context.getClassLoader().loadClass(realClassName); - creationFactory = (ObjectCreationFactory) - clazz.newInstance(); + // create the factory object + Class clazz = context.getClassLoader().loadClass(realClassName); + factory = (ObjectFactory) clazz.newInstance(); + + // and cache the object for later retrieval by this instance + context.putInstanceData(this, "objectFactory", factory); } catch(ClassNotFoundException ex) { - throw new ParseException("Unable to load class '" + realClassName + "'", ex); + throw new ParseException( + "Unable to load class '" + realClassName + "'", ex); } catch(InstantiationException ex) { - throw new ParseException("Unable to create instance of class '" + realClassName + "'", ex); + throw new ParseException( + "Unable to create instance of class '" + realClassName + "'", ex); } catch(IllegalAccessException ex) { - throw new ParseException("Unable to access constructor of class '" + realClassName + "'", ex); + throw new ParseException( + "Unable to access constructor of class '" + realClassName + "'", ex); + } + } else { + if (log.isDebugEnabled()) { + log.debug("[CreateObjectWithFactoryAction]{" + context.getMatchPath() + + "} Reusing cached factory " + realClassName); } } - return creationFactory; - } + + return factory; + } } Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/CreateObjectWithFactoryAction.java ------------------------------------------------------------------------------ svn:keywords = Id Copied: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/ObjectFactory.java (from r151291, jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/ObjectCreationFactory.java) URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/ObjectFactory.java?view=diff&rev=152977&p1=jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/ObjectCreationFactory.java&r1=151291&p2=jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/ObjectFactory.java&r2=152977 ============================================================================== --- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/ObjectCreationFactory.java (original) +++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/actions/ObjectFactory.java Tue Feb 8 18:40:19 2005 @@ -1,6 +1,6 @@ -/* $Id: $ +/* $Id$ * - * Copyright 2001-2004 The Apache Software Foundation. + * Copyright 2001-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,33 +17,46 @@ package org.apache.commons.digester2.actions; - import org.xml.sax.Attributes; - import org.apache.commons.digester2.Context; import org.apache.commons.digester2.AbstractAction; import org.apache.commons.digester2.ParseException; /** - * <p> Interface for use with [EMAIL PROTECTED] FactoryCreateAction}. - * The rule calls [EMAIL PROTECTED] #createObject} to create an object - * to be pushed onto the <code>Digester</code> stack - * whenever it is matched.</p> - * - * <p> [EMAIL PROTECTED] AbstractObjectCreationFactory} is an abstract - * implementation suitable for creating anonymous - * <code>ObjectCreationFactory</code> implementations. + * Interface for use with [EMAIL PROTECTED] CreateObjectWithFactoryAction}. + * <p> + * When that action is fired, it calls method [EMAIL PROTECTED] #createObject} on some + * implementation of this interface to create an object to be pushed onto the + * <code>Digester</code> stack. + * <p> + * Class [EMAIL PROTECTED] AbstractObjectFactory} is an abstract implementation + * suitable for creating anonymous <code>ObjectFactory</code> implementations. + * <p> + * <strong>IMPORTANT NOTE</strong>: Anyone implementing a custom ObjectFactory + * is strongly encouraged to subclass AbstractObjectFactory rather than + * implement this interface directly. Digester minor releases (2.x -> 2.y) + * guarantee that subclasses of AbstractObjectFactory will not be broken. + * However the ObjectFactory interface <i>may</i> change in minor releases, + * which will break any class which implements this interface directly. */ -public interface ObjectCreationFactory { +public interface ObjectFactory { /** - * <p>Factory method called by [EMAIL PROTECTED] FactoryCreateAction} to supply an - * object based on the element's attributes. + * <p>Factory method called by [EMAIL PROTECTED] CreateObjectWithFactoryAction} to + * supply an object based.</p> + * + * <p>Note in particular that implementations of this method have the + * option of inspecting the element's attributes to determine what kind + * of object to create. Note also that when accessing attributes that are + * not in any namespace, the empty string should be passed eg + * <code>String value = attributes.getValue("", "attrName");</code>.</p> * - * @param attributes the element's attributes + * @param context is the current parsing context. + * @param attributes is the current element's set of xml attributes. * - * @throws Exception any exception thrown will be propagated upwards + * @throws ParseException if a problem of any sort occurs. Any such + * exception will terminate parsing. */ public Object createObject(Context context, Attributes attributes) throws ParseException; --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]