Author: fmeschbe
Date: Wed Apr 25 08:50:30 2012
New Revision: 1330159
URL: http://svn.apache.org/viewvc?rev=1330159&view=rev
Log:
FELIX-3480 Implement support for SynchronousConfigurationListener
Added:
felix/sandbox/fmeschbe/configadmin-R5/src/test/java/org/apache/felix/cm/integration/ConfigurationListenerTest.java
Modified:
felix/sandbox/fmeschbe/configadmin-R5/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
Modified:
felix/sandbox/fmeschbe/configadmin-R5/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
URL:
http://svn.apache.org/viewvc/felix/sandbox/fmeschbe/configadmin-R5/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java?rev=1330159&r1=1330158&r2=1330159&view=diff
==============================================================================
---
felix/sandbox/fmeschbe/configadmin-R5/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
(original)
+++
felix/sandbox/fmeschbe/configadmin-R5/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
Wed Apr 25 08:50:30 2012
@@ -635,6 +635,7 @@ public class ConfigurationManager implem
void fireConfigurationEvent( int type, String pid, String factoryPid )
{
FireConfigurationEvent event = new FireConfigurationEvent( type, pid,
factoryPid );
+ event.fireSynchronousEvents();
if ( event.hasConfigurationEventListeners() )
{
eventThread.schedule( event );
@@ -1937,6 +1938,23 @@ public class ConfigurationManager implem
}
+ void fireSynchronousEvents()
+ {
+ if ( hasConfigurationEventListeners() )
+ {
+ final String typeName = getTypeName();
+ final ConfigurationEvent event = createEvent();
+ for ( int i = 0; i < this.listeners.length; i++ )
+ {
+ if ( this.listeners[i] instanceof
SynchronousConfigurationListener )
+ {
+ sendEvent( typeName, i, event );
+ }
+ }
+ }
+ }
+
+
boolean hasConfigurationEventListeners()
{
return this.listenerReferences != null;
@@ -1962,26 +1980,11 @@ public class ConfigurationManager implem
public void run()
{
final String typeName = getTypeName();
- final ConfigurationEvent event = new ConfigurationEvent(
getServiceReference(), type, factoryPid, pid );
+ final ConfigurationEvent event = createEvent();
for ( int i = 0; i < listeners.length; i++ )
{
- if ( listenerProvider[i].getState() == Bundle.ACTIVE )
- {
- log( LogService.LOG_DEBUG, "Sending {0} event for {1} to
{2}", new Object[]
- { typeName, pid, ConfigurationManager.toString(
listenerReferences[i] ) } );
-
- try
- {
- listeners[i].configurationEvent( event );
- }
- catch ( Throwable t )
- {
- log( LogService.LOG_ERROR, "Unexpected problem
delivering configuration event to {0}",
- new Object[]
- { ConfigurationManager.toString(
listenerReferences[i] ), t } );
- }
- }
+ sendEvent( typeName, i, event );
}
}
@@ -1989,6 +1992,36 @@ public class ConfigurationManager implem
{
return "Fire ConfigurationEvent: pid=" + pid;
}
+
+
+ private ConfigurationEvent createEvent()
+ {
+ return new ConfigurationEvent( getServiceReference(), type,
factoryPid, pid );
+ }
+
+
+ private void sendEvent( final String typeName, final int serviceIndex,
final ConfigurationEvent event )
+ {
+ if ( listenerProvider[serviceIndex].getState() == Bundle.ACTIVE &&
this.listeners[serviceIndex] != null )
+ {
+ log( LogService.LOG_DEBUG, "Sending {0} event for {1} to {2}",
new Object[]
+ { typeName, pid, ConfigurationManager.toString(
listenerReferences[serviceIndex] ) } );
+
+ try
+ {
+ listeners[serviceIndex].configurationEvent( event );
+ }
+ catch ( Throwable t )
+ {
+ log( LogService.LOG_ERROR, "Unexpected problem delivering
configuration event to {0}", new Object[]
+ { ConfigurationManager.toString(
listenerReferences[serviceIndex] ), t } );
+ }
+ finally
+ {
+ this.listeners[serviceIndex] = null;
+ }
+ }
+ }
}
private static class ManagedServiceTracker extends ServiceTracker
Added:
felix/sandbox/fmeschbe/configadmin-R5/src/test/java/org/apache/felix/cm/integration/ConfigurationListenerTest.java
URL:
http://svn.apache.org/viewvc/felix/sandbox/fmeschbe/configadmin-R5/src/test/java/org/apache/felix/cm/integration/ConfigurationListenerTest.java?rev=1330159&view=auto
==============================================================================
---
felix/sandbox/fmeschbe/configadmin-R5/src/test/java/org/apache/felix/cm/integration/ConfigurationListenerTest.java
(added)
+++
felix/sandbox/fmeschbe/configadmin-R5/src/test/java/org/apache/felix/cm/integration/ConfigurationListenerTest.java
Wed Apr 25 08:50:30 2012
@@ -0,0 +1,261 @@
+/*
+ * 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.felix.cm.integration;
+
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.cm.SynchronousConfigurationListener;
+
+
+@RunWith(JUnit4TestRunner.class)
+public class ConfigurationListenerTest extends ConfigurationTestBase
+{
+
+ static
+ {
+ // uncomment to enable debugging of this test class
+ // paxRunnerVmOption = DEBUG_VM_OPTION;
+ }
+
+
+ @Test
+ public void test_async_listener() throws IOException
+ {
+ final String pid = "test_listener";
+ final TestListener testListener = new TestListener();
+ final ServiceRegistration listener =
this.bundleContext.registerService( ConfigurationListener.class.getName(),
+ testListener, null );
+ int eventCount = 0;
+
+ Configuration config = configure( pid, null, false );
+ try
+ {
+ delay();
+ testListener.assertNoEvent();
+
+ config.update( new Hashtable<String, Object>()
+ {
+ {
+ put( "x", "x" );
+ }
+ } );
+ delay();
+ testListener.assertEvent( ConfigurationEvent.CM_UPDATED, pid,
null, true, ++eventCount );
+
+ config.update( new Hashtable<String, Object>()
+ {
+ {
+ put( "x", "x" );
+ }
+ } );
+ delay();
+ testListener.assertEvent( ConfigurationEvent.CM_UPDATED, pid,
null, true, ++eventCount );
+
+ config.setBundleLocation( "new_Location" );
+ delay();
+ testListener.assertEvent( ConfigurationEvent.CM_LOCATION_CHANGED,
pid, null, true, ++eventCount );
+
+ config.update();
+ testListener.assertNoEvent();
+
+ config.delete();
+ config = null;
+ delay();
+ testListener.assertEvent( ConfigurationEvent.CM_DELETED, pid,
null, true, ++eventCount );
+ }
+ finally
+ {
+ if ( config != null )
+ {
+ try
+ {
+ config.delete();
+ }
+ catch ( IOException ioe )
+ {
+ // ignore
+ }
+ }
+
+ listener.unregister();
+ }
+ }
+
+
+ @Test
+ public void test_sync_listener() throws IOException
+ {
+ final String pid = "test_listener";
+ Configuration config = configure( pid, null, false );
+ final TestListener testListener = new SynchronousTestListener();
+ final ServiceRegistration listener =
this.bundleContext.registerService( ConfigurationListener.class.getName(),
+ testListener, null );
+ int eventCount = 0;
+ try
+ {
+ delay();
+ testListener.assertNoEvent();
+
+ config.update( new Hashtable<String, Object>()
+ {
+ {
+ put( "x", "x" );
+ }
+ } );
+ delay();
+ testListener.assertEvent( ConfigurationEvent.CM_UPDATED, pid,
null, false, ++eventCount );
+
+ config.update( new Hashtable<String, Object>()
+ {
+ {
+ put( "x", "x" );
+ }
+ } );
+ delay();
+ testListener.assertEvent( ConfigurationEvent.CM_UPDATED, pid,
null, false, ++eventCount );
+
+ config.setBundleLocation( "new_Location" );
+ delay();
+ testListener.assertEvent( ConfigurationEvent.CM_LOCATION_CHANGED,
pid, null, false, ++eventCount );
+
+ config.update();
+ testListener.assertNoEvent();
+
+ config.delete();
+ config = null;
+ delay();
+ testListener.assertEvent( ConfigurationEvent.CM_DELETED, pid,
null, false, ++eventCount );
+ }
+ finally
+ {
+ if ( config != null )
+ {
+ try
+ {
+ config.delete();
+ }
+ catch ( IOException ioe )
+ {
+ // ignore
+ }
+ }
+
+ listener.unregister();
+ }
+ }
+
+ private static class TestListener implements ConfigurationListener
+ {
+
+ private final Thread mainThread;
+
+ private ConfigurationEvent event;
+
+ private Thread eventThread;
+
+ private int numberOfEvents;
+
+
+ TestListener()
+ {
+ this.mainThread = Thread.currentThread();
+ this.numberOfEvents = 0;
+ }
+
+
+ public void configurationEvent( final ConfigurationEvent event )
+ {
+ this.numberOfEvents++;
+
+ if ( this.event != null )
+ {
+ throw new IllegalStateException( "Untested event to be
replaced: " + this.event.getType() + "/"
+ + this.event.getPid() );
+ }
+
+ this.event = event;
+ this.eventThread = Thread.currentThread();
+ }
+
+
+ void resetNumberOfEvents()
+ {
+ this.numberOfEvents = 0;
+ }
+
+
+ void assertEvent( final int type, final String pid, final String
factoryPid, final boolean expectAsync,
+ final int numberOfEvents )
+ {
+ try
+ {
+ TestCase.assertNotNull( "Expecting an event", this.event );
+ TestCase.assertEquals( "Expecting event type " + type, type,
this.event.getType() );
+ TestCase.assertEquals( "Expecting pid " + pid, pid,
this.event.getPid() );
+ if ( factoryPid == null )
+ {
+ TestCase.assertNull( "Expecting no factoryPid",
this.event.getFactoryPid() );
+ }
+ else
+ {
+ TestCase.assertEquals( "Expecting factory pid " +
factoryPid, factoryPid,
+ this.event.getFactoryPid() );
+ }
+
+ TestCase.assertEquals( "Expecting " + numberOfEvents + "
events", numberOfEvents,
+ this.numberOfEvents );
+
+ if ( expectAsync )
+ {
+ TestCase.assertNotSame( "Expecting asynchronous event",
this.mainThread, this.eventThread );
+ }
+ else
+ {
+ TestCase.assertSame( "Expecting synchronous event",
this.mainThread, this.eventThread );
+ }
+ }
+ finally
+ {
+ this.event = null;
+ this.eventThread = null;
+ }
+ }
+
+
+ void assertNoEvent()
+ {
+ TestCase.assertNull( this.event );
+ }
+ }
+
+ private static class SynchronousTestListener extends TestListener
implements SynchronousConfigurationListener
+ {
+ }
+}