Package org.apache.commons.betwixt.io

Source Code of org.apache.commons.betwixt.io.BeanRuleSet$DigesterReadContext

/*
* 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.betwixt.io;

import org.apache.commons.betwixt.BindingConfiguration;
import org.apache.commons.betwixt.ElementDescriptor;
import org.apache.commons.betwixt.XMLIntrospector;
import org.apache.commons.betwixt.expression.Context;
import org.apache.commons.betwixt.io.read.BeanBindAction;
import org.apache.commons.betwixt.io.read.MappingAction;
import org.apache.commons.betwixt.io.read.ReadConfiguration;
import org.apache.commons.betwixt.io.read.ReadContext;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.Rule;
import org.apache.commons.digester.RuleSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;

/** <p>Sets <code>Betwixt</code> digestion rules for a bean class.</p>
  *
  * @author <a href="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
  * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
  * @since 0.5
  */
public class BeanRuleSet implements RuleSet {

    /** Logger */
    private static Log log = LogFactory.getLog(BeanRuleSet.class);

    /**
    * Set log to be used by <code>BeanRuleSet</code> instances
    * @param aLog the <code>Log</code> implementation for this class to log to
    */
    public static void setLog(Log aLog) {
        log = aLog;
    }

    /** The base path under which the rules will be attached */
    private String basePath;
    /** The element descriptor for the base  */
    private ElementDescriptor baseElementDescriptor;
    /** The (empty) base context from which all Contexts
    with beans are (directly or indirectly) obtained */
    private DigesterReadContext context;
    /** allows an attribute to be specified to overload the types of beans used */
    private String classNameAttribute = "className";

    /**
     * Base constructor.
     *
     * @param introspector the <code>XMLIntrospector</code> used to introspect
     * @param basePath specifies the (Digester-style) path under which the rules will be attached
     * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
     * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
     * @param matchIDs should ID/IDREFs be used to match beans?
     * @deprecated 0.5 use constructor which takes a ReadContext instead
     */
    public BeanRuleSet(
        XMLIntrospector introspector,
        String basePath,
        ElementDescriptor baseElementDescriptor,
        Class baseBeanClass,
        boolean matchIDs) {
        this.basePath = basePath;
        this.baseElementDescriptor = baseElementDescriptor;
        BindingConfiguration bindingConfiguration = new BindingConfiguration();
        bindingConfiguration.setMapIDs(matchIDs);
        context =
            new DigesterReadContext(
                log,
                bindingConfiguration,
                new ReadConfiguration());
        context.setRootClass(baseBeanClass);
        context.setXMLIntrospector(introspector);
    }

    /**
     * Base constructor.
     *
     * @param introspector the <code>XMLIntrospector</code> used to introspect
     * @param basePath specifies the (Digester-style) path under which the rules will be attached
     * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
     * @param context the root Context that bean carrying Contexts should be obtained from,
     * not null
     * @deprecated 0.6 use the constructor which takes a ReadContext instead
     */
    public BeanRuleSet(
        XMLIntrospector introspector,
        String basePath,
        ElementDescriptor baseElementDescriptor,
        Context context) {

        this.basePath = basePath;
        this.baseElementDescriptor = baseElementDescriptor;
        this.context =
            new DigesterReadContext(context, new ReadConfiguration());
        this.context.setRootClass(
            baseElementDescriptor.getSingularPropertyType());
        this.context.setXMLIntrospector(introspector);
    }

    /**
     * Base constructor.
     *
     * @param introspector the <code>XMLIntrospector</code> used to introspect
     * @param basePath specifies the (Digester-style) path under which the rules will be attached
     * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
     * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
     * @param context the root Context that bean carrying Contexts should be obtained from,
     * not null
     * @deprecated 0.5 use the constructor which takes a ReadContext instead
     */
    public BeanRuleSet(
                        XMLIntrospector introspector,
                        String basePath,
                        ElementDescriptor baseElementDescriptor,
                        Class baseBeanClass,
                        Context context) {
        this(
            introspector,
            basePath,
            baseElementDescriptor,
            baseBeanClass,
            new ReadContext( context, new ReadConfiguration() ));
    }

    /**
     * Base constructor.
     *
     * @param introspector the <code>XMLIntrospector</code> used to introspect
     * @param basePath specifies the (Digester-style) path under which the rules will be attached
     * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
     * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
     * @param baseContext the root Context that bean carrying Contexts should be obtained from,
     * not null
     */
    public BeanRuleSet(
        XMLIntrospector introspector,
        String basePath,
        ElementDescriptor baseElementDescriptor,
        Class baseBeanClass,
        ReadContext baseContext) {
        this.basePath = basePath;
        this.baseElementDescriptor = baseElementDescriptor;
        this.context = new DigesterReadContext(baseContext);
        this.context.setRootClass(baseBeanClass);
        this.context.setXMLIntrospector(introspector);
    }

    /**
     * The name of the attribute which can be specified in the XML to override the
     * type of a bean used at a certain point in the schema.
     *
     * <p>The default value is 'className'.</p>
     *
     * @return The name of the attribute used to overload the class name of a bean
     */
    public String getClassNameAttribute() {
        return context.getClassNameAttribute();
    }

    /**
     * Sets the name of the attribute which can be specified in
     * the XML to override the type of a bean used at a certain
     * point in the schema.
     *
     * <p>The default value is 'className'.</p>
     *
     * @param classNameAttribute The name of the attribute used to overload the class name of a bean
     * @deprecated 0.5 set the <code>ReadContext</code> property instead
     */
    public void setClassNameAttribute(String classNameAttribute) {
        context.setClassNameAttribute(classNameAttribute);
    }

    //-------------------------------- Ruleset implementation

