FELIX-516 Record whether a configuration change (update, delete) has been delivered
to a ManagedService[Factory] to prevent multiple delivery. See issue description
for a situation where this might occurr.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@635540 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java
index 9b26f90..d0632b7 100644
--- a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java
+++ b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java
@@ -106,6 +106,17 @@
*/
private CaseInsensitiveDictionary properties;
+ /**
+ * Flag indicating that this configuration object has been delivered to the
+ * owning ManagedService[Factory] after the last update or after being
+ * deleted. This flag is set by the {@link #delete()}, {@link #update()}
+ * and {@link #update(Dictionary)} method and must be checked when this
+ * instance is about to be delivered and reset after the configuration has
+ * been delivered.
+ * @see #setDelivered(boolean)
+ * @see #isDelivered()
+ */
+ private boolean delivered;
ConfigurationImpl( ConfigurationManager configurationManager, PersistenceManager persistenceManager,
Dictionary properties )
@@ -140,7 +151,30 @@
}
- /* (non-Javadoc)
+ /**
+ * Sets whether the last change (update, delete) to this instance should be
+ * assumed as being delivered to the owning ManagedService[Factory] or not.
+ */
+ void setDelivered( boolean delivered )
+ {
+ this.delivered = delivered;
+ }
+
+
+ /**
+ * Returns whether the last change (update, delete) to this instance should
+ * be assumed as being delivered to the owning ManagedService[Factory] or
+ * not.
+ */
+ boolean isDelivered()
+ {
+ return delivered;
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
* @see org.osgi.service.cm.Configuration#delete()
*/
public void delete() throws IOException
@@ -150,6 +184,9 @@
persistenceManager.delete( pid );
persistenceManager = null;
+ // ensure configuration is being delivered
+ setDelivered( false );
+
configurationManager.deleted( this );
}
}
@@ -244,6 +281,9 @@
configureFromPersistence( properties );
+ // ensure configuration is being delivered
+ setDelivered( false );
+
configurationManager.updated( this );
}
}
@@ -264,6 +304,9 @@
configure( newProperties );
+ // ensure configuration is being delivered
+ setDelivered( false );
+
configurationManager.updated( this );
}
}
diff --git a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
index d42b728..a2fc2f8 100644
--- a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
+++ b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
@@ -491,7 +491,7 @@
Factory factory = Factory.getFactory( pmList[i], config );
if ( factory != null )
{
- Factory cachedFactory = ( Factory ) factories.get( factory.getFactoryPid() );
+ Factory cachedFactory = getCachedFactory( factory.getFactoryPid() );
if ( cachedFactory != null )
{
factory = cachedFactory;
@@ -591,9 +591,27 @@
}
+ Factory getCachedFactory( String factoryPid )
+ {
+ synchronized ( factories )
+ {
+ return ( Factory ) factories.get( factoryPid );
+ }
+ }
+
+
+ void cacheFactory( Factory factory )
+ {
+ synchronized ( factories )
+ {
+ factories.put( factory.getFactoryPid(), factory );
+ }
+ }
+
+
Factory getFactory( String factoryPid ) throws IOException
{
- Factory factory = ( Factory ) factories.get( factoryPid );
+ Factory factory = getCachedFactory( factoryPid );
if ( factory != null )
{
return factory;
@@ -605,7 +623,7 @@
if ( Factory.exists( pmList[i], factoryPid ) )
{
factory = Factory.load( pmList[i], factoryPid );
- factories.put( factoryPid, factory );
+ cacheFactory( factory );
return factory;
}
}
@@ -618,7 +636,7 @@
Factory createFactory( String factoryPid )
{
Factory factory = new Factory( getPersistenceManagers()[0], factoryPid );
- factories.put( factoryPid, factory );
+ cacheFactory( factory );
return factory;
}
@@ -816,6 +834,12 @@
if ( cfg != null && !cfg.isNew() )
{
+ if ( cfg.isDelivered() )
+ {
+ log( LogService.LOG_DEBUG, "Configuration " + pid + " has already been delivered", null );
+ return;
+ }
+
// 104.3 Ignore duplicate PIDs from other bundles and report
// them to the log
// 104.4.1 No update call back for PID already bound to another
@@ -861,6 +885,12 @@
try
{
service.updated( dictionary );
+
+ // if there is nothing to set, don't
+ if ( cfg != null )
+ {
+ cfg.setDelivered( true );
+ }
}
catch ( ConfigurationException ce )
{
@@ -974,6 +1004,13 @@
continue;
}
+ // do not re-updated unmodified configuration
+ if ( cfg.isDelivered() )
+ {
+ log( LogService.LOG_DEBUG, "Configuration " + pid + " has already been updated", null );
+ continue;
+ }
+
// check bundle location of configuration
if ( cfg.getBundleLocation() == null )
{
@@ -1000,6 +1037,7 @@
{
log( LogService.LOG_DEBUG, sr + ": Updating configuration pid=" + pid, null );
service.updated( pid, dictionary );
+ cfg.setDelivered( true );
}
}
catch ( ConfigurationException ce )
@@ -1044,6 +1082,12 @@
public void run()
{
+ if ( config.isDelivered() )
+ {
+ log( LogService.LOG_DEBUG, "Configuration " + config.getPid() + " has already been updated", null );
+ return;
+ }
+
try
{
if ( config.getFactoryPid() == null )
@@ -1079,6 +1123,7 @@
// update the ManagedService with the properties
srv.updated( dictionary );
+ config.setDelivered( true );
}
finally
{
@@ -1123,6 +1168,7 @@
if ( dictionary != null )
{
srv.updated( config.getPid(), dictionary );
+ config.setDelivered( true );
}
}
finally
@@ -1162,12 +1208,14 @@
private class DeleteConfiguration implements Runnable
{
+ private ConfigurationImpl config;
private String pid;
private String factoryPid;
DeleteConfiguration( ConfigurationImpl config )
{
+ this.config = config;
this.pid = config.getPid();
this.factoryPid = config.getFactoryPid();
}
@@ -1175,6 +1223,12 @@
public void run()
{
+ if ( config.isDelivered() )
+ {
+ log( LogService.LOG_DEBUG, "Deletion of configuration " + pid + " has already been delivered", null );
+ return;
+ }
+
try
{
if ( factoryPid == null )
@@ -1187,6 +1241,7 @@
try
{
srv.updated( null );
+ config.setDelivered( true );
}
finally
{
@@ -1209,6 +1264,7 @@
try
{
srv.deleted( pid );
+ config.setDelivered( true );
}
finally
{
@@ -1314,6 +1370,7 @@
if ( cfg != null && reference.equals( cfg.getServiceReference() ) )
{
cfg.setServiceReference( null );
+ cfg.setDelivered( false );
}
}
@@ -1372,5 +1429,30 @@
return serviceObject;
}
+
+ public void removedService( ServiceReference reference, Object service )
+ {
+ // check whether we can take back the configuration objects
+ String factoryPid = ( String ) reference.getProperty( Constants.SERVICE_PID );
+ if ( factoryPid != null )
+ {
+ Factory factory = cm.getCachedFactory( factoryPid );
+ if ( factory != null )
+ {
+ for ( Iterator pi = factory.getPIDs().iterator(); pi.hasNext(); )
+ {
+ String pid = ( String ) pi.next();
+ ConfigurationImpl cfg = cm.getCachedConfiguration( pid );
+ if ( cfg != null )
+ {
+ cfg.setDelivered( false );
+ }
+ }
+ }
+ }
+
+ super.removedService( reference, service );
+ }
+
}
}