You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@etch.apache.org by sc...@apache.org on 2009/03/31 15:22:38 UTC

svn commit: r760436 - in /incubator/etch/branches/config/services/config: ./ src/main/java/org/apache/etch/services/config/ src/test/java/org/apache/etch/services/config/

Author: sccomer
Date: Tue Mar 31 13:22:31 2009
New Revision: 760436

URL: http://svn.apache.org/viewvc?rev=760436&view=rev
Log:
more unit tests and update functionality.

Added:
    incubator/etch/branches/config/services/config/configtestplan.txt   (with props)
    incubator/etch/branches/config/services/config/update0.yml
    incubator/etch/branches/config/services/config/update1.yml
    incubator/etch/branches/config/services/config/update10.yml
    incubator/etch/branches/config/services/config/update11.yml
    incubator/etch/branches/config/services/config/update12.yml
    incubator/etch/branches/config/services/config/update13.yml
    incubator/etch/branches/config/services/config/update14.yml
    incubator/etch/branches/config/services/config/update2.yml
    incubator/etch/branches/config/services/config/update3.yml
    incubator/etch/branches/config/services/config/update4.yml
    incubator/etch/branches/config/services/config/update5.yml
    incubator/etch/branches/config/services/config/update6.yml
    incubator/etch/branches/config/services/config/update7.yml
    incubator/etch/branches/config/services/config/update8.yml
    incubator/etch/branches/config/services/config/update9.yml
Modified:
    incubator/etch/branches/config/services/config/src/main/java/org/apache/etch/services/config/YamlConfig.java
    incubator/etch/branches/config/services/config/src/test/java/org/apache/etch/services/config/TestYamlConfig.java

Added: incubator/etch/branches/config/services/config/configtestplan.txt
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/configtestplan.txt?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/configtestplan.txt (added)
+++ incubator/etch/branches/config/services/config/configtestplan.txt Tue Mar 31 13:22:31 2009
@@ -0,0 +1,37 @@
+possible yaml updates:
+
+update key value in map: scalar -> scalar [update1]
+add scalar key to map [update2]
+remove scalar key from map [update3]
+
+update element in list: scalar -> scalar [update4]
+add scalar element to list [update5]
+remove scalar element from list [update6]
+
+add map key to map [update7]
+add list key to map [update8]
+remove map key from map [update9]
+remove list key from map [update10]
+
+add map element to list [update11]
+add list element to list [update12]
+remove map element from list [update13]
+remove list element from list [update14]
+
+update key value in map: scalar -> map [update?]
+update key value in map: scalar -> list [update?]
+update key value in map: map -> scalar [update?]
+update key value in map: map -> map [update?]
+update key value in map: map -> list [update?]
+update key value in map: list -> scalar [update?]
+update key value in map: list -> map [update?]
+update key value in map: list -> list [update?]
+
+update element in list: scalar -> map [update?]
+update element in list: scalar -> list [update?]
+update element in list: map -> scalar [update?]
+update element in list: map -> map [update?]
+update element in list: map -> list [update?]
+update element in list: list -> scalar [update?]
+update element in list: list -> map [update?]
+update element in list: list -> list [update?]

Propchange: incubator/etch/branches/config/services/config/configtestplan.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/branches/config/services/config/configtestplan.txt
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Modified: incubator/etch/branches/config/services/config/src/main/java/org/apache/etch/services/config/YamlConfig.java
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/src/main/java/org/apache/etch/services/config/YamlConfig.java?rev=760436&r1=760435&r2=760436&view=diff
==============================================================================
--- incubator/etch/branches/config/services/config/src/main/java/org/apache/etch/services/config/YamlConfig.java (original)
+++ incubator/etch/branches/config/services/config/src/main/java/org/apache/etch/services/config/YamlConfig.java Tue Mar 31 13:22:31 2009
@@ -581,7 +581,7 @@
 		}
 	}
 	
-	private final static int INTERVAL = 5*1000;
+	private int INTERVAL = 5*1000;
 	
 	private final static int FAIL_INTERVAL = 60*1000;
 
