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