| package org.apache.commons.digester3; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| import static java.lang.String.format; |
| |
| import java.util.Formatter; |
| import java.util.Stack; |
| |
| import org.xml.sax.Attributes; |
| |
| /** |
| * <p> |
| * Rule implementation that uses an {@link 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> |
| * This rule is intended in situations where the element's attributes are needed before the object can be created. A |
| * common senario 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. |
| */ |
| public class FactoryCreateRule |
| extends Rule |
| { |
| |
| // ----------------------------------------------------------- Fields |
| |
| /** Should exceptions thrown by the factory be ignored? */ |
| private boolean ignoreCreateExceptions; |
| |
| /** Stock to manage */ |
| private Stack<Boolean> exceptionIgnoredStack; |
| |
| // ----------------------------------------------------------- Constructors |
| |
| /** |
| * <p> |
| * Construct a factory create rule that will use the specified class name to create an {@link ObjectCreationFactory} |
| * 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> |
| * |
| * @param className Java class name of the object creation factory class |
| */ |
| public FactoryCreateRule( String className ) |
| { |
| this( className, false ); |
| } |
| |
| /** |
| * <p> |
| * Construct a factory create rule that will use the specified class to create an {@link ObjectCreationFactory} |
| * 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> |
| * |
| * @param clazz Java class name of the object creation factory class |
| */ |
| public FactoryCreateRule( Class<? extends ObjectCreationFactory<?>> clazz ) |
| { |
| this( clazz, false ); |
| } |
| |
| /** |
| * <p> |
| * Construct a factory create rule that will use the specified class name (possibly overridden by the specified |
| * attribute if present) to create an {@link ObjectCreationFactory}, which will then be used to instantiate an |
| * object instance and push it onto the stack. |
| * </p> |
| * <p> |
| * Exceptions thrown during the object creation process will be propagated. |
| * </p> |
| * |
| * @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. |
| */ |
| public FactoryCreateRule( String className, String attributeName ) |
| { |
| this( className, attributeName, false ); |
| } |
| |
| /** |
| * <p> |
| * Construct a factory create rule that will use the specified class (possibly overridden by the specified attribute |
| * if present) to create an {@link ObjectCreationFactory}, which will then be used to instantiate an object instance |
| * and push it onto the stack. |
| * </p> |
| * <p> |
| * Exceptions thrown during the object creation process will be propagated. |
| * </p> |
| * |
| * @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. |
| */ |
| public FactoryCreateRule( Class<? extends ObjectCreationFactory<?>> clazz, String attributeName ) |
| { |
| this( clazz, attributeName, false ); |
| } |
| |
| /** |
| * <p> |
| * Construct a factory create rule using the given, already instantiated, {@link ObjectCreationFactory}. |
| * </p> |
| * <p> |
| * Exceptions thrown during the object creation process will be propagated. |
| * </p> |
| * |
| * @param creationFactory called on to create the object. |
| */ |
| public FactoryCreateRule( ObjectCreationFactory<?> creationFactory ) |
| { |
| this( creationFactory, false ); |
| } |
| |
| /** |
| * Construct a factory create rule that will use the specified class name to create an {@link 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 FactoryCreateRule( String className, boolean ignoreCreateExceptions ) |
| { |
| this( className, null, ignoreCreateExceptions ); |
| } |
| |
| /** |
| * Construct a factory create rule that will use the specified class to create an {@link 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 FactoryCreateRule( Class<? extends ObjectCreationFactory<?>> 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 {@link 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 FactoryCreateRule( String className, String attributeName, boolean ignoreCreateExceptions ) |
| { |
| this.className = className; |
| 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 {@link 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 FactoryCreateRule( Class<? extends ObjectCreationFactory<?>> clazz, String attributeName, |
| boolean ignoreCreateExceptions ) |
| { |
| this( clazz.getName(), attributeName, ignoreCreateExceptions ); |
| } |
| |
| /** |
| * Construct a factory create rule using the given, already instantiated, {@link ObjectCreationFactory}. |
| * |
| * @param creationFactory called on to create the object. |
| * @param ignoreCreateExceptions if true, exceptions thrown by the object creation factory will be ignored. |
| */ |
| public FactoryCreateRule( 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 |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void begin( String namespace, String name, Attributes attributes ) |
| throws Exception |
| { |
| if ( ignoreCreateExceptions ) |
| { |
| if ( exceptionIgnoredStack == null ) |
| { |
| exceptionIgnoredStack = new Stack<Boolean>(); |
| } |
| |
| try |
| { |
| Object instance = getFactory( attributes ).createObject( attributes ); |
| |
| if ( getDigester().getLogger().isDebugEnabled() ) |
| { |
| getDigester().getLogger().debug( format( "[FactoryCreateRule]{%s} New %s", |
| getDigester().getMatch(), |
| ( instance == null ? "null object" |
| : instance.getClass().getName() ) ) ); |
| } |
| getDigester().push( instance ); |
| exceptionIgnoredStack.push( Boolean.FALSE ); |
| |
| } |
| catch ( Exception e ) |
| { |
| // log message and error |
| if ( getDigester().getLogger().isInfoEnabled() ) |
| { |
| getDigester().getLogger().info( format( "[FactoryCreateRule]{%s} Create exception ignored: %s", |
| getDigester().getMatch(), |
| ( ( e.getMessage() == null ) ? e.getClass().getName() |
| : e.getMessage() ) ) ); |
| if ( getDigester().getLogger().isDebugEnabled() ) |
| { |
| getDigester().getLogger().debug( "[FactoryCreateRule] Ignored exception:", e ); |
| } |
| } |
| exceptionIgnoredStack.push( Boolean.TRUE ); |
| } |
| |
| } |
| else |
| { |
| Object instance = getFactory( attributes ).createObject( attributes ); |
| |
| if ( getDigester().getLogger().isDebugEnabled() ) |
| { |
| getDigester().getLogger().debug( format( "[FactoryCreateRule]{%s} New %s", |
| getDigester().getMatch(), |
| ( instance == null ? "null object" |
| : instance.getClass().getName() ) ) ); |
| } |
| getDigester().push( instance ); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void end( String namespace, String name ) |
| throws Exception |
| { |
| // 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 ( exceptionIgnoredStack.pop().booleanValue() ) |
| { |
| // creation exception was ignored |
| // nothing was put onto the stack |
| if ( getDigester().getLogger().isTraceEnabled() ) |
| { |
| getDigester().getLogger().trace( format( "[FactoryCreateRule]{%s} No creation so no push so no pop", |
| getDigester().getMatch() ) ); |
| } |
| return; |
| } |
| } |
| |
| Object top = getDigester().pop(); |
| if ( getDigester().getLogger().isDebugEnabled() ) |
| { |
| getDigester().getLogger().debug( format( "[FactoryCreateRule]{%s} Pop %s", |
| getDigester().getMatch(), |
| top.getClass().getName() ) ); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void finish() |
| throws Exception |
| { |
| if ( attributeName != null ) |
| { |
| creationFactory = null; |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public String toString() |
| { |
| Formatter formatter = new Formatter().format( "FactoryCreateRule[className=%s, attributeName=%s", |
| className, attributeName ); |
| if ( creationFactory != null ) |
| { |
| formatter.format( ", creationFactory=%s", creationFactory ); |
| } |
| formatter.format( "]" ); |
| return ( formatter.toString() ); |
| } |
| |
| // ------------------------------------------------------ Protected Methods |
| |
| /** |
| * Return an instance of our associated object creation factory, creating one if necessary. |
| * |
| * @param attributes Attributes passed to our factory creation element |
| * @return An instance of our associated object creation factory, creating one if necessary |
| * @exception Exception if any error occurs |
| */ |
| protected ObjectCreationFactory<?> getFactory( Attributes attributes ) |
| throws Exception |
| { |
| if ( creationFactory == null ) |
| { |
| String realClassName = className; |
| if ( attributeName != null ) |
| { |
| String value = attributes.getValue( attributeName ); |
| if ( value != null ) |
| { |
| realClassName = value; |
| } |
| } |
| if ( getDigester().getLogger().isDebugEnabled() ) |
| { |
| getDigester().getLogger().debug( format( "[FactoryCreateRule]{%s} New factory %s", |
| getDigester().getMatch(), realClassName ) ); |
| } |
| Class<?> clazz = getDigester().getClassLoader().loadClass( realClassName ); |
| creationFactory = (ObjectCreationFactory<?>) clazz.newInstance(); |
| creationFactory.setDigester( getDigester() ); |
| } |
| return ( creationFactory ); |
| } |
| |
| } |