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/24 17:13:14 UTC

svn commit: r757878 - in /incubator/etch/branches/config: ./ services/config/example/ services/config/example/src/ services/config/example/src/main/ services/config/example/src/main/etch/ services/config/example/src/main/java/ services/config/example/s...

Author: sccomer
Date: Tue Mar 24 16:13:07 2009
New Revision: 757878

URL: http://svn.apache.org/viewvc?rev=757878&view=rev
Log:
an example listener configured using best practice.

fixed a bug or two in the config service.

Added:
    incubator/etch/branches/config/services/config/example/   (with props)
    incubator/etch/branches/config/services/config/example/local.yml
    incubator/etch/branches/config/services/config/example/remote.yml
    incubator/etch/branches/config/services/config/example/src/
    incubator/etch/branches/config/services/config/example/src/main/
    incubator/etch/branches/config/services/config/example/src/main/etch/
    incubator/etch/branches/config/services/config/example/src/main/etch/ConfigExample.etch   (with props)
    incubator/etch/branches/config/services/config/example/src/main/java/
    incubator/etch/branches/config/services/config/example/src/main/java/org/
    incubator/etch/branches/config/services/config/example/src/main/java/org/apache/
    incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/
    incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/
    incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/
    incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/
    incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleClient.java   (with props)
    incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleServer.java   (with props)
    incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleClient.java   (with props)
    incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleListener.java   (with props)
Modified:
    incubator/etch/branches/config/.classpath
    incubator/etch/branches/config/services/config/src/main/etch/Configuration.etch
    incubator/etch/branches/config/services/config/src/main/java/org/apache/etch/services/config/MainConfigurationClient.java
    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

Modified: incubator/etch/branches/config/.classpath
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/.classpath?rev=757878&r1=757877&r2=757878&view=diff
==============================================================================
--- incubator/etch/branches/config/.classpath (original)
+++ incubator/etch/branches/config/.classpath Tue Mar 24 16:13:07 2009
@@ -46,6 +46,8 @@
 	<classpathentry kind="src" path="services/config/src/main/java"/>
 	<classpathentry kind="src" path="services/config/src/test/java"/>
 	<classpathentry kind="src" path="services/config/target/generated-sources/main/etch/java"/>
+	<classpathentry kind="src" path="services/config/example/src/main/java"/>
+	<classpathentry kind="src" path="services/config/example/target/generated-sources/main/etch/java"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/ETCH_DEPENDENT_JARS"/>
 	<classpathentry kind="output" path="bin"/>

Propchange: incubator/etch/branches/config/services/config/example/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Mar 24 16:13:07 2009
@@ -0,0 +1 @@
+target

Added: incubator/etch/branches/config/services/config/example/local.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/example/local.yml?rev=757878&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/example/local.yml (added)
+++ incubator/etch/branches/config/services/config/example/local.yml Tue Mar 24 16:13:07 2009
@@ -0,0 +1 @@
+configUri: tcp://localhost:4001/services/config/example/remote?TcpTransport.reconnectDelay=4000

Added: incubator/etch/branches/config/services/config/example/remote.yml
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/example/remote.yml?rev=757878&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/example/remote.yml (added)
+++ incubator/etch/branches/config/services/config/example/remote.yml Tue Mar 24 16:13:07 2009
@@ -0,0 +1 @@
+listenUri: tcp://0.0.0.0:4002

Added: incubator/etch/branches/config/services/config/example/src/main/etch/ConfigExample.etch
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/example/src/main/etch/ConfigExample.etch?rev=757878&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/example/src/main/etch/ConfigExample.etch (added)
+++ incubator/etch/branches/config/services/config/example/src/main/etch/ConfigExample.etch Tue Mar 24 16:13:07 2009
@@ -0,0 +1,6 @@
+module org.apache.etch.services.config.example
+
+service ConfigExample
+{
+	int add( int x, int y )
+}

Propchange: incubator/etch/branches/config/services/config/example/src/main/etch/ConfigExample.etch
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/branches/config/services/config/example/src/main/etch/ConfigExample.etch
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleClient.java
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleClient.java?rev=757878&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleClient.java (added)
+++ incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleClient.java Tue Mar 24 16:13:07 2009
@@ -0,0 +1,49 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.etch.services.config.example;
+
+/**
+ * Your custom implementation of BaseConfigExampleClient. Add methods here to provide
+ * implementations of messages from the server.
+ */
+public class ImplConfigExampleClient extends BaseConfigExampleClient
+{
+	/**
+	 * Constructs the ImplConfigExampleClient.
+	 *
+	 * @param server a connection to the server session. Use this to send a
+	 * message to the server.
+	 */
+	public ImplConfigExampleClient( RemoteConfigExampleServer server )
+	{
+		this.server = server;
+	}
+	
+	/**
+	 * A connection to the server session. Use this to send a
+	 * message to the server.
+	 */
+	@SuppressWarnings( "unused" )
+	private final RemoteConfigExampleServer server;
+
+	// TODO insert methods here to provide implementations of ConfigExampleClient
+	// messages from the server.
+}
\ No newline at end of file