@@ -668,6 +668,15 @@
 		return c;
 	}
 	
+	/**
+	 * This is purely for testing.
+	 */
+	void setConfig( String name ) throws Exception
+	{
+		file = mkfile( name );
+		lastModified = Long.MIN_VALUE;
+	}
+	
 	private void updateConfig() throws ConfigurationException
 	{
 		if (file.lastModified() != lastModified)
@@ -702,15 +711,15 @@
 	private int importObject( List<Conf> c, Integer parent, Object nameOrIndex,
 		Object value )
 	{
-		if (value instanceof List)
+		if (valueIsList( value ))
 		{
 			return importList( c, parent, nameOrIndex, (List<?>) value );
 		}
-		else if (value instanceof Map)
+		else if (valueIsMap( value ))
 		{
 			return importMap( c, parent, nameOrIndex, (Map<?, ?>) value );
 		}
-		else if (isScalar( value ))
+		else if (valueIsScalar( value ))
 		{
 			int k = c.size();
 			c.add( new Conf( parent, nameOrIndex, value ) );
@@ -723,20 +732,27 @@
 		}
 	}
 	
-	private static boolean isScalar( Object value )
+	private static boolean valueIsScalar( Object value )
 	{
 		return value instanceof Boolean || value instanceof Number ||
 			value instanceof String || value instanceof Date;
 	}
 
+	private boolean valueIsList( Object value )
+	{
+		return value instanceof List;
+	}
+
+	private boolean valueIsMap( Object value )
+	{
+		return value instanceof Map;
+	}
+
 	private void updateObject( List<Conf> newConfigs, Set<Integer> newSubs,
 		List<Integer> changeSet, int iid, Integer parent, Object nameOrIndex,
 		Object value )
 	{
-		// TODO implement this.
-		if (true) return;
-		
-		Conf c = getConf0( iid );
+		Conf c = newConfigs.get( iid );
 		
 		Assertion.check( (parent == null && c.parent == null) ||
 			(parent != null && c.parent != null && parent.equals( c.parent )),
@@ -744,28 +760,80 @@
 		
 		Assertion.check( (nameOrIndex == null && c.nameOrIndex == null) ||
 			(nameOrIndex != null && c.nameOrIndex != null && nameOrIndex.equals( c.nameOrIndex )),
-			"names match" );
+			"nameOrIndex match" );
 		
-		if (value instanceof List)
+		if (valueIsList( value ))
 		{
-			// return updateList( changeSet, parent, name, (List<?>) value, c.value );
-			return;
-		}
-		else if (value instanceof Map)
-		{
-			// return updateMap( changeSet, parent, name, (Map<?, ?>) value );
+			if (c.isList())
+			{
+				updateList( newConfigs, newSubs, changeSet, iid, parent, nameOrIndex, (List<?>) value, c );
+				return;
+			}
+			if (c.isMap())
+			{
+				destroyMap( newConfigs, iid, c );
+				importList( newConfigs, newSubs, changeSet, iid, parent, nameOrIndex, (List<?>) value );
+				return;
+			}
+			if (c.isScalar())
+			{
+				importList( newConfigs, newSubs, changeSet, iid, parent, nameOrIndex, (List<?>) value );
+				return;
+			}
+			throw new IllegalArgumentException(
+				"don't know how to update to list from type " + c.value.getClass() );
 		}
-		else if (isScalar( value ))
+		
+		if (valueIsMap( value ))
 		{
-			if ((value == null && c.value == null) ||
-				(value != null && c.value != null && value.equals( c.value )))
+			if (c.isMap())
+			{
+				updateMap( newConfigs, newSubs, changeSet, iid, parent, nameOrIndex, (Map<?, ?>) value, c );
 				return;
+			}
+			if (c.isList())
+			{
+				destroyList( newConfigs, iid, c );
+				importMap( newConfigs, newSubs, changeSet, iid, parent, nameOrIndex, (Map<?, ?>) value );
+				return;
+			}
+			if (c.isScalar())
+			{
+				importMap( newConfigs, newSubs, changeSet, iid, parent, nameOrIndex, (Map<?, ?>) value );
+				return;
+			}
+			throw new IllegalArgumentException(
+				"don't know how to update to map from type " + c.value.getClass() );
 		}
-		else
+		
+		if (valueIsScalar( value ))
 		{
-			throw new IllegalArgumentException(
-				"don't know how to update type "+value.getClass() );
+			if (c.isMap())
+			{
+				destroyMap( newConfigs, iid, c );
+				newConfigs.set( iid, new Conf( parent, nameOrIndex, value ) );
+				return;
+			}
+			
+			if (c.isList())
+			{
+				destroyList( newConfigs, iid, c );
+				newConfigs.set( iid, new Conf( parent, nameOrIndex, value ) );
+				return;
+			}
+			
+			if (c.isScalar())
+			{
+				if (value.equals( c.value ))
+					return;
+				
+				newConfigs.set( iid, new Conf( parent, nameOrIndex, value ) );
+				return;
+			}
 		}
+		
+		throw new IllegalArgumentException( "don't know how to update to " +
+			value.getClass() + " from " + c.value.getClass() );
 	}
 
 	private int importList( List<Conf> c, Integer parent, Object nameOrIndex, List<?> value )
@@ -780,12 +848,59 @@
 		
 		return k;
 	}
