You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by pr...@apache.org on 2002/07/26 21:18:44 UTC

cvs commit: jakarta-avalon-excalibur/configuration/src/java/org/apache/excalibur/configuration/merged ConfigurationSplitter.java

proyal      2002/07/26 12:18:44

  Added:       configuration/src/java/org/apache/excalibur/configuration/merged
                        ConfigurationSplitter.java
  Log:
  Class to "split" a configuration. Given a Configuration
  and a "base" configuration, generate the "layer" that when
  merged with the base yields the original Configuration
  
  Revision  Changes    Path
  1.1                  jakarta-avalon-excalibur/configuration/src/java/org/apache/excalibur/configuration/merged/ConfigurationSplitter.java
  
  Index: ConfigurationSplitter.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.excalibur.configuration.merged;
  
  import java.util.HashSet;
  
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  import org.apache.excalibur.configuration.ConfigurationUtil;
  
  /**
   * The ConfigurationSplitter will take two Configuration objects and calculate the
   * differences between them.
   *
   * The resulting Configuration will contain special attribute that can be used by the
   * ConfigurationMerger to reconstruct the original Configuration
   *
   * @see ConfigurationMerger
   * @author <a href="mailto:proyal@apache.org">Peter Royal</a>
   */
  public class ConfigurationSplitter
  {
      /**
       * Split a configuration, given a merged configuration and a base configuration.
       * Functionally equivalent to producing a <i>diff</i> between the merged and base.
       *
       * @param merged Configuration that is a combination of the <i>result</i> and
       *        the <i>base</i> param
       * @param base Configuration that when merged with the <i>result</i> will yield the
       *        <i>merged</i> param
       *
       * @return a Configuration that when merged with the <i>base</i> will yeild the
       *         <i>merged</i>
       *
       * @throws ConfigurationException if unable to split
       */
      public static Configuration split( final Configuration merged, final Configuration base )
          throws ConfigurationException
      {
          final DefaultConfiguration layer = doSplit( merged, base, false );
  
          layer.makeReadOnly();
  
          return layer;
      }
  
      private static DefaultConfiguration doSplit( final Configuration merged,
                                                   final Configuration base,
                                                   final boolean isMerged )
          throws ConfigurationException
      {
          final DefaultConfiguration layer =
              new DefaultConfiguration( base.getName(),
                                        "Merged [merged: " + merged.getLocation()
                                        + ", base: " + base.getLocation() + "]" );
  
          copyAttributes( layer, merged, base );
          copyValue( layer, merged, base );
          copyChildren( layer, merged, base );
  
          if( isMerged )
          {
              layer.setAttribute( Constants.MERGE_ATTR, "true" );
          }
  
          return layer;
      }
  
      private static DefaultConfiguration doSplit( final Configuration merged,
                                                   final Configuration base,
                                                   final String keyAttr )
          throws ConfigurationException
      {
          final DefaultConfiguration layer = doSplit( merged, base, true );
  
          if( null != keyAttr )
          {
              layer.setAttribute( Constants.KEY_ATTR, keyAttr );
          }
  
          return layer;
      }
  
      private static void copyChildren( final DefaultConfiguration layer,
                                        final Configuration merged,
                                        final Configuration base )
          throws ConfigurationException
      {
          final Configuration[] kids = merged.getChildren();
  
          for( int i = 0; i < kids.length; i++ )
          {
              final Configuration mergedChild = kids[i];
              final String name = mergedChild.getName();
              final Configuration[] mc = merged.getChildren( name );
              final Configuration[] bc = base.getChildren( name );
  
              Configuration mergedWith;
              String keyAttr = null;
  
              if( bc.length > mc.length )
              {
                  throw new UnsupportedOperationException( "Unable to mask children from base "
                                                           + "in layer" );
              }
              else if( bc.length == 0 )
              {
                  mergedWith = null;
              }
              else if( mc.length == 1 && bc.length == 1 )
              {
                  mergedWith = bc[0];
              }
              else //we know that mc.length > 1 here, so find the "key" attribute
              {
                  keyAttr = findUniqueAttributeName( mc );
  
                  final String keyValue = mergedChild.getAttribute( keyAttr );
                  final Configuration[] matches =
                      ConfigurationUtil.match( base, name, keyAttr, keyValue );
  
                  if( matches.length == 1 )
                  {
                      mergedWith = matches[0];
                  }
                  else
                  {
                      throw new ConfigurationException( "Multiple children in base with name '"
                                                        + name + "' and attr '" + keyAttr
                                                        + " = " + keyValue + "'" );
                  }
              }
  
              if( null == mergedWith )
              {
                  layer.addChild( kids[i] );
              }
              else if( !ConfigurationUtil.equals( kids[i], mergedWith ) )
              {
                  final DefaultConfiguration layerChild = doSplit( kids[i], mergedWith, keyAttr );
  
                  layerChild.makeReadOnly();
  
                  layer.addChild( layerChild );
              }
          }
      }
  
      private static String findUniqueAttributeName( final Configuration[] c )
          throws ConfigurationException
      {
          final HashSet testedAttributes = new HashSet();
          String uniqueAttr = null;
  
          for( int i = 0; i < c.length; i++ )
          {
              final String[] attrs = c[i].getAttributeNames();
  
              for( int j = 0; j < attrs.length; j++ )
              {
                  final String attr = attrs[j];
  
                  if( !testedAttributes.contains( attr )
                      && isUniqueAttribute( attr, c[i].getAttribute( attr ), i, c ) )
                  {
                      if( null == uniqueAttr )
                      {
                          uniqueAttr = attr;
                      }
                      else
                      {
                          throw new ConfigurationException( "Multiple unique attributes for child "
                                                            + "[name: " + c[0].getName()
                                                            + ", unique1: " + uniqueAttr
                                                            + ", unique2: " + attr + "]" );
                      }
                  }
                  else
                  {
                      testedAttributes.add( attr );
                  }
              }
          }
  
          if( null == uniqueAttr )
          {
              throw new ConfigurationException( "Unable to find unique attribute for "
                                                + "children of name: " + c[0].getName() );
          }
  
          return uniqueAttr;
      }
  
      private static boolean isUniqueAttribute( final String attr,
                                                final String value,
                                                final int currentConfig,
                                                final Configuration[] c )
      {
          for( int i = 0; i < c.length; i++ )
          {
              if( i != currentConfig )
              {
                  try
                  {
                      if( value.equals( c[i].getAttribute( attr ) ) )
                      {
                          return false;
                      }
                  }
                  catch( ConfigurationException e )
                  {
                      return false;
                  }
              }
          }
  
          return true;
      }
  
      private static void copyValue( final DefaultConfiguration layer,
                                     final Configuration merged,
                                     final Configuration base )
      {
          final String value = merged.getValue( null );
  
          if( null != value )
          {
              try
              {
                  final String baseValue = base.getValue();
  
                  if( !value.equals( baseValue ) )
                  {
                      layer.setValue( value );
                  }
              }
              catch( ConfigurationException e )
              {
                  layer.setValue( value );
              }
          }
      }
  
      private static void copyAttributes( final DefaultConfiguration layer,
                                          final Configuration merged,
                                          final Configuration base )
          throws ConfigurationException
      {
          final String[] mergedAttr = merged.getAttributeNames();
  
          for( int i = 0; i < mergedAttr.length; i++ )
          {
              final String value = merged.getAttribute( mergedAttr[i] );
  
              try
              {
                  final String baseValue = base.getAttribute( mergedAttr[i] );
  
                  if( !value.equals( baseValue ) )
                  {
                      layer.setAttribute( mergedAttr[i], value );
                  }
              }
              catch( ConfigurationException e )
              {
                  //not in base add to layer
                  layer.setAttribute( mergedAttr[i], value );
              }
          }
      }
  
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>