Propchange: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleClient.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleServer.java
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleServer.java?rev=757878&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleServer.java (added)
+++ incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleServer.java Tue Mar 24 16:13:07 2009
@@ -0,0 +1,52 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.etch.services.config.example;
+
+/**
+ * Your custom implementation of BaseConfigExampleServer. Add methods here to provide
+ * implementations of messages from the client.
+ */
+public class ImplConfigExampleServer extends BaseConfigExampleServer
+{
+	/**
+	 * Constructs the ImplConfigExampleServer.
+	 *
+	 * @param client a connection to the client session. Use this to send a
+	 * message to the client.
+	 */
+	public ImplConfigExampleServer( RemoteConfigExampleClient client )
+	{
+		this.client = client;
+	}
+	
+	/**
+	 * A connection to the client session. Use this to send a
+	 * message to the client.
+	 */
+	@SuppressWarnings( "unused" )
+	private final RemoteConfigExampleClient client;
+
+	@Override
+	public Integer add( Integer x, Integer y )
+	{
+		return x + y;
+	}
+}

Propchange: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/ImplConfigExampleServer.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleClient.java
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleClient.java?rev=757878&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleClient.java (added)
+++ incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleClient.java Tue Mar 24 16:13:07 2009
@@ -0,0 +1,58 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.etch.services.config.example;
+
+/**
+ * Main program for ConfigExampleClient. This program makes a connection to the
+ * listener created by MainConfigExampleListener.
+ */
+public class MainConfigExampleClient implements ConfigExampleHelper.ConfigExampleClientFactory
+{
+	/**
+	 * Main program for ConfigExampleClient.
+	 * 
+	 * @param args command line arguments.
+	 * @throws Exception
+	 */
+	public static void main( String[] args ) throws Exception
+	{
+		// TODO Change to correct URI
+		String uri = "tcp://localhost:4002";
+		
+		RemoteConfigExampleServer server = ConfigExampleHelper.newServer( uri, null,
+			new MainConfigExampleClient() );
+
+		// Connect to the service
+		server._startAndWaitUp( 4000 );
+
+		Integer z = server.add( 4, 5 );
+		System.out.println( "add 4, 5 => "+z );
+
+		// Disconnect from the service
+		server._stopAndWaitDown( 4000 );
+	}
+
+	public ConfigExampleClient newConfigExampleClient( RemoteConfigExampleServer server )
+		throws Exception
+	{
+		return new ImplConfigExampleClient( server );
+	}
+}

