bloritsch 02/05/06 12:23:04
Modified: src/java/org/apache/avalon/framework/configuration
DefaultConfigurationBuilder.java
SAXConfigurationHandler.java
src/test/org/apache/avalon/framework/configuration/test
DefaultConfigurationBuilderTestCase.java
Log:
Apply patch from Leo for config object building
Revision Changes Path
1.15 +8 -0
jakarta-avalon/src/java/org/apache/avalon/framework/configuration/DefaultConfigurationBuilder.java
Index: DefaultConfigurationBuilder.java
===================================================================
RCS file:
/home/cvs/jakarta-avalon/src/java/org/apache/avalon/framework/configuration/DefaultConfigurationBuilder.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- DefaultConfigurationBuilder.java 21 Mar 2002 14:51:13 -0000 1.14
+++ DefaultConfigurationBuilder.java 6 May 2002 19:23:04 -0000 1.15
@@ -43,6 +43,14 @@
* Configuration#getNamespace
getNamespace()}.equals("http://foo.com")</code>.
* </li>
* </ul>
+ * <p>
+ * Whitespace handling. Since mixed content is not allowed in the
+ * configurations, whitespace is completely discarded in non-leaf nodes.
+ * For the leaf nodes the default behavior is to trim the space
+ * surrounding the value. This can be changed by specifying
+ * <code>xml:space</code> attribute with value of <code>preserve</code>
+ * in that case the whitespace is left intact.
+ * </p>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Federico Barbieri</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
1.17 +75 -42
jakarta-avalon/src/java/org/apache/avalon/framework/configuration/SAXConfigurationHandler.java
Index: SAXConfigurationHandler.java
===================================================================
RCS file:
/home/cvs/jakarta-avalon/src/java/org/apache/avalon/framework/configuration/SAXConfigurationHandler.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- SAXConfigurationHandler.java 6 May 2002 10:46:57 -0000 1.16
+++ SAXConfigurationHandler.java 6 May 2002 19:23:04 -0000 1.17
@@ -14,21 +14,32 @@
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
+import java.util.BitSet;
/**
* A SAXConfigurationHandler helps build Configurations out of sax events.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Federico Barbieri</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
- * @author <a href="mailto:[EMAIL PROTECTED]">Leo Sutic</a>
*/
public class SAXConfigurationHandler
extends DefaultHandler
implements ErrorHandler
{
- private final ArrayList m_elements = new ArrayList();
- private Configuration m_configuration;
- private Locator m_locator;
+ /**
+ * Likely number of nested configuration items. If more is
+ * encountered the lists will grow automatically.
+ */
+ private final static 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;
+ private Locator m_locator;
/**
* Get the configuration object that was built.
@@ -46,6 +57,7 @@
public void clear()
{
m_elements.clear();
+ m_values.clear();
m_locator = null;
}
@@ -70,18 +82,13 @@
public void characters( final char[] ch, int start, int end )
throws SAXException
{
- String value = new String( ch, start, end );
-
- if( value.equals( "" ) )
- {
- return;
- }
-
- final DefaultConfiguration configuration =
- (DefaultConfiguration)m_elements.get( m_elements.size() - 1 );
-
- value = configuration.getValue( "" ) + value;
- configuration.setValue( value );
+ // 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( ch, start, end );
}
/**
@@ -97,37 +104,41 @@
final String rawName )
throws SAXException
{
- final int location = m_elements.size() - 1;
- final DefaultConfiguration object = (DefaultConfiguration)
m_elements.remove( location );
-
- // Check for validity
- if ( object.getValue( null ) != null && object.getChildCount() > 0 )
+ final int depth = m_elements.size() - 1;
+ final DefaultConfiguration finishedConfiguration =
+ (DefaultConfiguration) m_elements.remove( depth );
+ final String accumulatedValue =
+ ((StringBuffer) m_values.remove( depth )).toString();
+
+ if( finishedConfiguration.getChildren().length == 0 )
{
- // Could be invalid - the configuration has children and a value.
- // It is valid, however, to have a value consisting of just
whitespace.
- // So let's trim the value, and see if we can resolve the
conflict that way.
- if ( object.getValue("").trim().equals("") )
+ // leaf node
+ String finishedValue;
+ if( m_preserveSpace.get(depth) )
{
- // Resolved!
- object.setValue( null );
+ finishedValue = accumulatedValue;
}
- else
+ else
{
- throw new SAXException( "Not allowed to define mixed content
in the " +
- "element " + object.getName() + " at
" +
- object.getLocation() );
+ finishedValue = accumulatedValue.trim();
}
+ finishedConfiguration.setValue( finishedValue );
}
-
- if( 0 == location )
+ else
{
- m_configuration = object;
- final String value = m_configuration.getValue( null );
- if( null != value )
+ final String trimmedValue = accumulatedValue.trim();
+ if( trimmedValue.length() > 0 )
{
- ((DefaultConfiguration)m_configuration).setValue(
value.trim() );
+ throw new SAXException( "Not allowed to define mixed content
in the " +
+ "element " +
finishedConfiguration.getName() + " at " +
+ finishedConfiguration.getLocation()
);
}
}
+
+ if( 0 == depth )
+ {
+ m_configuration = finishedConfiguration;
+ }
}
/**
@@ -161,17 +172,22 @@
{
final DefaultConfiguration configuration =
createConfiguration( rawName, getLocationString() );
- final int size = m_elements.size() - 1;
+ // 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( size > -1 )
+ if( depth > 0 )
{
final DefaultConfiguration parent =
- (DefaultConfiguration)m_elements.get( size );
-
+ (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 = attributes.getLength();
@@ -179,7 +195,24 @@
{
final String name = attributes.getQName( i );
final String value = attributes.getValue( i );
- configuration.setAttribute( name, value );
+
+ 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 );
}
}
1.5 +62 -2
jakarta-avalon/src/test/org/apache/avalon/framework/configuration/test/DefaultConfigurationBuilderTestCase.java
Index: DefaultConfigurationBuilderTestCase.java
===================================================================
RCS file:
/home/cvs/jakarta-avalon/src/test/org/apache/avalon/framework/configuration/test/DefaultConfigurationBuilderTestCase.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- DefaultConfigurationBuilderTestCase.java 6 May 2002 10:46:57 -0000
1.4
+++ DefaultConfigurationBuilderTestCase.java 6 May 2002 19:23:04 -0000
1.5
@@ -7,14 +7,15 @@
*/
package org.apache.avalon.framework.configuration.test;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
-import java.io.IOException;
-import java.util.List;
+import java.io.InputStream;
import junit.framework.TestCase;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
+import org.xml.sax.SAXException;
/**
* Test that the <code>Configuration</code>s built by
@@ -336,5 +337,64 @@
simpleAssertionsNS( conf );
conf = m_nsBuilder.buildFromFile( m_nsFile );
nsAssertions( conf );
+ }
+
+ private final String spaceTrimmingCheckXML =
+ "<?xml version=\"1.0\" ?>"+
+ " <config>"+
+ " <trimmed-item>\n"+
+ " value \n"+
+ " </trimmed-item>\n"+
+ " <preserved-item xml:space='preserve'>\n"+
+ " a space a CR, then a trailing space </preserved-item>\n"+
+ " <first-level-item xml:space='preserve'>\n"+
+ " <second-level-preserved> whitespace around
</second-level-preserved>\n"+
+ " </first-level-item>\n"+
+ " <trimmed-again-item>\n"+
+ " value \n"+
+ " </trimmed-again-item>\n"+
+ "</config>";
+
+ /**
+ * Checks that whitespace is normally stripped but preserved if
+ * space preserving processing instructions are present.
+ */
+ public void testSpaceTrimming()
+ throws Exception
+ {
+ DefaultConfigurationBuilder builder = new
DefaultConfigurationBuilder();
+ InputStream in = new ByteArrayInputStream(
spaceTrimmingCheckXML.getBytes() );
+ Configuration conf = builder.build( in );
+ assertEquals( "Value is trimmed by default",
+ "value",
+ conf.getChild( "trimmed-item" ).getValue() );
+ assertEquals( "After trimming turned off value is preserved",
+ "\n a space\r a CR, then a trailing space ",
+ conf.getChild( "preserved-item" ).getValue() );
+ assertEquals( "Trimming two levels deep works too",
+ " whitespace around ",
+ conf.getChild( "first-level-item" )
+ .getChild( "second-level-preserved" ).getValue() );
+ assertEquals( "Trimming turned back on",
+ "value",
+ conf.getChild( "trimmed-again-item" ).getValue() );
+ }
+
+
+ private final String mixedContentXML =
+ "<?xml version=\"1.0\" ?>"+
+ "<a>a<a/></a>"
+ ;
+ public void testMixedContentDetection()
+ throws Exception
+ {
+ DefaultConfigurationBuilder builder = new
DefaultConfigurationBuilder();
+ InputStream in = new ByteArrayInputStream(
mixedContentXML.getBytes() );
+ try
+ {
+ builder.build( in );
+ fail ("Must fail on mixed content");
+ } catch ( SAXException e )
+ {}
}
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>