You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by le...@apache.org on 2004/02/11 15:32:00 UTC
cvs commit: avalon/framework/impl/src/test/org/apache/avalon/framework/configuration/test DefaultConfigurationTestCase.java
leosutic 2004/02/11 06:32:00
Modified: framework/impl/src/java/org/apache/avalon/framework/configuration
DefaultConfiguration.java
framework/impl/src/test/org/apache/avalon/framework/configuration/test
DefaultConfigurationTestCase.java
Added: framework/impl/src/java/org/apache/avalon/framework/configuration
MutableConfiguration.java
DefaultImmutableConfiguration.java
Log:
Added MutableConfiguration interface and supporting code.
Revision Changes Path
1.42 +118 -2 avalon/framework/impl/src/java/org/apache/avalon/framework/configuration/DefaultConfiguration.java
Index: DefaultConfiguration.java
===================================================================
RCS file: /home/cvs/avalon/framework/impl/src/java/org/apache/avalon/framework/configuration/DefaultConfiguration.java,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- DefaultConfiguration.java 30 Jan 2004 10:43:09 -0000 1.41
+++ DefaultConfiguration.java 11 Feb 2004 14:31:59 -0000 1.42
@@ -27,7 +27,7 @@
*/
public class DefaultConfiguration
extends AbstractConfiguration
- implements Serializable
+ implements MutableConfiguration, Serializable
{
/**
* An empty (length zero) array of configuration objects.
@@ -607,6 +607,122 @@
throw new IllegalStateException
( "Configuration is read only and can not be modified" );
}
+ }
+
+ /**
+ * Returns true iff this DefaultConfiguration has been made read-only.
+ */
+ protected final boolean isReadOnly()
+ {
+ return m_readOnly;
+ }
+
+ /**
+ * Convenience function to convert a child to a mutable configuration.
+ * If the child is-a MutableConfiguration, and it isn't a read-only DefaultConfiguration
+ * (which isn't really mutable), the child is cast to MutableConfiguration and returned.
+ * If not, the child is replaced in the m_children array with a new writable DefaultConfiguration
+ * that is a shallow copy of the child, and the new child is returned.
+ */
+ private MutableConfiguration toMutable( Configuration child ) throws ConfigurationException
+ {
+ if (child instanceof MutableConfiguration &&
+ !( child instanceof DefaultConfiguration && ((DefaultConfiguration) child).isReadOnly() ))
+ {
+ // Child is already mutable - return it.
+ return (MutableConfiguration) child;
+ }
+
+ // Child isn't mutable. (This is a mutating operation, so let's check
+ // if we're writable.)
+ checkWriteable();
+
+ DefaultConfiguration config = new DefaultConfiguration( child );
+
+ // Replace the old child.
+ for( int i = 0; i < m_children.size(); i++)
+ {
+ if( m_children.get(i) == child )
+ {
+ m_children.set( i, config );
+ break;
+ }
+ }
+
+ return config;
+ }
+
+ public MutableConfiguration getMutableChild( final String name ) throws ConfigurationException
+ {
+ return getMutableChild( name, true );
+ }
+
+ public MutableConfiguration getMutableChild( final String name, boolean autoCreate ) throws ConfigurationException
+ {
+ Configuration child = getChild( name, false );
+ if( child == null )
+ {
+ // No child. Create?
+
+ if( autoCreate )
+ {
+ DefaultConfiguration config = new DefaultConfiguration( name, "-" );
+ addChild( config );
+ return config;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ // Child exists
+ return toMutable( child );
+ }
+
+ public MutableConfiguration[] getMutableChildren() throws ConfigurationException
+ {
+ if( null == m_children )
+ {
+ return new MutableConfiguration[ 0 ];
+ }
+ else
+ {
+ final ArrayList children = new ArrayList();
+ final int size = m_children.size();
+
+ for( int i = 0; i < size; i++ )
+ {
+ final Configuration configuration = (Configuration)m_children.get( i );
+ children.add( toMutable( configuration ) );
+ }
+
+ return (MutableConfiguration[])children.toArray( new MutableConfiguration[ 0 ] );
+ }
+ }
+
+ public MutableConfiguration[] getMutableChildren( final String name ) throws ConfigurationException
+ {
+ if( null == m_children )
+ {
+ return new MutableConfiguration[ 0 ];
+ }
+ else
+ {
+ final ArrayList children = new ArrayList();
+ final int size = m_children.size();
+
+ for( int i = 0; i < size; i++ )
+ {
+ final Configuration configuration = (Configuration)m_children.get( i );
+ if( name.equals( configuration.getName() ) )
+ {
+ children.add( toMutable( configuration ) );
+ }
+ }
+
+ return (MutableConfiguration[])children.toArray( new MutableConfiguration[ 0 ] );
+ }
}
/**
1.1 avalon/framework/impl/src/java/org/apache/avalon/framework/configuration/MutableConfiguration.java
Index: MutableConfiguration.java
===================================================================
/*
* Copyright 1997-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.avalon.framework.configuration;
/**
* A read/write extension of the Configuration interface.
*
* @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
* @version CVS $Revision: 1.1 $ $Date: 2004/02/11 14:31:59 $
* @since 4.1.6
*/
public interface MutableConfiguration extends Configuration
{
/**
* Set the value of this <code>Configuration</code> object to the specified string.
*
* @param value a <code>String</code> value
*/
public void setValue( final String value );
/**
* Set the value of this <code>Configuration</code> object to the specified int.
*
* @param value a <code>int</code> value
*/
public void setValue( final int value );
/**
* Set the value of this <code>Configuration</code> object to the specified long.
*
* @param value a <code>long</code> value
*/
public void setValue( final long value );
/**
* Set the value of this <code>Configuration</code> object to the specified boolean.
*
* @param value a <code>boolean</code> value
*/
public void setValue( final boolean value );
/**
* Set the value of this <code>Configuration</code> object to the specified float.
*
* @param value a <code>float</code> value
*/
public void setValue( final float value );
/**
* Set the value of the specified attribute to the specified string.
*
* @param name name of the attribute to set
* @param value a <code>String</code> value. If null, the attribute is removed.
*/
public void setAttribute( final String name, final String value );
/**
* Set the value of the specified attribute to the specified int.
*
* @param name name of the attribute to set
* @param value an <code>int</code> value
*/
public void setAttribute( final String name, final int value );
/**
* Set the value of the specified attribute to the specified long.
*
* @param name name of the attribute to set
* @param value an <code>long</code> value
*/
public void setAttribute( final String name, final long value );
/**
* Set the value of the specified attribute to the specified boolean.
*
* @param name name of the attribute to set
* @param value an <code>boolean</code> value
*/
public void setAttribute( final String name, final boolean value );
/**
* Set the value of the specified attribute to the specified float.
*
* @param name name of the attribute to set
* @param value an <code>float</code> value
*/
public void setAttribute( final String name, final float value );
/**
* Add a child <code>Configuration</code> to this configuration element.
* @param configuration a <code>Configuration</code> value
*/
public void addChild( final Configuration configuration );
/**
* Add all the attributes, children and value
* from specified configuration element to current
* configuration element.
*
* @param other the {@link Configuration} element
*/
public void addAll( final Configuration other );
/**
* Add all attributes from specified configuration
* element to current configuration element.
*
* @param other the {@link Configuration} element
*/
public void addAllAttributes( final Configuration other );
/**
* Add all child <code>Configuration</code> objects from specified
* configuration element to current configuration element.
*
* @param other the other {@link Configuration} value
*/
public void addAllChildren( final Configuration other );
/**
* Remove a child <code>Configuration</code> to this configuration element.
* @param configuration a <code>Configuration</code> value
*/
public void removeChild( final Configuration configuration );
/**
* Equivalent to <code>getMutableChild( name, true )</code>
*/
public MutableConfiguration getMutableChild( final String name ) throws ConfigurationException;
/**
* Gets a child node of this configuration. If a mutable child with the
* given name exists, it is returned. If an immutable child with the
* given name exists, it is converted into a mutable child and returned.
* In this case, the immutable child will be replaced with the mutable
* child in this configuration (that is, it will be as if the child
* node always had been mutable).
* If no child with the given name exists, and <code>autoCreate</code>
* is <code>true</code>, a new mutable child is created and added to
* this configuration before being returned.
*
* @returns the child MutableConfiguration, or <code>null</code> if <code>autoCreate</code>
* was false and no child by the given name existed.
* @param name the name of the child.
* @param autoCreate set to true to create the child node if it doesn't exist.
* @throws ConfigurationException if an error occurrs.
*/
public MutableConfiguration getMutableChild( final String name, boolean autoCreate ) throws ConfigurationException;
/**
* Returns an array of mutable children. Immutable children
* are converted just as for <code>getMutableChild</code>.
* @throws ConfigurationException if an error occurrs.
*/
public MutableConfiguration[] getMutableChildren() throws ConfigurationException;
/**
* Returns an array of mutable children with the given name. Immutable children
* are converted just as for <code>getMutableChild</code>.
* @throws ConfigurationException if an error occurrs.
*/
public MutableConfiguration[] getMutableChildren( final String name ) throws ConfigurationException;
}
1.1 avalon/framework/impl/src/java/org/apache/avalon/framework/configuration/DefaultImmutableConfiguration.java
Index: DefaultImmutableConfiguration.java
===================================================================
/*
* Copyright 1997-2004 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.avalon.framework.configuration;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
/**
* An immutable implementation of the <code>Configuration</code> interface.
*
* @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
* @version CVS $Revision: 1.1 $ $Date: 2004/02/11 14:31:59 $
*/
public class DefaultImmutableConfiguration
extends AbstractConfiguration
implements Serializable
{
/**
* An empty (length zero) array of configuration objects.
*/
protected static final Configuration[] EMPTY_ARRAY = new Configuration[ 0 ];
private final String m_name;
private final String m_location;
private final String m_namespace;
private final String m_prefix;
private final HashMap m_attributes;
private final ArrayList m_children;
private final String m_value;
/**
* Deep copy constructor.
*
* @param config the <code>Configuration</code> to do a deep copy of.
* @throws ConfigurationException if an error occurs when copying
*/
public DefaultImmutableConfiguration( Configuration config ) throws ConfigurationException
{
m_name = config.getName();
m_location = config.getLocation();
m_namespace = config.getNamespace();
m_prefix = (config instanceof AbstractConfiguration) ? ((AbstractConfiguration)config).getPrefix() : "";
m_value = config.getValue( null );
final String[] attributes = config.getAttributeNames();
if( attributes.length > 0 )
{
m_attributes = new HashMap ();
for( int i = 0; i < attributes.length; i++ )
{
final String name = attributes[ i ];
final String value = config.getAttribute( name, null );
m_attributes.put( name, value );
}
}
else
{
m_attributes = null;
}
Configuration[] children = config.getChildren();
if( children.length > 0 )
{
m_children = new ArrayList ();
for( int i = 0; i < children.length; i++ )
{
// Deep copy
m_children.add( new DefaultImmutableConfiguration( children[i] ) );
}
}
else
{
m_children = null;
}
}
/**
* Returns the name of this configuration element.
* @return a <code>String</code> value
*/
public String getName()
{
return m_name;
}
/**
* Returns the namespace of this configuration element
* @return a <code>String</code> value
* @throws ConfigurationException if an error occurs
* @since 4.1
*/
public String getNamespace() throws ConfigurationException
{
if( null != m_namespace )
{
return m_namespace;
}
else
{
throw new ConfigurationException
( "No namespace (not even default \"\") is associated with the "
+ "configuration element \"" + getName()
+ "\" at " + getLocation() );
}
}
/**
* Returns the prefix of the namespace
* @return a <code>String</code> value
* @throws ConfigurationException if prefix is not present (<code>null</code>).
* @since 4.1
*/
protected String getPrefix() throws ConfigurationException
{
if( null != m_prefix )
{
return m_prefix;
}
else
{
throw new ConfigurationException
( "No prefix (not even default \"\") is associated with the "
+ "configuration element \"" + getName()
+ "\" at " + getLocation() );
}
}
/**
* Returns a description of location of element.
* @return a <code>String</code> value
*/
public String getLocation()
{
return m_location;
}
/**
* Returns the value of the configuration element as a <code>String</code>.
*
* @param defaultValue the default value to return if value malformed or empty
* @return a <code>String</code> value
*/
public String getValue( final String defaultValue )
{
if( null != m_value )
{
return m_value;
}
else
{
return defaultValue;
}
}
/**
* Returns the value of the configuration element as a <code>String</code>.
*
* @return a <code>String</code> value
* @throws ConfigurationException If the value is not present.
*/
public String getValue() throws ConfigurationException
{
if( null != m_value )
{
return m_value;
}
else
{
throw new ConfigurationException( "No value is associated with the "
+ "configuration element \"" + getName()
+ "\" at " + getLocation() );
}
}
/**
* Return an array of all attribute names.
* @return a <code>String[]</code> value
*/
public String[] getAttributeNames()
{
if( null == m_attributes )
{
return new String[ 0 ];
}
else
{
return (String[])m_attributes.keySet().toArray( new String[ 0 ] );
}
}
/**
* Return an array of <code>Configuration</code>
* elements containing all node children.
*
* @return The child nodes with name
*/
public Configuration[] getChildren()
{
if( null == m_children )
{
return new Configuration[ 0 ];
}
else
{
return (Configuration[])m_children.toArray( new Configuration[ 0 ] );
}
}
/**
* Returns the value of the attribute specified by its name as a
* <code>String</code>.
*
* @param name a <code>String</code> value
* @return a <code>String</code> value
* @throws ConfigurationException If the attribute is not present.
*/
public String getAttribute( final String name )
throws ConfigurationException
{
final String value =
( null != m_attributes ) ? (String)m_attributes.get( name ) : null;
if( null != value )
{
return value;
}
else
{
throw new ConfigurationException(
"No attribute named \"" + name + "\" is "
+ "associated with the configuration element \""
+ getName() + "\" at " + getLocation() );
}
}
/**
* Return the first <code>Configuration</code> object child of this
* associated with the given name.
* @param name a <code>String</code> value
* @param createNew a <code>boolean</code> value
* @return a <code>Configuration</code> value
*/
public Configuration getChild( final String name, final boolean createNew )
{
if( null != m_children )
{
final int size = m_children.size();
for( int i = 0; i < size; i++ )
{
final Configuration configuration = (Configuration)m_children.get( i );
if( name.equals( configuration.getName() ) )
{
return configuration;
}
}
}
if( createNew )
{
return new DefaultConfiguration( name, "<generated>" + getLocation(), m_namespace, m_prefix );
}
else
{
return null;
}
}
/**
* Return an array of <code>Configuration</code> objects
* children of this associated with the given name.
* <br>
* The returned array may be empty but is never <code>null</code>.
*
* @param name The name of the required children <code>Configuration</code>.
* @return a <code>Configuration[]</code> value
*/
public Configuration[] getChildren( final String name )
{
if( null == m_children )
{
return new Configuration[ 0 ];
}
else
{
final ArrayList children = new ArrayList();
final int size = m_children.size();
for( int i = 0; i < size; i++ )
{
final Configuration configuration = (Configuration)m_children.get( i );
if( name.equals( configuration.getName() ) )
{
children.add( configuration );
}
}
return (Configuration[])children.toArray( new Configuration[ 0 ] );
}
}
/**
* Return count of children.
* @return an <code>int</code> value
*/
public int getChildCount()
{
if( null == m_children )
{
return 0;
}
return m_children.size();
}
/**
* Compare if this configuration is equal to another.
*
* @param other The other configuration
* @return <code>true</code> if they are the same.
*/
public boolean equals( Object other )
{
if( other == null ) return false;
if( !( other instanceof Configuration ) ) return false;
return ConfigurationUtil.equals( this, (Configuration) other );
}
/**
* Obtaine the hashcode for this configuration.
*
* @return the hashcode.
*/
public int hashCode()
{
int hash = m_prefix.hashCode();
if( m_name != null ) hash ^= m_name.hashCode();
hash >>>= 7;
if( m_location != null ) hash ^= m_location.hashCode();
hash >>>= 7;
if( m_namespace != null ) hash ^= m_namespace.hashCode();
hash >>>= 7;
if( m_attributes != null ) hash ^= m_attributes.hashCode();
hash >>>= 7;
if( m_children != null ) hash ^= m_children.hashCode();
hash >>>= 7;
if( m_value != null ) hash ^= m_value.hashCode();
hash >>>= 7;
return hash;
}
}
1.14 +50 -0 avalon/framework/impl/src/test/org/apache/avalon/framework/configuration/test/DefaultConfigurationTestCase.java
Index: DefaultConfigurationTestCase.java
===================================================================
RCS file: /home/cvs/avalon/framework/impl/src/test/org/apache/avalon/framework/configuration/test/DefaultConfigurationTestCase.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- DefaultConfigurationTestCase.java 30 Jan 2004 10:43:09 -0000 1.13
+++ DefaultConfigurationTestCase.java 11 Feb 2004 14:32:00 -0000 1.14
@@ -21,6 +21,7 @@
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.ConfigurationUtil;
import org.apache.avalon.framework.configuration.DefaultConfiguration;
+import org.apache.avalon.framework.configuration.MutableConfiguration;
/**
* Test the basic public methods of DefaultConfiguration.
@@ -187,5 +188,54 @@
// OK, this is what we expect - the attribute wasn't found.
}
}
+
+ public void testMutable() throws Exception
+ {
+ MutableConfiguration root = new DefaultConfiguration( "root", "-" );
+ root.setAttribute( "root1", "root1" );
+ root.setAttribute( "root2", "root2" );
+ root.getMutableChild( "child1" ).setAttribute( "child1-attr1", "child1-attr1" );
+ root.getMutableChild( "child1" ).setAttribute( "child1-attr2", "child1-attr2" );
+ root.getMutableChild( "child2" ).setAttribute( "child2-attr1", "child2-attr1" );
+ root.getMutableChild( "child2" ).setAttribute( "child2-attr2", "child2-attr2" );
+
+ assertEquals( "root1", root.getAttribute( "root1" ) );
+ assertEquals( "root2", root.getAttribute( "root2" ) );
+ assertEquals( "child1-attr1", root.getChild( "child1" ).getAttribute( "child1-attr1" ) );
+ assertEquals( "child1-attr2", root.getChild( "child1" ).getAttribute( "child1-attr2" ) );
+ assertEquals( "child2-attr1", root.getChild( "child2" ).getAttribute( "child2-attr1" ) );
+ assertEquals( "child2-attr2", root.getChild( "child2" ).getAttribute( "child2-attr2" ) );
+
+ assertEquals( null, root.getMutableChild( "child3", false ) );
+
+ assertEquals( 2, root.getChildren().length );
+
+ assertEquals( 2, root.getMutableChildren().length );
+ assertEquals( 1, root.getMutableChildren( "child1" ).length );
+ assertEquals( 1, root.getMutableChildren( "child2" ).length );
+ assertTrue( root.getMutableChildren( "child1" )[0] == root.getChild( "child1" ) );
+
+ // Add an immutable child.
+ DefaultConfiguration immutableChild = new DefaultConfiguration( "immutable-child", "-" );
+ immutableChild.makeReadOnly();
+
+ try
+ {
+ immutableChild.setAttribute( "attr", "attr" );
+ fail( "Read-only DefaultConfiguration wasn't read-only!" );
+ }
+ catch (IllegalStateException ise)
+ {
+ // expected
+ }
+
+ root.addChild( immutableChild );
+
+ // OK, ask to have it back.
+ root.getMutableChild( "immutable-child" ).setAttribute( "attr", "attr" );
+
+ assertEquals( 1, root.getChildren( "immutable-child" ).length );
+ assertEquals( "attr", root.getChild( "immutable-child" ).getAttribute( "attr" ) );
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: cvs-unsubscribe@avalon.apache.org
For additional commands, e-mail: cvs-help@avalon.apache.org