Propchange: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleClient.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleClient.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleListener.java
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleListener.java?rev=757878&view=auto
==============================================================================
--- incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleListener.java (added)
+++ incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleListener.java Tue Mar 24 16:13:07 2009
@@ -0,0 +1,207 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.etch.services.config.example;
+
+import org.apache.etch.bindings.java.support.ServerFactory;
+import org.apache.etch.services.config.BaseConfigurationClient;
+import org.apache.etch.services.config.ConfigurationClient;
+import org.apache.etch.services.config.ConfigurationHelper;
+import org.apache.etch.services.config.ConfigurationServer;
+import org.apache.etch.services.config.RemoteConfigurationServer;
+import org.apache.etch.services.config.YamlConfig;
+import org.apache.etch.services.config.ConfigurationHelper.ConfigurationClientFactory;
+import org.apache.etch.services.config.example.ConfigExampleHelper.ConfigExampleServerFactory;
+import org.apache.etch.util.URL;
+import org.apache.etch.util.core.io.Session;
+import org.apache.etch.util.core.io.Transport;
+
+/**
+ * Main program for ConfigExampleServer. This program makes a listener to accept
+ * connections from MainConfigExampleClient.
+ */
+public class MainConfigExampleListener implements ConfigExampleServerFactory
+{
+	private static final String LOCAL = "services/config/example/local";
+	private static final String CONFIG_URI = "configUri";
+	private static final String LISTEN_URI = "listenUri";
+
+	/**
+	 * Main program for ConfigExampleServer.
+	 * 
+	 * @param args command line arguments.
+	 * @throws Exception
+	 */
+	public static void main( String[] args ) throws Exception
+	{
+		// use our local configuration to find our remote configuration service
+		// and keep us updated if it changes.
+		
+		local = new YamlConfig( new MyLocalConfigurationClient(), LOCAL );
+		System.out.println( "loaded local configuration named '"+LOCAL+"'" );
+		configUriId = local.getConfigPath( local.getRoot(), CONFIG_URI );
+		System.out.println( "subscribing to local "+CONFIG_URI );
+		local.subscribe( configUriId );
+	}
+	
+	private static ConfigurationServer local;
+	
+	private static Object configUriId;
+	
+	private static class MyLocalConfigurationClient implements ConfigurationClient
+	{
+		public void configValuesChanged( Object[] updated )
+		{
+			for (Object id: updated)
+			{
+				if (id.equals( configUriId ))
+				{
+					try
+					{
+						configUriChanged();
+					}
+					catch ( Exception e )
+					{
+						e.printStackTrace();
+					}
+					continue;
+				}
+			}
+		}
+	}
+	
+	private static void configUriChanged() throws Exception
+	{
+		configUri = local.getString( configUriId );
+		System.out.println( "local "+CONFIG_URI+" changed: "+configUri );
+		
+		RemoteConfigurationServer s = server;
+		if (s != null)
+		{
+			System.out.println( "shutting down remote config service connection" );
+			server = null;
+			s._stop();
+			s = null;
+		}
+		
+		server = ConfigurationHelper.newServer( configUri, null,
+			new MyConfigurationClientFactory() );
+		System.out.println( "starting remote config service connection" );
+		server._start();
+	}
+	
+	private static String configUri;
+	
+	private static RemoteConfigurationServer server;
+	
+	private static class MyConfigurationClientFactory
+		implements ConfigurationClientFactory
+	{
+		public ConfigurationClient newConfigurationClient(
+			RemoteConfigurationServer server ) throws Exception
+		{
+			return new MyRemoteConfigurationClient( server );
+		}
+	}
+	
+	private static class MyRemoteConfigurationClient extends BaseConfigurationClient
+	{
+		public MyRemoteConfigurationClient( RemoteConfigurationServer server )
+		{
+			this.server = server;
+		}
+		
+		private final RemoteConfigurationServer server;
+
+		@Override
+		public void _sessionNotify( Object event ) throws Exception
+		{
+			if (event == Session.UP)
+			{
+				System.out.println( "remote config service connection is up" );
+				String name = new URL( configUri ).getUri();
+				System.out.println( "loading remote configuration named '"+name+"'" );
+				Object root = server.loadConfig( name );
+				System.out.println( "loaded remote configuration named '"+name+"'" );
+				listenUriId = server.getConfigPath( root, LISTEN_URI );
+				System.out.println( "subscribing to remote "+LISTEN_URI );
+				server.subscribe( listenUriId );
+			}
+		}
+		
+		private Object listenUriId;
+		
+		@Override
+		public void configValuesChanged( Object[] updated )
+		{
+			for (Object id: updated)
+			{
+				if (id.equals( listenUriId ))
+				{
+					try
+					{
+						listenUriChanged();
+					}
+					catch ( Exception e )
+					{
+						e.printStackTrace();
+					}
+					continue;
+				}
+			}
+		}
+
+		private void listenUriChanged() throws Exception
+		{
+			String listenUri = server.getString( listenUriId );
+			System.out.println( "remote "+LISTEN_URI+" changed: "+listenUri );
+			resetListener( listenUri );
+		}
+	}
+
+	private static void resetListener( String listenUri ) throws Exception
+	{
+		ServerFactory l = listener;
+		if (l != null)
+		{
+			System.out.println( "stopping listener "+l );
+			listener = null;
+			l.transportControl( Transport.STOP, null );
+			l = null;
+		}
+		
+		listener = ConfigExampleHelper.newListener( listenUri, null, factory );
+		
+		// Start the Listener
+		listener.transportControl( Transport.START_AND_WAIT_UP, 4000 );
+		System.out.println( "started listener "+listener );
+	}
+	
+	private static ServerFactory listener;
+	
+	private final static MainConfigExampleListener factory =
+		new MainConfigExampleListener();
+
+	public ConfigExampleServer newConfigExampleServer(
+		RemoteConfigExampleClient client ) throws Exception
+	{
+		return new ImplConfigExampleServer( client );
+	}
+}