+
+	private void importList( List<Conf> newConfigs, Set<Integer> newSubs,
+		List<Integer> changeSet, int iid, Integer parent, Object nameOrIndex,
+		List<?> value )
+	{
+		List<Integer> v = new ArrayList<Integer>( value.size() );
+		newConfigs.set( iid, new Conf( parent, nameOrIndex, v ) );
+		
+		int i = 0;
+		for (Object o: value )
+			v.add( importObject( newConfigs, iid, i++, o ) );
+	}
+
+	private void updateList( List<Conf> newConfigs, Set<Integer> newSubs,
+		List<Integer> changeSet, int iid, Integer parent, Object nameOrIndex,
+		List<?> value, Conf c )
+	{
+		int n = Math.max( value.size(), c.size() );
+		for (int i = 0; i < n; i++)
+		{
+			if (i < value.size() && i < c.size())
+			{
+				updateObject( newConfigs, newSubs, changeSet, c.list().get( i ), iid, i, value.get( i ) );
+			}
+			else if (i < c.size()) // ran out of new values
+			{
+				destroy( newConfigs, c.list().get( i ) );
+				c.list().set( i, null );
+			}
+			else // i < value.size() // extending c
+			{
+				c.list().add( importObject( newConfigs, iid, i, value.get( i ) ) );
+			}
+		}
+		
+		// trim c if it is too long.
+		
+		while (c.list().size() > value.size())
+			c.list().remove( value.size() );
+	}
+
+	private void destroyList( List<Conf> newConfigs, int iid, Conf c )
+	{
+		newConfigs.set( iid, null );
+		for (int i: c.list())
+			destroy( newConfigs, i );
+	}
 	
 	private int importMap( List<Conf> c, Integer parent, Object nameOrIndex, Map<?, ?> value )
 	{
 		Map<String, Integer> v = new HashMap<String, Integer>( value.size() * 4 / 3 + 1 );
 		int k = c.size();
-		c.add( new Conf( parent, nameOrIndex, v ) );
+		c.add( new Conf( parent, nameOrIndex, Collections.unmodifiableMap( v ) ) );
 		
 		for (Map.Entry<?, ?> me: value.entrySet() )
 		{
@@ -795,6 +910,84 @@
 		
 		return k;
 	}
+
+	private void importMap( List<Conf> newConfigs, Set<Integer> newSubs,
+		List<Integer> changeSet, int iid, Integer parent, Object nameOrIndex,
+		Map<?, ?> value )
+	{
+		Map<String, Integer> v = new HashMap<String, Integer>( value.size() * 4 / 3 + 1 );
+		newConfigs.set( iid, new Conf( parent, nameOrIndex, Collections.unmodifiableMap( v ) ) );
+		
+		for (Map.Entry<?, ?> me: value.entrySet() )
+		{
+			String n = (String) me.getKey();
+			v.put( n, importObject( newConfigs, iid, n, me.getValue() ) );
+		}
+	}
+
+	private void updateMap( List<Conf> newConfigs, Set<Integer> newSubs,
+		List<Integer> changeSet, int iid, Integer parent, Object nameOrIndex,
+		Map<?, ?> value, Conf c )
+	{
+		Map<String, Integer> newMap = new HashMap<String, Integer>( c.map() );
+		
+		// Look for names in the current map which are not in the new.
+		
+		for (Map.Entry<String, Integer> me: c.map().entrySet())
+		{
+			String name = me.getKey();
+			Integer siid = me.getValue();
+			if (!value.containsKey( name ))
+			{
+				// this name will have to be deleted.
+				newMap.remove( name );
+				destroy( newConfigs, siid );
+			}
+		}
+		
+		// Look for names in the new map which are not in the current.
+		
+		for (Map.Entry<?, ?> me: value.entrySet())
+		{
+			String name = (String) me.getKey();
+			Object v = me.getValue();
+			if (!newMap.containsKey( name ))
+			{
+				// import the object
+				int k = importObject( newConfigs, iid, name, v );
+				newMap.put( name, k );
+			}
+			else
+			{
+				// update the object
+				Integer siid = newMap.get( name );
+				updateObject( newConfigs, newSubs, changeSet, siid, iid, name, v );
+			}
+		}
+		
+		newConfigs.set( iid, new Conf( parent, nameOrIndex, Collections.unmodifiableMap( newMap ) ) );
+	}
+
+	private void destroy( List<Conf> newConfigs, int iid )
+	{
+		Conf c = newConfigs.get( iid );
+		if (c.isMap())
+			destroyMap( newConfigs, iid, c );
+		else if (c.isList())
+			destroyList( newConfigs, iid, c );
+		else if (c.isScalar())
+			newConfigs.set( iid, null );
+		else
+			throw new UnsupportedOperationException(
+				"don't know how to destroy "+c.value.getClass() );
+	}
+
+	private void destroyMap( List<Conf> newConfigs, int iid, Conf c )
+	{
+		newConfigs.set( iid, null );
+		for (int i: c.map().values())
+			destroy( newConfigs, i );
+	}
 	
 	private Conf getConf0( int iid )
 	{
@@ -906,6 +1099,11 @@
 			this.value = value;
 		}
 
+		public boolean isScalar()
+		{
+			return valueIsScalar( value );
+		}
+
 		public String getPath()
 		{
 			if (isRoot())
@@ -952,11 +1150,11 @@
 			return nameOrIndex.toString();
 		}
 
-		public Integer parent;
+		public final Integer parent;
 		
-		public Object nameOrIndex;
+		public final Object nameOrIndex;
 		
-		public Object value;
+		public final Object value;
 		
 		public boolean subcribed;
 		
@@ -977,12 +1175,12 @@
 		
 		public boolean isList()
 		{
-			return value instanceof List;
+			return valueIsList( value );
 		}
 
 		public boolean isMap()
 		{
-			return value instanceof Map;
+			return valueIsMap( value );
 		}
 		
 		@SuppressWarnings("unchecked")
@@ -1119,7 +1317,7 @@
 			if (isMap())
 				return getMap0( depth );
 			
-			throw new IllegalArgumentException( "cannot convert value to Map" );
+			throw new IllegalArgumentException( "cannot convert value to Map: "+value.getClass() );
 		}
 
 		private Map<?, ?> getMap0( Integer depth )