    /**
     * <p>Gets the namespace associated with this ruleset.</p>
     *
     * <p><strong>Note</strong> namespaces are not currently supported.</p>
     *
     * @return null
     */
    public String getNamespaceURI() {
        return null;
    }

    /**
     * Add rules for bean to given <code>Digester</code>.
     *
     * @param digester the <code>Digester</code> to which the rules for the bean will be added
     */
    public void addRuleInstances(Digester digester) {
        if (log.isTraceEnabled()) {
            log.trace("Adding rules to:" + digester);
        }

        context.setDigester(digester);

        // if the classloader is not set, set to the digester classloader
        if (context.getClassLoader() == null) {
            context.setClassLoader(digester.getClassLoader());
        }

        // TODO: need to think about strategy for paths
        // may need to provide a default path and then allow the user to override
        digester.addRule("!" + basePath + "/*", new ActionMappingRule());
    }

    /**
     * Single rule that is used to map all elements.
     *
     * @author <a href='http://jakarta.apache.org/'>Jakarta Commons Team</a>
     */
    private final class ActionMappingRule extends Rule {

        /**
          * Processes the start of a new <code>Element</code>.
          * The actual processing is delegated to <code>MappingAction</code>'s.
          * @see Rule#begin(String, String, Attributes)
          */
        public void begin(String namespace, String name, Attributes attributes)
            throws Exception {

            if (log.isTraceEnabled()) {
                int attributesLength = attributes.getLength();
                if (attributesLength > 0) {
                    log.trace("Attributes:");
                }
                for (int i = 0, size = attributesLength; i < size; i++) {
                    log.trace("Local:" + attributes.getLocalName(i));
                    log.trace("URI:" + attributes.getURI(i));
                    log.trace("QName:" + attributes.getQName(i));
                }
            }

            context.pushElement(name);
           
            MappingAction nextAction =
                nextAction(namespace, name, attributes, context);

            context.pushMappingAction(nextAction);
        }

        /**
         * Gets the next action to be executed
         * @param namespace the element's namespace, not null
         * @param name the element name, not null
         * @param attributes the element's attributes, not null
         * @param context the <code>ReadContext</code> against which the xml is being mapped.
         * @return the initialized <code>MappingAction</code>, not null
         * @throws Exception
         */
        private MappingAction nextAction(
            String namespace,
            String name,
            Attributes attributes,
            ReadContext context)
            throws Exception {
               
            MappingAction result = null;
            MappingAction lastAction = context.currentMappingAction();
            if (lastAction == null)
            {
                result =  BeanBindAction.INSTANCE;  
            } else {
               
                result = lastAction.next(namespace, name, attributes, context);
            }
            return result.begin(namespace, name, attributes, context);
        }



        /**
        * Processes the body text for the current element.
        * This is delegated to the current <code>MappingAction</code>.
        * @see Rule#body(String, String, String)
        */
        public void body(String namespace, String name, String text)
            throws Exception {

            if (log.isTraceEnabled()) log.trace("[BRS] Body with text " + text);
            if (digester.getCount() > 0) {
                MappingAction action = context.currentMappingAction();
                action.body(text, context);
            } else {
                log.trace("[BRS] ZERO COUNT");
            }
        }

        /**
        * Process the end of this element.
        * This is delegated to the current <code>MappingAction</code>.
        */
        public void end(String namespace, String name) throws Exception {

            MappingAction action = context.popMappingAction();
            action.end(context);
        }

        /**
         * Tidy up.
         */
        public void finish() {
            //
            // Clear indexed beans so that we're ready to process next document
            //
            context.clearBeans();
        }

    }

    /**
     * Specialization of <code>ReadContext</code> when reading from <code>Digester</code>.
     * @author <a href='http://jakarta.apache.org/'>Jakarta Commons Team</a>
     * @version $Revision: 190509 $
     */
    private static class DigesterReadContext extends ReadContext {

        private Digester digester;

        /**
         * @param context
         * @param readConfiguration
         */
        public DigesterReadContext(
            Context context,
            ReadConfiguration readConfiguration) {
            super(context, readConfiguration);
            // TODO Auto-generated constructor stub
        }

        /**
         * @param bindingConfiguration
         * @param readConfiguration
         */
        public DigesterReadContext(
            BindingConfiguration bindingConfiguration,
            ReadConfiguration readConfiguration) {
            super(bindingConfiguration, readConfiguration);
        }

        /**
         * @param log
         * @param bindingConfiguration
         * @param readConfiguration
         */
        public DigesterReadContext(
            Log log,
            BindingConfiguration bindingConfiguration,
            ReadConfiguration readConfiguration) {
            super(log, bindingConfiguration, readConfiguration);
        }

        /**
         * @param log
         * @param bindingConfiguration
         * @param readConfiguration
         */
        public DigesterReadContext(ReadContext readContext) {
            super(readContext);
        }

        public Digester getDigester() {
            // TODO: replace with something better
            return digester;
        }

        public void setDigester(Digester digester) {
            // TODO: replace once moved to single Rule
            this.digester = digester;
        }

        /* (non-Javadoc)
         * @see org.apache.commons.betwixt.io.read.ReadContext#pushBean(java.lang.Object)
         */
        public void pushBean(Object bean) {
            super.pushBean(bean);
            digester.push(bean);
        }

        /* (non-Javadoc)
         * @see org.apache.commons.betwixt.io.read.ReadContext#putBean(java.lang.Object)
         */
        public Object popBean() {
            Object bean = super.popBean();
            Object top = digester.pop();
            return bean;
        }
    }

}
TOP

Related Classes of org.apache.commons.betwixt.io.BeanRuleSet$DigesterReadContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.