Propchange: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/etch/branches/config/services/config/example/src/main/java/org/apache/etch/services/config/example/MainConfigExampleListener.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Modified: incubator/etch/branches/config/services/config/src/main/etch/Configuration.etch
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/src/main/etch/Configuration.etch?rev=757878&r1=757877&r2=757878&view=diff
==============================================================================
--- incubator/etch/branches/config/services/config/src/main/etch/Configuration.etch (original)
+++ incubator/etch/branches/config/services/config/src/main/etch/Configuration.etch Tue Mar 24 16:13:07 2009
@@ -421,5 +421,6 @@
 	 * @param updated the ids of nodes that have been updated.
 	 */
 	@Direction( Client )
+	@AsyncReceiver( Queued )
 	void configValuesChanged( object[] updated )
 }

Modified: incubator/etch/branches/config/services/config/src/main/java/org/apache/etch/services/config/MainConfigurationClient.java
URL: http://svn.apache.org/viewvc/incubator/etch/branches/config/services/config/src/main/java/org/apache/etch/services/config/MainConfigurationClient.java?rev=757878&r1=757877&r2=757878&view=diff
==============================================================================
--- incubator/etch/branches/config/services/config/src/main/java/org/apache/etch/services/config/MainConfigurationClient.java (original)
+++ incubator/etch/branches/config/services/config/src/main/java/org/apache/etch/services/config/MainConfigurationClient.java Tue Mar 24 16:13:07 2009
@@ -42,7 +42,7 @@
 		String configUri = local.getStringPath( local.getRoot(), "configUri" );
 		System.out.println( "configUri = "+configUri );
 		local.unloadConfig();
-		local = null;		
+		local = null;
 		
 		RemoteConfigurationServer server = ConfigurationHelper.newServer(
 			configUri, null, new MainConfigurationClient() );

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=757878&r1=757877&r2=757878&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 24 16:13:07 2009
@@ -38,6 +38,8 @@
 import org.apache.etch.util.AlarmListener;
 import org.apache.etch.util.AlarmManager;
 import org.apache.etch.util.Assertion;
+import org.apache.etch.util.Todo;
+import org.apache.etch.util.TodoManager;
 import org.ho.yaml.Yaml;
 import org.ho.yaml.exception.YamlException;
 
@@ -71,7 +73,6 @@
 		loadConfig( name );
 	}
 	
-	@SuppressWarnings("unused")
 	private final ConfigurationClient client;
 
 	////////////////////
@@ -420,11 +421,36 @@
 			if (subs.isEmpty())
 				AlarmManager.staticAdd( LISTENER, null, INTERVAL );
 			
-			subs.add( iid );
+			if (!subs.add( iid ))
+			{
+				Assertion.check( c.subcribed, "subcribed" );
+				return;
+			}
+			
+			Assertion.check( !c.subcribed, "!subcribed" );
 			c.subcribed = true;
 		}
+		
+		fireConfigValuesChanged( new Object[] { id } );
 	}
+	
+	private void fireConfigValuesChanged( final Object[] updated )
+	{
+		TodoManager.addTodo( new Todo()
+		{
+
+			public void doit( TodoManager mgr ) throws Exception
+			{
+				client.configValuesChanged( updated );
+			}
 
+			public void exception( TodoManager mgr, Exception e )
+			{
+				e.printStackTrace();
+			}
+		} );
+	}
+	
 	public void subscribePath( Object id, String path )
 	{
 		subscribe( getConfigPath( id, path ) );
@@ -440,7 +466,13 @@
 		
 		synchronized (subs)
 		{
-			subs.remove( iid );
+			if (!subs.remove( iid ))
+			{
+				Assertion.check( !c.subcribed, "!subcribed" );
+				return;
+			}
+			
+			Assertion.check( c.subcribed, "subcribed" );
 			c.subcribed = false;
 			
 			if (subs.isEmpty())
@@ -458,6 +490,8 @@
 		if (subs == null)
 			return;
 		
+		AlarmManager.staticRemove( LISTENER );
+		
 		synchronized (subs)
 		{
 			for (Integer iid: subs)
@@ -467,8 +501,6 @@
 					c.subcribed = false;
 			}
 			subs.clear();
-
-			AlarmManager.staticRemove( LISTENER );
 		}
 	}
 

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=757878&r1=757877&r2=757878&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 24 16:13:07 2009
@@ -1,11 +1,34 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.etch.services.config;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Set;
 
 import org.apache.etch.services.config.Configuration.ConfigurationException;
 import org.junit.Assert;