@@ -1144,4 +1342,9 @@
 			return m;
 		}
 	}
+
+	void setInterval( int newInterval )
+	{
+		INTERVAL = newInterval;
+	}
 }

Modified: incubator/etch/branches/config/services/config/src/test/java/org/apache/etch/services/config/TestYamlConfig.java
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/src/test/java/org/apache/etch/services/config/TestYamlConfig.java?rev=760436&r1=760435&r2=760436&view=diff
==============================================================================
--- incubator/etch/branches/config/services/config/src/test/java/org/apache/etch/services/config/TestYamlConfig.java (original)
+++ incubator/etch/branches/config/services/config/src/test/java/org/apache/etch/services/config/TestYamlConfig.java Tue Mar 31 13:22:31 2009
@@ -46,6 +46,8 @@
 	private static final String EMPTY = "services/config/empty";
 	
 	private static final String DIR = "services/config/dir";
+
+	private static final String UPDATE = "services/config/update";
 	
 	private final MyConfigurationClient client = new MyConfigurationClient();
 	
@@ -1174,6 +1176,264 @@
 		Assert.assertEquals( 2, client.changed.size() );
 	}
 	
+	/** @throws Exception */
+	@Test
+	public void update0() throws Exception
+	{
+		YamlConfig c = new YamlConfig( client, UPDATE+0 );
+		client.setServer( c );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 5, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+	
+	private List<?> list( Object ... objs )
+	{
+		List<Object> list = new ArrayList<Object>( objs.length );
+		for (Object obj: objs)
+			list.add( obj );
+		return list;
+	}
+	
+	private Map<?, ?> map( Object ... objs )
+	{
+		Map<String, Object> map = new HashMap<String, Object>(
+			(objs.length * 2 + 2) / 3 );
+		for (int i = 0; i < objs.length; i += 2)
+			map.put( (String) objs[i], objs[i + 1] );
+		return map;
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update1() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+1 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 5, c.size( root ) );
+		Assert.assertEquals( 3, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+	
+	private YamlConfig setupUpdate( String updateConfig ) throws Exception
+	{
+		YamlConfig c = new YamlConfig( client, UPDATE+0 );
+		client.setServer( c );
+		Object root = c.getRoot();
+		
+		c.setInterval( 50 );
+		c.subscribe( root );
+		c.setConfig( updateConfig );
+		Thread.sleep( 1000 );
+		c.unsubscribeAll();
+		
+		return c;
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update2() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+2 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 6, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( 3, c.getIntegerPath( root, "baz" ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update3() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+3 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 4, c.size( root ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update4() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+4 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 5, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 5 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update5() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+5 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 5, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4, 5 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update6() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+6 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 5, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update7() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+7 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 6, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( map( "x", 6, "y", 7, "z", 8 ), c.getMapPath( root, "map1", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update8() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+8 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 6, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( 3, 4, 5 ), c.getListPath( root, "array1", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update9() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+9 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 4, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update10() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+10 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 4, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update11() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+11 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 5, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), map( "d", 8, "e", 9, "f", 10 ), list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update12() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+12 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 5, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), list( 1, 2, 3 ), list( 4, 5, 6 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update13() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+13 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 5, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", list( 1, 2, 3 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+
+	/** @throws Exception */
+	@Test
+	public void update14() throws Exception
+	{
+		YamlConfig c = setupUpdate( UPDATE+14 );
+		Object root = c.getRoot();
+		
+		Assert.assertEquals( 5, c.size( root ) );
+		Assert.assertEquals( 2, c.getIntegerPath( root, "foo" ) );
+		Assert.assertEquals( 4, c.getIntegerPath( root, "bar" ) );
+		Assert.assertEquals( list( 2, 3, 4 ), c.getListPath( root, "array", null ) );
+		Assert.assertEquals( map( "a", 5, "b", 6, "c", 7 ), c.getMapPath( root, "map", null ) );
+		Assert.assertEquals( list( "fish", map( "a", 5, "b", 6, "c", 7 ), "bear" ), c.getListPath( root, "list", null ) );
+	}
+	
 	private static class MyConfigurationClient implements ConfigurationClient
 	{
 		public void configValuesChanged( Object[] updated )

Added: incubator/etch/branches/config/services/config/update0.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update0.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update0.yml (added)
+++ incubator/etch/branches/config/services/config/update0.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,10 @@
+# starting point for update tests
+foo: 2
+bar: 4
+array: [ 2, 3, 4 ]
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update1.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update1.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update1.yml (added)
+++ incubator/etch/branches/config/services/config/update1.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,10 @@
+# update key value in map: scalar -> scalar
+foo: 3
+bar: 4
+array: [2, 3, 4]
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update10.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update10.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update10.yml (added)
+++ incubator/etch/branches/config/services/config/update10.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,9 @@
+# remove list key from map
+foo: 2
+bar: 4
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update11.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update11.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update11.yml (added)
+++ incubator/etch/branches/config/services/config/update11.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,11 @@
+# add map element to list
+foo: 2
+bar: 4
+array: [ 2, 3, 4 ]
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - { d: 8, e: 9, f: 10 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update12.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update12.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update12.yml (added)
+++ incubator/etch/branches/config/services/config/update12.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,11 @@
+# add list element to list
+foo: 2
+bar: 4
+array: [ 2, 3, 4 ]
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - [ 4, 5, 6 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update13.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update13.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update13.yml (added)
+++ incubator/etch/branches/config/services/config/update13.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,9 @@
+# remove map element from list
+foo: 2
+bar: 4
+array: [ 2, 3, 4 ]
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update14.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update14.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update14.yml (added)
+++ incubator/etch/branches/config/services/config/update14.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,9 @@
+# remove list element from list
+foo: 2
+bar: 4
+array: [ 2, 3, 4 ]
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - bear

Added: incubator/etch/branches/config/services/config/update2.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update2.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update2.yml (added)
+++ incubator/etch/branches/config/services/config/update2.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,11 @@
+# add scalar key to map
+foo: 2
+bar: 4
+array: [2, 3, 4]
+map: { a: 5, b: 6, c: 7 }
+baz: 3
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update3.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update3.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update3.yml (added)
+++ incubator/etch/branches/config/services/config/update3.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,9 @@
+# remove scalar key from map
+bar: 4
+array: [2, 3, 4]
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update4.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update4.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update4.yml (added)
+++ incubator/etch/branches/config/services/config/update4.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,10 @@
+# update element in list: scalar -> scalar
+foo: 2
+bar: 4
+array: [2, 3, 5]
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update5.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update5.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update5.yml (added)
+++ incubator/etch/branches/config/services/config/update5.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,10 @@
+# add scalar element to list
+foo: 2
+bar: 4
+array: [2, 3, 4, 5]
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update6.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update6.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update6.yml (added)
+++ incubator/etch/branches/config/services/config/update6.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,10 @@
+# remove scalar element from list
+foo: 2
+bar: 4
+array: [2, 3]
+map: { a: 5, b: 6, c: 7 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update7.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update7.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update7.yml (added)
+++ incubator/etch/branches/config/services/config/update7.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,11 @@
+# add map key to map
+foo: 2
+bar: 4
+array: [2, 3, 4]
+map: { a: 5, b: 6, c: 7 }
+map1: { x: 6, y: 7, z: 8 }
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update8.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update8.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update8.yml (added)
+++ incubator/etch/branches/config/services/config/update8.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,11 @@
+# add list key to map
+foo: 2
+bar: 4
+array: [2, 3, 4]
+map: { a: 5, b: 6, c: 7 }
+array1: [3, 4, 5]
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear

Added: incubator/etch/branches/config/services/config/update9.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/update9.yml?rev=760436&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/update9.yml (added)
+++ incubator/etch/branches/config/services/config/update9.yml Tue Mar 31 13:22:31 2009
@@ -0,0 +1,9 @@
+# remove map key from map
+foo: 2
+bar: 4
+array: [2, 3, 4]
+list:
+  - fish
+  - { a: 5, b: 6, c: 7 }
+  - [ 1, 2, 3 ]
+  - bear