CVS: plexus-container-new/src/java/org/apache/plexus/configuration XmlPullConfigurationBuilder.java,NONE,1.1

[email protected] Fri, 2 May 2003 19:31:37 -0500
Newsgroups gmane.comp.java.plexus.devel
Message-ID <[email protected]>
Update of /cvsroot/plexus/plexus-container-new/src/java/org/apache/plexus/configuration
In directory eng.werken.com:/tmp/cvs-serv1367

Added Files:
	XmlPullConfigurationBuilder.java 
Log Message:
o Adding XmlPull-based configuration builder.


--- NEW FILE: XmlPullConfigurationBuilder.java ---
package org.apache.plexus.configuration;

import org.apache.avalon.framework.configuration.Configuration;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

import java.io.Reader;
import java.util.ArrayList;
import java.util.BitSet;

/**
 * @author Jason van Zyl
 * @version $Id: XmlPullConfigurationBuilder.java,v 1.1 2003/05/03 00:31:35 jvanzyl Exp $
 */
public class XmlPullConfigurationBuilder
{
    /**
     * Likely number of nested configuration items. If more is
     * encountered the lists will grow automatically.
     */
    private static final int EXPECTED_DEPTH = 5;
    private final ArrayList m_elements = new ArrayList( EXPECTED_DEPTH );
    private final ArrayList m_values = new ArrayList( EXPECTED_DEPTH );
    /**
     * Contains true at index n if space in the configuration with
     * depth n is to be preserved.
     */
    private final BitSet m_preserveSpace = new BitSet();
    private Configuration m_configuration;

    public Configuration parse( Reader reader )
        throws Exception
    {
        clear();

        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        XmlPullParser parser = factory.newPullParser();
        parser.setInput( reader );

        int eventType = parser.getEventType();

        while ( eventType != XmlPullParser.END_DOCUMENT )
        {
            if ( eventType == XmlPullParser.START_TAG )
            {
                String rawName = parser.getName();

                final DefaultConfiguration configuration =
                    createConfiguration( rawName, getLocationString() );
                // depth of new configuration (not decrementing here, configuration
                // is to be added)
                final int depth = m_elements.size();
                boolean preserveSpace = false; // top level element trims space by default

                if ( depth > 0 )
                {
                    final DefaultConfiguration parent =
                        (DefaultConfiguration) m_elements.get( depth - 1 );
                    parent.addChild( configuration );
                    // inherits parent's space preservation policy
                    preserveSpace = m_preserveSpace.get( depth - 1 );
                }

                m_elements.add( configuration );
                m_values.add( new StringBuffer() );

                final int attributesSize = parser.getAttributeCount();

                for ( int i = 0; i < attributesSize; i++ )
                {
                    final String name = parser.getAttributeName( i );
                    final String value = parser.getAttributeValue( i );

                    if ( !name.equals( "xml:space" ) )
                    {
                        configuration.setAttribute( name, value );
                    }
                    else
                    {
                        preserveSpace = value.equals( "preserve" );
                    }
                }

                if ( preserveSpace )
                {
                    m_preserveSpace.set( depth );
                }
                else
                {
                    m_preserveSpace.clear( depth );
                }
            }
            else if ( eventType == XmlPullParser.TEXT )
            {
                // it is possible to play micro-optimization here by doing
                // manual trimming and thus preserve some precious bits
                // of memory, but it's really not important enough to justify
                // resulting code complexity
                final int depth = m_values.size() - 1;
                final StringBuffer valueBuffer = (StringBuffer) m_values.get( depth );
                valueBuffer.append( parser.getText() );
            }
            else if ( eventType == XmlPullParser.END_TAG )
            {

                final int depth = m_elements.size() - 1;
                final DefaultConfiguration finishedConfiguration =
                    (DefaultConfiguration) m_elements.remove( depth );
                final String accumulatedValue = ( m_values.remove( depth ) ).toString();

                if ( finishedConfiguration.getChildren().length == 0 )
                {
                    // leaf node
                    String finishedValue;
                    if ( m_preserveSpace.get( depth ) )
                    {
                        finishedValue = accumulatedValue;
                    }
                    else if ( 0 == accumulatedValue.length() )
                    {
                        finishedValue = null;
                    }
                    else
                    {
                        finishedValue = accumulatedValue.trim();
                    }
                    finishedConfiguration.setValue( finishedValue );
                }
                else
                {
                    final String trimmedValue = accumulatedValue.trim();
                    if ( trimmedValue.length() > 0 )
                    {
                        throw new Exception( "Not allowed to define mixed content in the "
                                                + "element " + finishedConfiguration.getName() + " at "
                                                + finishedConfiguration.getLocation() );
                    }
                }

                if ( 0 == depth )
                {
                    m_configuration = finishedConfiguration;
                }
            }

            eventType = parser.next();
        }

        return m_configuration;
    }

    /**
     * Clears all data from this configuration handler.
     */
    public void clear()
    {
        m_elements.clear();
        m_values.clear();
    }

    /**
     * Create a new <code>DefaultConfiguration</code> with the specified
     * local name and location.
     *
     * @param localName a <code>String</code> value
     * @param location a <code>String</code> value
     * @return a <code>DefaultConfiguration</code> value
     */
    protected DefaultConfiguration createConfiguration( final String localName,
                                                        final String location )
    {
        return new DefaultConfiguration( localName, location );
    }

    /**
     * Returns a string showing the current system ID, line number and column number.
     *
     * @return a <code>String</code> value
     */
    protected String getLocationString()
    {
        return "Unknown";
    }
}