@@ -1029,7 +1052,9 @@
 	@Test
 	public void subscribePath1() throws Exception
 	{
-		ConfigurationServer c = new YamlConfig( null, REMOTE );
+		ConfigurationServer c = new YamlConfig( client, REMOTE );
+		client.setServer( c );
+		
 		Object r = c.getRoot();
 		Assert.assertNotNull( r );
 
@@ -1044,7 +1069,8 @@
 	@Test
 	public void subscribePath2() throws Exception
 	{
-		ConfigurationServer c = new YamlConfig( null, REMOTE );
+		ConfigurationServer c = new YamlConfig( client, REMOTE );
+		client.setServer( c );
 		Object r = c.getRoot();
 		Assert.assertNotNull( r );
 
@@ -1055,7 +1081,8 @@
 	@Test
 	public void unsubscribePath1() throws Exception
 	{
-		ConfigurationServer c = new YamlConfig( null, REMOTE );
+		ConfigurationServer c = new YamlConfig( client, REMOTE );
+		client.setServer( c );
 		Object r = c.getRoot();
 		Assert.assertNotNull( r );
 
@@ -1070,18 +1097,102 @@
 	@Test
 	public void unsubscribePath2() throws Exception
 	{
-		ConfigurationServer c = new YamlConfig( null, REMOTE );
+		ConfigurationServer c = new YamlConfig( client, REMOTE );
+		client.setServer( c );
 		Object r = c.getRoot();
 		Assert.assertNotNull( r );
 
 		c.unsubscribePath( r, "blah" );
 	}
 	
+	/** @throws Exception */
+	@Test
+	public void configValuesChanged1() throws Exception
+	{
+		ConfigurationServer c = new YamlConfig( client, REMOTE );
+		client.setServer( c );
+		Object r = c.getRoot();
+		Assert.assertNotNull( r );
+		
+		Assert.assertFalse( client.changed.contains( r ) );
+		Assert.assertEquals( 0, client.changed.size() );
+		
+		c.subscribe( r );
+		Thread.sleep( 1000 );
+		
+		Assert.assertTrue( client.changed.contains( r ) );
+		Assert.assertEquals( 1, client.changed.size() );
+	}
+	
+	/** @throws Exception */
+	@Test
+	public void configValuesChanged2() throws Exception
+	{
+		ConfigurationServer c = new YamlConfig( client, REMOTE );
+		client.setServer( c );
+		Object r = c.getRoot();
+		Assert.assertNotNull( r );
+		
+		Object x = c.getConfigPath( r, "users" );
+		Assert.assertNotNull( x );
+		
+		Assert.assertFalse( client.changed.contains( x ) );
+		Assert.assertEquals( 0, client.changed.size() );
+		
+		c.subscribe( x );
+		Thread.sleep( 1000 );
+		
+		Assert.assertTrue( client.changed.contains( x ) );
+		Assert.assertEquals( 1, client.changed.size() );
+	}
+	
+	/** @throws Exception */
+	@Test
+	public void configValuesChanged3() throws Exception
+	{
+		ConfigurationServer c = new YamlConfig( client, REMOTE );
+		client.setServer( c );
+		Object r = c.getRoot();
+		Assert.assertNotNull( r );
+		
+		Object x = c.getConfigPath( r, "users" );
+		Assert.assertNotNull( x );
+		
+		Object y = c.getConfigPath( r, "primes" );
+		Assert.assertNotNull( y );
+
+		Assert.assertFalse( client.changed.contains( x ) );
+		Assert.assertFalse( client.changed.contains( y ) );
+		Assert.assertEquals( 0, client.changed.size() );
+
+		c.subscribe( x );
+		c.subscribe( y );
+		Thread.sleep( 1000 );
+
+		Assert.assertTrue( client.changed.contains( x ) );
+		Assert.assertTrue( client.changed.contains( y ) );
+		Assert.assertEquals( 2, client.changed.size() );
+	}
+	
 	private static class MyConfigurationClient implements ConfigurationClient
 	{
 		public void configValuesChanged( Object[] updated )
 		{
-			throw new UnsupportedOperationException( "configValuesChanged" );
+			for (Object id: updated)
+			{
+				System.out.println( "id changed: "+id );
+				System.out.println( "path changed: "+server.getPath( id ) );
+				changed.add( id );
+			}
 		}
+		
+		private final Set<Object> changed = Collections.synchronizedSet( new HashSet<Object>() );
+
+		public void setServer( ConfigurationServer server )
+		{
+			this.server = server;
+		}
+		
+		private ConfigurationServer server;
 	}
 }