You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cz...@apache.org on 2016/09/16 06:11:25 UTC

svn commit: r1760997 [1/2] - in /felix/trunk/configadmin: ./ src/main/java/org/apache/felix/cm/impl/ src/main/java/org/osgi/ src/main/java/org/osgi/service/ src/main/java/org/osgi/service/cm/ src/test/java/org/apache/felix/cm/ src/test/java/org/apache/...

Author: cziegeler
Date: Fri Sep 16 06:11:25 2016
New Revision: 1760997

URL: http://svn.apache.org/viewvc?rev=1760997&view=rev
Log:
FELIX-5288 - Implement RFC 227 (R7 Update)

Added:
    felix/trunk/configadmin/src/main/java/org/osgi/
    felix/trunk/configadmin/src/main/java/org/osgi/service/
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/Configuration.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationEvent.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationException.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationListener.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationPermission.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationPlugin.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/LockedConfigurationException.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ManagedService.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ManagedServiceFactory.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/SynchronousConfigurationListener.java   (with props)
    felix/trunk/configadmin/src/main/java/org/osgi/service/cm/package-info.java   (with props)
Modified:
    felix/trunk/configadmin/changelog.txt
    felix/trunk/configadmin/pom.xml
    felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdapter.java
    felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdminImpl.java
    felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java
    felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/RankingComparator.java
    felix/trunk/configadmin/src/test/java/org/apache/felix/cm/MockBundleContext.java
    felix/trunk/configadmin/src/test/java/org/apache/felix/cm/impl/ConfigurationManagerTest.java
    felix/trunk/configadmin/src/test/java/org/apache/felix/cm/impl/RankingComparatorTest.java

Modified: felix/trunk/configadmin/changelog.txt
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/changelog.txt?rev=1760997&r1=1760996&r2=1760997&view=diff
==============================================================================
--- felix/trunk/configadmin/changelog.txt (original)
+++ felix/trunk/configadmin/changelog.txt Fri Sep 16 06:11:25 2016
@@ -1,3 +1,14 @@
+Changes in 1.9.0
+----------------
+** Improvement
+    * [FELIX-5288] - Implement RFC 227 (R7 Update)
+    * [FELIX-5289] - PID Handling of Factory Configurations
+    * [FELIX-5290] - Locking Configuration Records
+    * [FELIX-5291] - Improving Configuration Updates
+    * [FELIX-5292] - Capabilities
+    * [FELIX-5293] - Improved ConfigurationPlugin Support
+
+
 Changes from 1.8.8 to 1.8.10
 ----------------------------
 

Modified: felix/trunk/configadmin/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/pom.xml?rev=1760997&r1=1760996&r2=1760997&view=diff
==============================================================================
--- felix/trunk/configadmin/pom.xml (original)
+++ felix/trunk/configadmin/pom.xml Fri Sep 16 06:11:25 2016
@@ -22,8 +22,8 @@
     <parent>
         <groupId>org.apache.felix</groupId>
         <artifactId>felix-parent</artifactId>
-        <version>3</version>
-        <relativePath>../pom/pom.xml</relativePath>
+        <version>4</version>
+        <relativePath/>
     </parent>
 
     <artifactId>org.apache.felix.configadmin</artifactId>
@@ -68,6 +68,7 @@
         in the IDE launcher. 
     -->
     <properties>
+        <felix.java.version>6</felix.java.version>
         <bundle.build.name>
             ${basedir}/target
         </bundle.build.name>
@@ -77,29 +78,25 @@
     </properties>
 
     <dependencies>
-    
-        <!--
-            Depend on latest version to make use of generics. Still we
-            make sure to only require Framework API 1.5 (OSGi Core R4.2)
-        -->
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.annotation</artifactId>
+            <version>6.0.1</version>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
-            <version>5.0.0</version>
+            <version>6.0.0</version>
             <scope>provided</scope>
         </dependency>
-        
-        <!--
-            Configuration Admin and other API from latest enterprise
-            which provides Config Admin 1.5 API
-        -->
         <dependency>
             <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.enterprise</artifactId>
-            <version>5.0.0</version>
+            <artifactId>org.osgi.service.log</artifactId>
+            <version>1.3.0</version>
             <scope>provided</scope>
         </dependency>
-
+        
         <!-- BND export annotations -->        
         <dependency>
             <groupId>biz.aQute</groupId>
@@ -112,7 +109,6 @@
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <version>4.6</version>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -160,7 +156,7 @@
         <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.framework</artifactId>
-            <version>4.0.3</version>
+            <version>5.4.0</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
@@ -170,7 +166,7 @@
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
-                <version>2.3.7</version>
+                <version>3.0.1</version>
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
@@ -190,11 +186,10 @@
                             <!-- when the spec version changes, update the service property that includes the spec version in ConfigurationManager -->
                             org.apache.felix.cm;
                             org.apache.felix.cm.file,
-                            org.osgi.service.cm;provide:=true;version=1.5
+                            org.osgi.service.cm;provide:=true;version=1.6
                         </Export-Package>
                         <Import-Package>
-                            org.osgi.service.cm;version="[1.5,1.6)",
-                            org.osgi.framework;version="[1.4,2)",
+                            org.osgi.service.cm;version="[1.6,1.7)",
 							org.osgi.service.log;resolution:=optional;version="1.3",
                             *
                         </Import-Package>
@@ -202,9 +197,14 @@
                             <!-- overwrite version from compendium bundle -->
                             org.osgi.service.log;version="1.3"
                         </DynamicImport-Package>
-                        <Provide-Capability>osgi.service;objectClass:List&lt;String&gt;="org.osgi.service.cm.ConfigurationAdmin",
-                        osgi.service;objectClass:List&lt;String&gt;="org.apache.felix.cm.PersistenceManager"</Provide-Capability>
-                        <Require-Capability>osgi.service;filter:="(objectClass=org.osgi.service.log.LogService)";effective:=active;resolution:=optional</Require-Capability>
+                        <Provide-Capability><![CDATA[
+                            osgi.service;objectClass:List<String>="org.osgi.service.cm.ConfigurationAdmin";uses:="org.osgi.service.cm,org.apache.felix.cm",
+                            osgi.service;objectClass:List<String>="org.apache.felix.cm.PersistenceManager";uses:="org.osgi.service.cm,org.apache.felix.cm",
+                            osgi.implementation;osgi.implementation="osgi.cm";uses:="org.osgi.service.cm,org.apache.felix.cm";version:Version="1.6"
+                        ]]></Provide-Capability>
+                        <Require-Capability><![CDATA[
+                            osgi.service;filter:="(objectClass=org.osgi.service.log.LogService)";effective:=active;resolution:=optional
+                        ]]></Require-Capability>
                         <Embed-Dependency>
                             org.osgi.core;inline=org/osgi/util/tracker/ServiceTracker*|org/osgi/util/tracker/AbstractTracked.class
                         </Embed-Dependency>

Modified: felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdapter.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdapter.java?rev=1760997&r1=1760996&r2=1760997&view=diff
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdapter.java (original)
+++ felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdapter.java Fri Sep 16 06:11:25 2016
@@ -22,7 +22,13 @@ package org.apache.felix.cm.impl;
 import java.io.IOException;
 import java.util.Dictionary;
 
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
 import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationPermission;
+import org.osgi.service.cm.LockedConfigurationException;
+import org.osgi.service.cm.ManagedService;
 import org.osgi.service.log.LogService;
 
 
@@ -49,6 +55,7 @@ public class ConfigurationAdapter implem
     /**
      * @see org.apache.felix.cm.impl.ConfigurationImpl#getPid()
      */
+    @Override
     public String getPid()
     {
         checkDeleted();
@@ -59,6 +66,7 @@ public class ConfigurationAdapter implem
     /**
      * @see org.apache.felix.cm.impl.ConfigurationImpl#getFactoryPid()
      */
+    @Override
     public String getFactoryPid()
     {
         checkDeleted();
@@ -69,6 +77,7 @@ public class ConfigurationAdapter implem
     /**
      * @see org.apache.felix.cm.impl.ConfigurationImpl#getBundleLocation()
      */
+    @Override
     public String getBundleLocation()
     {
         // CM 1.4 / 104.13.2.4
@@ -86,6 +95,7 @@ public class ConfigurationAdapter implem
      * @param bundleLocation
      * @see org.apache.felix.cm.impl.ConfigurationImpl#setStaticBundleLocation(String)
      */
+    @Override
     public void setBundleLocation( String bundleLocation )
     {
         delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "setBundleLocation(bundleLocation={0})",
@@ -106,6 +116,7 @@ public class ConfigurationAdapter implem
      * @throws IOException
      * @see org.apache.felix.cm.impl.ConfigurationImpl#update()
      */
+    @Override
     public void update() throws IOException
     {
         delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "update()", ( Throwable ) null );
@@ -121,18 +132,21 @@ public class ConfigurationAdapter implem
      * @throws IOException
      * @see org.apache.felix.cm.impl.ConfigurationImpl#update(java.util.Dictionary)
      */
-    public void update( Dictionary properties ) throws IOException
+    @Override
+    public void update( Dictionary<String, ?> properties ) throws IOException
     {
         delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "update(properties={0})", new Object[]
             { properties } );
 
         checkActive();
         checkDeleted();
+        checkLocked();
         delegatee.update( properties );
     }
 
 
-    public Dictionary getProperties()
+    @Override
+    public Dictionary<String, Object> getProperties()
     {
         delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "getProperties()", ( Throwable ) null );
 
@@ -144,6 +158,7 @@ public class ConfigurationAdapter implem
     }
 
 
+    @Override
     public long getChangeCount()
     {
         delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "getChangeCount()", ( Throwable ) null );
@@ -158,6 +173,7 @@ public class ConfigurationAdapter implem
      * @throws IOException
      * @see org.apache.felix.cm.impl.ConfigurationImpl#delete()
      */
+    @Override
     public void delete() throws IOException
     {
         delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "delete()", ( Throwable ) null );
@@ -169,8 +185,78 @@ public class ConfigurationAdapter implem
 
 
     /**
+     * @see org.osgi.service.cm.Configuration#setProperties(java.util.Dictionary)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean setProperties(final Dictionary<String, ?> properties) throws IOException
+    {
+        delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "setProperties(properties={0})", new Object[]
+                { properties } );
+
+        checkActive();
+        checkDeleted();
+        checkLocked();
+
+        if ( ConfigurationImpl.equals((Dictionary<String, Object>)properties, delegatee.getProperties(false)) )
+        {
+            // nothing to do
+            return false;
+        }
+        delegatee.update( properties );
+        return true;
+    }
+
+
+    /**
+     * @see org.osgi.service.cm.Configuration#setLocked(boolean)
+     */
+    @Override
+    public void setLocked(boolean flag) throws IOException
+    {
+        delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "setLocked({0})",
+                new Object[] { flag } );
+
+        checkDeleted();
+        final String bundleLocation = delegatee.getBundleLocation();
+        this.configurationAdmin.checkPermission(this.delegatee.getConfigurationManager(),
+                ( bundleLocation == null ) ? "*" : bundleLocation,
+                        ConfigurationPermission.LOCK,
+                        true);
+        delegatee.setLocked( flag );
+    }
+
+
+    /**
+     * @see org.osgi.service.cm.Configuration#getModifiedProperties(org.osgi.framework.ServiceReference)
+     */
+    @Override
+    public Dictionary<String, Object> getModifiedProperties(ServiceReference<ManagedService> sr) {
+        final Dictionary<String, Object> props = this.getProperties();
+
+        this.delegatee.getConfigurationManager().callPlugins(props, sr,
+                (String)props.get(Constants.SERVICE_PID),
+                (String)props.get(ConfigurationAdmin.SERVICE_FACTORYPID));
+
+        return props;
+    }
+
+
+    /**
+     * @see org.osgi.service.cm.Configuration#isLocked()
+     */
+    @Override
+    public boolean isLocked()
+    {
+        checkDeleted();
+        return delegatee.isLocked();
+    }
+
+
+    /**
      * @see org.apache.felix.cm.impl.ConfigurationImpl#hashCode()
      */
+    @Override
     public int hashCode()
     {
         return delegatee.hashCode();
@@ -181,6 +267,7 @@ public class ConfigurationAdapter implem
      * @param obj
      * @see org.apache.felix.cm.impl.ConfigurationImpl#equals(java.lang.Object)
      */
+    @Override
     public boolean equals( Object obj )
     {
         return delegatee.equals( obj );
@@ -190,6 +277,7 @@ public class ConfigurationAdapter implem
     /**
      * @see org.apache.felix.cm.impl.ConfigurationImpl#toString()
      */
+    @Override
     public String toString()
     {
         return delegatee.toString();
@@ -225,4 +313,17 @@ public class ConfigurationAdapter implem
             throw new IllegalStateException( "Configuration " + delegatee.getPid() + " deleted" );
         }
     }
+
+    /**
+     * Checks whether this configuration object is locked.
+     *
+     * @throws LockedConfigurationException If this configuration object is locked.
+     */
+    private void checkLocked() throws IOException
+    {
+        if ( delegatee.isLocked() )
+        {
+            throw new LockedConfigurationException( "Configuration " + delegatee.getPid() + " is locked" );
+        }
+    }
 }

Modified: felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdminImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdminImpl.java?rev=1760997&r1=1760996&r2=1760997&view=diff
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdminImpl.java (original)
+++ felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdminImpl.java Fri Sep 16 06:11:25 2016
@@ -70,6 +70,7 @@ public class ConfigurationAdminImpl impl
     /* (non-Javadoc)
      * @see org.osgi.service.cm.ConfigurationAdmin#createFactoryConfiguration(java.lang.String)
      */
+    @Override
     public Configuration createFactoryConfiguration( String factoryPid ) throws IOException
     {
         final ConfigurationManager configurationManager = getConfigurationManager();
@@ -87,6 +88,7 @@ public class ConfigurationAdminImpl impl
     /* (non-Javadoc)
      * @see org.osgi.service.cm.ConfigurationAdmin#createFactoryConfiguration(java.lang.String, java.lang.String)
      */
+    @Override
     public Configuration createFactoryConfiguration( String factoryPid, String location ) throws IOException
     {
         final ConfigurationManager configurationManager = getConfigurationManager();
@@ -106,6 +108,7 @@ public class ConfigurationAdminImpl impl
     /* (non-Javadoc)
      * @see org.osgi.service.cm.ConfigurationAdmin#getConfiguration(java.lang.String)
      */
+    @Override
     public Configuration getConfiguration( String pid ) throws IOException
     {
         final ConfigurationManager configurationManager = getConfigurationManager();
@@ -147,6 +150,7 @@ public class ConfigurationAdminImpl impl
     /* (non-Javadoc)
      * @see org.osgi.service.cm.ConfigurationAdmin#getConfiguration(java.lang.String, java.lang.String)
      */
+    @Override
     public Configuration getConfiguration( String pid, String location ) throws IOException
     {
         final ConfigurationManager configurationManager = getConfigurationManager();
@@ -175,6 +179,7 @@ public class ConfigurationAdminImpl impl
     /* (non-Javadoc)
      * @see org.osgi.service.cm.ConfigurationAdmin#listConfigurations(java.lang.String)
      */
+    @Override
     public Configuration[] listConfigurations( String filter ) throws IOException, InvalidSyntaxException
     {
         final ConfigurationManager configurationManager = getConfigurationManager();
@@ -239,6 +244,25 @@ public class ConfigurationAdminImpl impl
      */
     void checkPermission( final ConfigurationManager configurationManager, String name, boolean checkOwn )
     {
+        checkPermission(configurationManager, name, ConfigurationPermission.CONFIGURE, checkOwn);
+    }
+
+    /**
+     * Checks whether the current access control context (call stack) has
+     * the given permission for the given bundle location and throws a
+     * <code>SecurityException</code> if this is not the case.
+     *
+     * @param name The bundle location to check for permission. If this
+     *      is <code>null</code> permission is always granted.
+     * @param action The action to check.
+     * @param checkOwn If {@code false} permission is alwas granted if
+     *      {@code name} is the same the using bundle's location.
+     *
+     * @throws SecurityException if the access control context does not
+     *      have the appropriate permission
+     */
+    void checkPermission( final ConfigurationManager configurationManager, String name, String action, boolean checkOwn )
+    {
         // the caller's permission must be checked
         final SecurityManager sm = System.getSecurityManager();
         if ( sm != null )
@@ -248,45 +272,45 @@ public class ConfigurationAdminImpl impl
             {
                 try
                 {
-                    sm.checkPermission( new ConfigurationPermission( name, ConfigurationPermission.CONFIGURE ) );
+                    sm.checkPermission( new ConfigurationPermission( name, action ) );
 
                     configurationManager.log( LogService.LOG_DEBUG,
-                        "Explicit Permission; grant CONFIGURE permission on configuration bound to {0} to bundle {1}",
+                        "Explicit Permission; grant {0} permission on configuration bound to {1} to bundle {2}",
                         new Object[]
-                            { name, getBundle().getLocation() } );
+                            { action, name, getBundle().getLocation() } );
                 }
                 catch ( SecurityException se )
                 {
                     configurationManager
                         .log(
                             LogService.LOG_DEBUG,
-                            "No Permission; denied CONFIGURE permission on configuration bound to {0} to bundle {1}; reason: {2}",
+                            "No Permission; denied {0} permission on configuration bound to {1} to bundle {2}; reason: {3}",
                             new Object[]
-                                { name, getBundle().getLocation(), se.getMessage() } );
+                                { action, name, getBundle().getLocation(), se.getMessage() } );
                     throw se;
                 }
             }
             else if ( configurationManager.isLogEnabled( LogService.LOG_DEBUG ) )
             {
                 configurationManager.log( LogService.LOG_DEBUG,
-                    "Implicit Permission; grant CONFIGURE permission on configuration bound to {0} to bundle {1}",
+                    "Implicit Permission; grant {0} permission on configuration bound to {1} to bundle {2}",
                     new Object[]
-                        { name, getBundle().getLocation() } );
+                        { action, name, getBundle().getLocation() } );
 
             }
         }
         else if ( configurationManager.isLogEnabled( LogService.LOG_DEBUG ) )
         {
             configurationManager.log( LogService.LOG_DEBUG,
-                "No SecurityManager installed; grant CONFIGURE permission on configuration bound to {0} to bundle {1}",
+                "No SecurityManager installed; grant {0} permission on configuration bound to {1} to bundle {2}",
                 new Object[]
-                    { name, getBundle().getLocation() } );
+                    { action, name, getBundle().getLocation() } );
         }
     }
 
 
     /**
-     * Returns the {@link ConfigurationManager} backing this configuraiton
+     * Returns the {@link ConfigurationManager} backing this configuration
      * admin instance or throws {@code IllegalStateException} if already
      * disposed off.
      *
@@ -303,4 +327,79 @@ public class ConfigurationAdminImpl impl
 
         return this.configurationManager;
     }
+
+
+    /**
+     * @see org.osgi.service.cm.ConfigurationAdmin#getFactoryConfiguration(java.lang.String, java.lang.String, java.lang.String)
+     */
+    @Override
+    public Configuration getFactoryConfiguration(String factoryPid, String alias, String location) throws IOException
+    {
+        final ConfigurationManager configurationManager = getConfigurationManager();
+
+        configurationManager.log( LogService.LOG_DEBUG, "getFactoryConfiguration(factoryPid={0}, alias={1}, location={2})", new Object[]
+            { factoryPid, alias, location } );
+
+        final String pid = factoryPid + '#' + alias;
+
+        // CM 1.4 / 104.13.2.3
+        this.checkPermission( configurationManager, ( location == null ) ? "*" : location, false );
+
+        ConfigurationImpl config = configurationManager.getConfiguration( pid );
+        if ( config == null )
+        {
+            config = configurationManager.createConfiguration( pid, factoryPid, location );
+        }
+        else
+        {
+            final String configLocation = config.getBundleLocation();
+            this.checkPermission( configurationManager, ( configLocation == null ) ? "*" : configLocation, false );
+        }
+
+        return this.wrap( config );
+      }
+
+
+    /**
+     * @see org.osgi.service.cm.ConfigurationAdmin#getFactoryConfiguration(java.lang.String, java.lang.String)
+     */
+    @Override
+    public Configuration getFactoryConfiguration(String factoryPid, String alias) throws IOException {
+        final ConfigurationManager configurationManager = getConfigurationManager();
+
+        configurationManager.log( LogService.LOG_DEBUG, "getFactoryConfiguration(factoryPid={0}, alias={1})", new Object[]
+            { factoryPid, alias } );
+
+        final String pid = factoryPid + '#' + alias;
+
+        ConfigurationImpl config = configurationManager.getConfiguration( pid );
+        if ( config == null )
+        {
+            config = configurationManager.createConfiguration( pid, factoryPid, null );
+
+            // FELIX-3360: configuration creation with implicit binding is dynamic
+            config.setDynamicBundleLocation( getBundle().getLocation(), false );
+        }
+        else
+        {
+            if ( config.getBundleLocation() == null )
+            {
+                configurationManager.log( LogService.LOG_DEBUG, "Binding configuration {0} (isNew: {1}) to bundle {2}",
+                    new Object[]
+                        { config.getPid(), config.isNew() ? Boolean.TRUE : Boolean.FALSE,
+                            this.getBundle().getLocation() } );
+
+                // FELIX-3360: first implicit binding is dynamic
+                config.setDynamicBundleLocation( getBundle().getLocation(), true );
+            }
+            else
+            {
+                // CM 1.4 / 104.13.2.3
+                this.checkPermission( configurationManager, config.getBundleLocation(), false );
+            }
+        }
+
+        return this.wrap( config );
+    }
+
 }

Modified: felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java?rev=1760997&r1=1760996&r2=1760997&view=diff
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java (original)
+++ felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java Fri Sep 16 06:11:25 2016
@@ -21,6 +21,7 @@ package org.apache.felix.cm.impl;
 
 import java.io.IOException;
 import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.Hashtable;
 
 import org.apache.felix.cm.PersistenceManager;
@@ -96,6 +97,8 @@ public class ConfigurationImpl extends C
      */
     private static final String CONFIGURATION_NEW = "_felix_.cm.newConfiguration";
 
+    private static final String PROPERTY_LOCKED = ":org.apache.felix.configadmin.locked:";
+
     /**
      * The factory PID of this configuration or <code>null</code> if this
      * is not a factory configuration.
@@ -140,9 +143,11 @@ public class ConfigurationImpl extends C
      */
     private volatile long revision;
 
+    private volatile boolean locked;
+
 
     ConfigurationImpl( ConfigurationManager configurationManager, PersistenceManager persistenceManager,
-        Dictionary properties )
+        Dictionary<String, Object> properties )
     {
         super( configurationManager, persistenceManager, ( String ) properties.remove( Constants.SERVICE_PID ) );
 
@@ -315,7 +320,7 @@ public class ConfigurationImpl extends C
      *            <code>true</code> if a deep copy is to be returned.
      * @return the configuration properties
      */
-    public Dictionary getProperties( boolean deepCopy )
+    public Dictionary<String, Object> getProperties( boolean deepCopy )
     {
         // no properties yet
         if ( properties == null )
@@ -343,7 +348,7 @@ public class ConfigurationImpl extends C
             // read configuration from persistence (again)
             if ( localPersistenceManager.exists( getPidString() ) )
             {
-                Dictionary properties = localPersistenceManager.load( getPidString() );
+                Dictionary<String, Object> properties = localPersistenceManager.load( getPidString() );
 
                 // ensure serviceReference pid
                 String servicePid = ( String ) properties.get( Constants.SERVICE_PID );
@@ -362,10 +367,10 @@ public class ConfigurationImpl extends C
     }
 
 
-    /* (non-Javadoc)
+    /**
      * @see org.osgi.service.cm.Configuration#update(java.util.Dictionary)
      */
-    public void update( Dictionary properties ) throws IOException
+    public void update( Dictionary<String, ?> properties ) throws IOException
     {
         PersistenceManager localPersistenceManager = getPersistenceManager();
         if ( localPersistenceManager != null )
@@ -397,6 +402,7 @@ public class ConfigurationImpl extends C
 
     //---------- Object overwrites --------------------------------------------
 
+    @Override
     public boolean equals( Object obj )
     {
         if ( obj == this )
@@ -413,12 +419,14 @@ public class ConfigurationImpl extends C
     }
 
 
+    @Override
     public int hashCode()
     {
         return getPidString().hashCode();
     }
 
 
+    @Override
     public String toString()
     {
         return "Configuration PID=" + getPidString() + ", factoryPID=" + factoryPID + ", bundleLocation=" + getBundleLocation();
@@ -456,7 +464,7 @@ public class ConfigurationImpl extends C
      */
     private void storeNewConfiguration() throws IOException
     {
-        Dictionary props = new Hashtable();
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
         setAutoProperties( props, true );
         props.put( CONFIGURATION_NEW, Boolean.TRUE );
         getPersistenceManager().store( getPidString(), props );
@@ -494,17 +502,18 @@ public class ConfigurationImpl extends C
     }
 
 
+    @Override
     void store() throws IOException
     {
         // we don't need a deep copy, since we are not modifying
         // any value in the dictionary itself. we are just adding
         // properties to it, which are required for storing
-        Dictionary props = getProperties( false );
+        Dictionary<String, Object> props = getProperties( false );
 
         // if this is a new configuration, we just use an empty Dictionary
         if ( props == null )
         {
-            props = new Hashtable();
+            props = new Hashtable<String, Object>();
 
             // add automatic properties including the bundle location (if
             // statically bound)
@@ -515,6 +524,11 @@ public class ConfigurationImpl extends C
             replaceProperty( props, ConfigurationAdmin.SERVICE_BUNDLELOCATION, getStaticBundleLocation() );
         }
 
+        if ( this.locked )
+        {
+            props.put(PROPERTY_LOCKED, this.locked);
+        }
+
         // only store now, if this is not a new configuration
         getPersistenceManager().store( getPidString(), props );
     }
@@ -555,7 +569,7 @@ public class ConfigurationImpl extends C
     }
 
 
-    private void configureFromPersistence( Dictionary properties )
+    private void configureFromPersistence( Dictionary<String, Object> properties )
     {
         // if the this is not an empty/new configuration, accept the properties
         // otherwise just set the properties field to null
@@ -569,8 +583,13 @@ public class ConfigurationImpl extends C
         }
     }
 
-    private void configure( final Dictionary properties )
+    private void configure( final Dictionary<String, Object> properties )
     {
+        final Object lockedValue = properties == null ? null : properties.get(PROPERTY_LOCKED);
+        if ( lockedValue != null )
+        {
+            this.locked = true;
+        }
         final CaseInsensitiveDictionary newProperties;
         if ( properties == null )
         {
@@ -600,7 +619,7 @@ public class ConfigurationImpl extends C
     }
 
 
-    void setAutoProperties( Dictionary properties, boolean withBundleLocation )
+    void setAutoProperties( Dictionary<String, Object> properties, boolean withBundleLocation )
     {
         // set pid and factory pid in the properties
         replaceProperty( properties, Constants.SERVICE_PID, getPidString() );
@@ -618,7 +637,7 @@ public class ConfigurationImpl extends C
     }
 
 
-    static void setAutoProperties( Dictionary properties, String pid, String factoryPid )
+    static void setAutoProperties( Dictionary<String, Object> properties, String pid, String factoryPid )
     {
         replaceProperty( properties, Constants.SERVICE_PID, pid );
         replaceProperty( properties, ConfigurationAdmin.SERVICE_FACTORYPID, factoryPid );
@@ -626,10 +645,105 @@ public class ConfigurationImpl extends C
     }
 
 
-    static void clearAutoProperties( Dictionary properties )
+    private static final String[] AUTO_PROPS = new String[] {
+            Constants.SERVICE_PID,
+            ConfigurationAdmin.SERVICE_FACTORYPID,
+            ConfigurationAdmin.SERVICE_BUNDLELOCATION,
+            PROPERTY_LOCKED
+    };
+
+    static void clearAutoProperties( Dictionary<String, Object> properties )
     {
-        properties.remove( Constants.SERVICE_PID );
-        properties.remove( ConfigurationAdmin.SERVICE_FACTORYPID );
-        properties.remove( ConfigurationAdmin.SERVICE_BUNDLELOCATION );
+        for(final String p : AUTO_PROPS)
+        {
+            properties.remove( p );
+        }
+    }
+
+
+    public void setLocked(final boolean flag) throws IOException
+    {
+        this.locked = flag;
+        store();
+    }
+
+    /**
+     * Compare the two properties, ignoring auto properties
+     * @param props1 Set of properties
+     * @param props2 Set of properties
+     * @return {@code true} if the set of properties is equal
+     */
+    static boolean equals( Dictionary<String, Object> props1, Dictionary<String, Object> props2)
+    {
+        final int count1 = getCount(props1);
+        final int count2 = getCount(props2);
+        if ( count1 != count2 )
+        {
+            return false;
+        }
+
+        final Enumeration<String> keys = props1.keys();
+        while ( keys.hasMoreElements() )
+        {
+            final String key = keys.nextElement();
+            if ( !isAutoProp(key) )
+            {
+                final Object val1 = props1.get(key);
+                final Object val2 = props2.get(key);
+                if ( val1 == null )
+                {
+                    if ( val2 != null )
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    if ( val2 == null )
+                    {
+                        return false;
+                    }
+                    if ( !val1.equals(val2) )
+                    {
+                        return false;
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
+    static boolean isAutoProp(final String name)
+    {
+        for(final String p : AUTO_PROPS)
+        {
+            if ( p.equals(name) )
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static int getCount( Dictionary<String, Object> props )
+    {
+        int count = (props == null ? 0 : props.size());
+        if ( props != null )
+        {
+            for(final String p : AUTO_PROPS)
+            {
+                if ( props.get(p) != null )
+                {
+                    count--;
+                }
+            }
+        }
+        return count;
+    }
+
+    public boolean isLocked()
+    {
+        return this.locked;
     }
 }

Modified: felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/RankingComparator.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/RankingComparator.java?rev=1760997&r1=1760996&r2=1760997&view=diff
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/RankingComparator.java (original)
+++ felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/RankingComparator.java Fri Sep 16 06:11:25 2016
@@ -95,16 +95,16 @@ public abstract class RankingComparator
             final long id1 = this.getLong( obj1, Constants.SERVICE_ID );
             final long id2 = this.getLong( obj2, Constants.SERVICE_ID );
 
+            if ( id1 == id2 )
+            {
+                return 0;
+            }
+
             final int rank1 = this.getInteger( obj1, ConfigurationPlugin.CM_RANKING );
             final int rank2 = this.getInteger( obj2, ConfigurationPlugin.CM_RANKING );
 
             if ( rank1 == rank2 )
             {
-                if ( id1 == id2 )
-                {
-                    return 0;
-                }
-
                 return ( id1 > id2 ) ? -1 : 1;
             }
 

Added: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/Configuration.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/osgi/service/cm/Configuration.java?rev=1760997&view=auto
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/osgi/service/cm/Configuration.java (added)
+++ felix/trunk/configadmin/src/main/java/org/osgi/service/cm/Configuration.java Fri Sep 16 06:11:25 2016
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) OSGi Alliance (2001, 2016). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import java.io.IOException;
+import java.util.Dictionary;
+
+import org.osgi.annotation.versioning.ProviderType;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * The configuration information for a {@code ManagedService} or
+ * {@code ManagedServiceFactory} object.
+ *
+ * The Configuration Admin service uses this interface to represent the
+ * configuration information for a {@code ManagedService} or for a service
+ * instance of a {@code ManagedServiceFactory}.
+ *
+ * <p>
+ * A {@code Configuration} object contains a configuration dictionary and allows
+ * the properties to be updated via this object. Bundles wishing to receive
+ * configuration dictionaries do not need to use this class - they register a
+ * {@code ManagedService} or {@code ManagedServiceFactory}. Only administrative
+ * bundles, and bundles wishing to update their own configurations need to use
+ * this class.
+ *
+ * <p>
+ * The properties handled in this configuration have case insensitive
+ * {@code String} objects as keys. However, case must be preserved from the last
+ * set key/value.
+ * <p>
+ * A configuration can be <i>bound</i> to a specific bundle or to a region of
+ * bundles using the <em>location</em>. In its simplest form the location is the
+ * location of the target bundle that registered a Managed Service or a Managed
+ * Service Factory. However, if the location starts with {@code ?} then the
+ * location indicates multiple delivery. In such a case the configuration must
+ * be delivered to all targets.
+ *
+ * If security is on, the Configuration Permission can be used to restrict the
+ * targets that receive updates. The Configuration Admin must only update a
+ * target when the configuration location matches the location of the target's
+ * bundle or the target bundle has a Configuration Permission with the action
+ * {@link ConfigurationPermission#TARGET} and a name that matches the
+ * configuration location. The name in the permission may contain wildcards (
+ * {@code '*'}) to match the location using the same substring matching rules as
+ * {@link Filter}.
+ *
+ * Bundles can always create, manipulate, and be updated from configurations
+ * that have a location that matches their bundle location.
+ *
+ * <p>
+ * If a configuration's location is {@code null}, it is not yet bound to a
+ * location. It will become bound to the location of the first bundle that
+ * registers a {@code ManagedService} or {@code ManagedServiceFactory} object
+ * with the corresponding PID.
+ * <p>
+ * The same {@code Configuration} object is used for configuring both a Managed
+ * Service Factory and a Managed Service. When it is important to differentiate
+ * between these two the term "factory configuration" is used.
+ *
+ * @author $Id$
+ * @ThreadSafe
+ */
+@ProviderType
+public interface Configuration {
+	/**
+	 * Get the PID for this {@code Configuration} object.
+	 *
+	 * @return the PID for this {@code Configuration} object.
+	 * @throws IllegalStateException if this configuration has been deleted
+	 */
+	public String getPid();
+
+	/**
+	 * Return the properties of this {@code Configuration} object.
+	 *
+	 * The {@code Dictionary} object returned is a private copy for the caller
+	 * and may be changed without influencing the stored configuration. The keys
+	 * in the returned dictionary are case insensitive and are always of type
+	 * {@code String}.
+	 *
+	 * <p>
+	 * If called just after the configuration is created and before update has
+	 * been called, this method returns {@code null}.
+	 *
+	 * @return A private copy of the properties for the caller or {@code null}.
+	 *         These properties must not contain the "service.bundleLocation"
+	 *         property. The value of this property may be obtained from the
+	 *         {@link #getBundleLocation()} method.
+	 * @throws IllegalStateException If this configuration has been deleted.
+	 */
+	public Dictionary<String, Object> getProperties();
+
+    /**
+     * Return the modified properties of this {@code Configuration} object.
+     *
+     * The {@code Dictionary} object returned is a private copy for the caller
+     * and may be changed without influencing the stored configuration. The keys
+     * in the returned dictionary are case insensitive and are always of type
+     * {@code String}.
+     *
+     * <p>
+     * Before the properties are returned they are run through all
+     * registered {@link ConfigurationPlugin}s handling the configuration
+     * for this PID.
+     *
+     * <p>
+     * If called just after the configuration is created and before update has
+     * been called, this method returns {@code null}.
+     *
+     * @return A private copy of the properties for the caller or {@code null}.
+     *         These properties must not contain the "service.bundleLocation"
+     *         property. The value of this property may be obtained from the
+     *         {@link #getBundleLocation()} method.
+     * @throws IllegalStateException If this configuration has been deleted.
+     */
+    public Dictionary<String, Object> getModifiedProperties(ServiceReference<ManagedService> reference);
+
+    /**
+	 * Update the properties of this {@code Configuration} object.
+	 *
+	 * Stores the properties in persistent storage after adding or overwriting
+	 * the following properties:
+	 * <ul>
+	 * <li>"service.pid" : is set to be the PID of this configuration.</li>
+	 * <li>"service.factoryPid" : if this is a factory configuration it is set
+	 * to the factory PID else it is not set.</li>
+	 * </ul>
+	 * These system properties are all of type {@code String}.
+	 *
+	 * <p>
+	 * If the corresponding Managed Service/Managed Service Factory is
+	 * registered, its updated method must be called asynchronously. Else, this
+	 * callback is delayed until aforementioned registration occurs.
+	 *
+	 * <p>
+	 * Also notifies all Configuration Listeners with a
+	 * {@link ConfigurationEvent#CM_UPDATED} event.
+	 *
+	 * @param properties the new set of properties for this configuration
+	 * @throws LockedConfigurationException if the configuration is locked
+	 * @throws IOException if update cannot be made persistent
+	 * @throws IllegalArgumentException if the {@code Dictionary} object
+	 *         contains invalid configuration types or contains case variants of
+	 *         the same key name.
+	 * @throws IllegalStateException If this configuration has been deleted.
+	 */
+	public void update(Dictionary<String, ?> properties) throws IOException;
+
+	/**
+	 * Delete this {@code Configuration} object.
+	 *
+	 * Removes this configuration object from the persistent store. Notify
+	 * asynchronously the corresponding Managed Service or Managed Service
+	 * Factory. A {@link ManagedService} object is notified by a call to its
+	 * {@code updated} method with a {@code null} properties argument. A
+	 * {@link ManagedServiceFactory} object is notified by a call to its
+	 * {@code deleted} method.
+	 *
+	 * <p>
+	 * Also notifies all Configuration Listeners with a
+	 * {@link ConfigurationEvent#CM_DELETED} event.
+	 *
+     * @throws LockedConfigurationException if the configuration is locked
+	 * @throws IOException If delete fails.
+	 * @throws IllegalStateException If this configuration has been deleted.
+	 */
+	public void delete() throws IOException;
+
+	/**
+	 * For a factory configuration return the PID of the corresponding Managed
+	 * Service Factory, else return {@code null}.
+	 *
+	 * @return factory PID or {@code null}
+	 * @throws IllegalStateException If this configuration has been deleted.
+	 */
+	public String getFactoryPid();
+
+	/**
+	 * Update the {@code Configuration} object with the current properties.
+	 *
+	 * Initiate the {@code updated} callback to the Managed Service or Managed
+	 * Service Factory with the current properties asynchronously.
+	 *
+	 * <p>
+	 * This is the only way for a bundle that uses a Configuration Plugin
+	 * service to initiate a callback. For example, when that bundle detects a
+	 * change that requires an update of the Managed Service or Managed Service
+	 * Factory via its {@code ConfigurationPlugin} object.
+	 *
+	 * @see ConfigurationPlugin
+	 * @throws IOException if update cannot access the properties in persistent
+	 *         storage
+	 * @throws IllegalStateException If this configuration has been deleted.
+	 */
+	public void update() throws IOException;
+
+    /**
+     * Update the properties of this {@code Configuration} object if the
+     * provided properties are different than the currently stored set
+     *
+     * If the properties are the same, no operation is performed, otherwise it
+     * stores the properties in persistent storage after adding or overwriting
+     * the following properties:
+     * <ul>
+     * <li>"service.pid" : is set to be the PID of this configuration.</li>
+     * <li>"service.factoryPid" : if this is a factory configuration it is set
+     * to the factory PID else it is not set.</li>
+     * </ul>
+     * These system properties are all of type {@code String}.
+     *
+     * <p>
+     * If the corresponding Managed Service/Managed Service Factory is
+     * registered, its updated method must be called asynchronously. Else, this
+     * callback is delayed until aforementioned registration occurs.
+     *
+     * <p>
+     * Also notifies all Configuration Listeners with a
+     * {@link ConfigurationEvent#CM_UPDATED} event.
+     *
+     * @param properties the new set of properties for this configuration
+     * @return Returns {@code true} if the configuration was updated.
+     *
+     * @throws LockedConfigurationException If the configuration is locked
+     * @throws IOException if update cannot be made persistent
+     * @throws IllegalArgumentException if the {@code Dictionary} object
+     *         contains invalid configuration types or contains case variants of
+     *         the same key name.
+     * @throws IllegalStateException If this configuration has been deleted.
+     * @since 1.6
+     */
+    public boolean setProperties(Dictionary<String, ?> properties) throws IOException;
+
+    /**
+	 * Bind this {@code Configuration} object to the specified location.
+	 *
+	 * If the location parameter is {@code null} then the {@code Configuration}
+	 * object will not be bound to a location/region. It will be set to the
+	 * bundle's location before the first time a Managed Service/Managed Service
+	 * Factory receives this {@code Configuration} object via the updated method
+	 * and before any plugins are called. The bundle location or region will be
+	 * set persistently.
+	 *
+	 * <p>
+	 * If the location starts with {@code ?} then all targets registered with
+	 * the given PID must be updated.
+	 *
+	 * <p>
+	 * If the location is changed then existing targets must be informed. If
+	 * they can no longer see this configuration, the configuration must be
+	 * deleted or updated with {@code null}. If this configuration becomes
+	 * visible then they must be updated with this configuration.
+	 *
+	 * <p>
+	 * Also notifies all Configuration Listeners with a
+	 * {@link ConfigurationEvent#CM_LOCATION_CHANGED} event.
+	 *
+	 * @param location a location, region, or {@code null}
+	 * @throws IllegalStateException If this configuration has been deleted.
+	 * @throws SecurityException when the required permissions are not available
+	 * @throws SecurityException when the required permissions are not available
+	 * @security ConfigurationPermission[this.location,CONFIGURE] if
+	 *           this.location is not {@code null}
+	 * @security ConfigurationPermission[location,CONFIGURE] if location is not
+	 *           {@code null}
+	 * @security ConfigurationPermission["*",CONFIGURE] if this.location is
+	 *           {@code null} or if location is {@code null}
+	 */
+	public void setBundleLocation(String location);
+
+	/**
+	 * Get the bundle location.
+	 *
+	 * Returns the bundle location or region to which this configuration is
+	 * bound, or {@code null} if it is not yet bound to a bundle location or
+	 * region. If the location starts with {@code ?} then the configuration is
+	 * delivered to all targets and not restricted to a single bundle.
+	 *
+	 * @return location to which this configuration is bound, or {@code null}.
+	 * @throws IllegalStateException If this configuration has been deleted.
+	 * @throws SecurityException when the required permissions are not available
+	 * @security ConfigurationPermission[this.location,CONFIGURE] if
+	 *           this.location is not {@code null}
+	 * @security ConfigurationPermission["*",CONFIGURE] if this.location is
+	 *           {@code null}
+	 *
+	 */
+	public String getBundleLocation();
+
+	/**
+	 * Get the change count.
+	 *
+	 * Each Configuration must maintain a change counter that is incremented
+	 * with a positive value every time the configuration is updated and its
+	 * properties are stored. The counter must be incremented before the targets
+	 * are updated and events are sent out.
+	 *
+	 * @return A monotonically increasing value reflecting changes in this
+	 *         Configuration.
+	 * @throws IllegalStateException If this configuration has been deleted.
+	 * @since 1.5
+	 */
+	public long getChangeCount();
+
+    /**
+     * Locks or unlocks the configuration.
+     * @param flag If {@code true} the configuration is locked,
+     *             if {@code false} the configuration is unlocked.
+     * @throws IOException If the new lock state cannot be persisted.
+     * @throws IllegalStateException If this configuration has been deleted.
+     * @since 1.6
+     */
+    public void setLocked(boolean flag) throws IOException;
+
+    /**
+     * Check if the configuration is currently locked.
+     * @return {@code true} if the configuration is locked, {
+     *         {@code false} otherwise.
+     * @throws IllegalStateException If this configuration has been deleted.
+     * @since 1.6
+     */
+    public boolean isLocked();
+
+    /**
+	 * Equality is defined to have equal PIDs
+	 *
+	 * Two Configuration objects are equal when their PIDs are equal.
+	 *
+	 * @param other {@code Configuration} object to compare against
+	 * @return {@code true} if equal, {@code false} if not a
+	 *         {@code Configuration} object or one with a different PID.
+	 */
+	@Override
+	public boolean equals(Object other);
+
+	/**
+	 * Hash code is based on PID.
+	 *
+	 * The hash code for two Configuration objects must be the same when the
+	 * Configuration PID's are the same.
+	 *
+	 * @return hash code for this Configuration object
+	 */
+	@Override
+	public int hashCode();
+}

Propchange: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/Configuration.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/Configuration.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java?rev=1760997&view=auto
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java (added)
+++ felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java Fri Sep 16 06:11:25 2016
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) OSGi Alliance (2001, 2016). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import java.io.IOException;
+import java.util.Dictionary;
+
+import org.osgi.annotation.versioning.ProviderType;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * Service for administering configuration data.
+ *
+ * <p>
+ * The main purpose of this interface is to store bundle configuration data
+ * persistently. This information is represented in {@code Configuration}
+ * objects. The actual configuration data is a {@code Dictionary} of properties
+ * inside a {@code Configuration} object.
+ *
+ * <p>
+ * There are two principally different ways to manage configurations. First
+ * there is the concept of a Managed Service, where configuration data is
+ * uniquely associated with an object registered with the service registry.
+ *
+ * <p>
+ * Next, there is the concept of a factory where the Configuration Admin service
+ * will maintain 0 or more {@code Configuration} objects for a Managed Service
+ * Factory that is registered with the Framework.
+ *
+ * <p>
+ * The first concept is intended for configuration data about "things/services"
+ * whose existence is defined externally, e.g. a specific printer. Factories are
+ * intended for "things/services" that can be created any number of times, e.g.
+ * a configuration for a DHCP server for different networks.
+ *
+ * <p>
+ * Bundles that require configuration should register a Managed Service or a
+ * Managed Service Factory in the service registry. A registration property
+ * named {@code service.pid} (persistent identifier or PID) must be used to
+ * identify this Managed Service or Managed Service Factory to the Configuration
+ * Admin service.
+ *
+ * <p>
+ * When the ConfigurationAdmin detects the registration of a Managed Service, it
+ * checks its persistent storage for a configuration object whose
+ * {@code service.pid} property matches the PID service property (
+ * {@code service.pid}) of the Managed Service. If found, it calls
+ * {@link ManagedService#updated(Dictionary)} method with the new properties.
+ * The implementation of a Configuration Admin service must run these call-backs
+ * asynchronously to allow proper synchronization.
+ *
+ * <p>
+ * When the Configuration Admin service detects a Managed Service Factory
+ * registration, it checks its storage for configuration objects whose
+ * {@code service.factoryPid} property matches the PID service property of the
+ * Managed Service Factory. For each such {@code Configuration} objects, it
+ * calls the {@code ManagedServiceFactory.updated} method asynchronously with
+ * the new properties. The calls to the {@code updated} method of a
+ * {@code ManagedServiceFactory} must be executed sequentially and not overlap
+ * in time.
+ *
+ * <p>
+ * In general, bundles having permission to use the Configuration Admin service
+ * can only access and modify their own configuration information. Accessing or
+ * modifying the configuration of other bundles requires
+ * {@code ConfigurationPermission[location,CONFIGURE]}, where location is the
+ * configuration location.
+ *
+ * <p>
+ * {@code Configuration} objects can be <i>bound</i> to a specified bundle
+ * location or to a region (configuration location starts with {@code ?}). If a
+ * location is not set, it will be learned the first time a target is
+ * registered. If the location is learned this way, the Configuration Admin
+ * service must detect if the bundle corresponding to the location is
+ * uninstalled. If this occurs, the {@code Configuration} object must be
+ * unbound, that is its location field is set back to {@code null}.
+ *
+ * <p>
+ * If target's bundle location matches the configuration location it is always
+ * updated.
+ *
+ * <p>
+ * If the configuration location starts with {@code ?}, that is, the location is
+ * a region, then the configuration must be delivered to all targets registered
+ * with the given PID. If security is on, the target bundle must have
+ * Configuration Permission[location,TARGET], where location matches given the
+ * configuration location with wildcards as in the Filter substring match. The
+ * security must be verified using the
+ * {@link org.osgi.framework.Bundle#hasPermission(Object)} method on the target
+ * bundle.
+ *
+ * <p>
+ * If a target cannot be updated because the location does not match or it has
+ * no permission and security is active then the Configuration Admin service
+ * must not do the normal callback.
+ *
+ * <p>
+ * The method descriptions of this class refer to a concept of "the calling
+ * bundle". This is a loose way of referring to the bundle which obtained the
+ * Configuration Admin service from the service registry. Implementations of
+ * {@code ConfigurationAdmin} must use a
+ * {@link org.osgi.framework.ServiceFactory} to support this concept.
+ *
+ * @author $Id$
+ * @ThreadSafe
+ */
+@ProviderType
+public interface ConfigurationAdmin {
+	/**
+	 * Configuration property naming the Factory PID in the configuration
+	 * dictionary. The property's value is of type {@code String}.
+	 *
+	 * @since 1.1
+	 */
+	public final static String	SERVICE_FACTORYPID		= "service.factoryPid";
+	/**
+	 * Configuration property naming the location of the bundle that is
+	 * associated with a {@code Configuration} object. This property can be
+	 * searched for but must not appear in the configuration dictionary for
+	 * security reason. The property's value is of type {@code String}.
+	 *
+	 * @since 1.1
+	 */
+	public final static String	SERVICE_BUNDLELOCATION	= "service.bundleLocation";
+
+	/**
+	 * Create a new factory {@code Configuration} object with a new PID.
+	 *
+	 * The properties of the new {@code Configuration} object are {@code null}
+	 * until the first time that its {@link Configuration#update(Dictionary)}
+	 * method is called.
+	 *
+	 * <p>
+	 * It is not required that the {@code factoryPid} maps to a registered
+	 * Managed Service Factory.
+	 *
+	 * <p>
+	 * The {@code Configuration} object is bound to the location of the calling
+	 * bundle. It is possible that the same factoryPid has associated
+	 * configurations that are bound to different bundles. Bundles should only
+	 * see the factory configurations that they are bound to or have the proper
+	 * permission.
+	 *
+	 * @param factoryPid PID of factory (not {@code null}).
+	 * @return A new {@code Configuration} object.
+	 * @throws IOException if access to persistent storage fails.
+	 */
+	public Configuration createFactoryConfiguration(String factoryPid) throws IOException;
+
+	/**
+	 * Create a new factory {@code Configuration} object with a new PID.
+	 *
+	 * The properties of the new {@code Configuration} object are {@code null}
+	 * until the first time that its {@link Configuration#update(Dictionary)}
+	 * method is called.
+	 *
+	 * <p>
+	 * It is not required that the {@code factoryPid} maps to a registered
+	 * Managed Service Factory.
+	 *
+	 * <p>
+	 * The {@code Configuration} is bound to the location specified. If this
+	 * location is {@code null} it will be bound to the location of the first
+	 * bundle that registers a Managed Service Factory with a corresponding PID.
+	 * It is possible that the same factoryPid has associated configurations
+	 * that are bound to different bundles. Bundles should only see the factory
+	 * configurations that they are bound to or have the proper permission.
+	 *
+	 * <p>
+	 * If the location starts with {@code ?} then the configuration must be
+	 * delivered to all targets with the corresponding PID.
+	 *
+	 * @param factoryPid PID of factory (not {@code null}).
+	 * @param location A bundle location string, or {@code null}.
+	 * @return a new {@code Configuration} object.
+	 * @throws IOException if access to persistent storage fails.
+	 * @throws SecurityException when the require permissions are not available
+	 * @security ConfigurationPermission[location,CONFIGURE] if location is not
+	 *           {@code null}
+	 * @security ConfigurationPermission["*",CONFIGURE] if location is
+	 *           {@code null}
+	 */
+	public Configuration createFactoryConfiguration(String factoryPid, String location) throws IOException;
+
+	/**
+	 * Get an existing {@code Configuration} object from the persistent store,
+	 * or create a new {@code Configuration} object.
+	 *
+	 * <p>
+	 * If a {@code Configuration} with this PID already exists in Configuration
+	 * Admin service return it. The location parameter is ignored in this case
+	 * though it is still used for a security check.
+	 *
+	 * <p>
+	 * Else, return a new {@code Configuration} object. This new object is bound
+	 * to the location and the properties are set to {@code null}. If the
+	 * location parameter is {@code null}, it will be set when a Managed Service
+	 * with the corresponding PID is registered for the first time. If the
+	 * location starts with {@code ?} then the configuration is bound to all
+	 * targets that are registered with the corresponding PID.
+	 *
+	 * @param pid Persistent identifier.
+	 * @param location The bundle location string, or {@code null}.
+	 * @return An existing or new {@code Configuration} object.
+	 * @throws IOException if access to persistent storage fails.
+	 * @throws SecurityException when the require permissions are not available
+	 * @security ConfigurationPermission[*,CONFIGURE] if location is
+	 *           {@code null} or if the returned configuration {@code c} already
+	 *           exists and c.location is {@code null}
+	 * @security ConfigurationPermission[location,CONFIGURE] if location is not
+	 *           {@code null}
+	 * @security ConfigurationPermission[c.location,CONFIGURE] if the returned
+	 *           configuration {@code c} already exists and c.location is not
+	 *           {@code null}
+	 */
+	public Configuration getConfiguration(String pid, String location) throws IOException;
+
+	/**
+	 * Get an existing or new {@code Configuration} object from the persistent
+	 * store.
+	 *
+	 * If the {@code Configuration} object for this PID does not exist, create a
+	 * new {@code Configuration} object for that PID, where properties are
+	 * {@code null}. Bind its location to the calling bundle's location.
+	 *
+	 * <p>
+	 * Otherwise, if the location of the existing {@code Configuration} object
+	 * is {@code null}, set it to the calling bundle's location.
+	 *
+	 * @param pid persistent identifier.
+	 * @return an existing or new {@code Configuration} matching the PID.
+	 * @throws IOException if access to persistent storage fails.
+	 * @throws SecurityException when the required permission is not available
+	 * @security ConfigurationPermission[c.location,CONFIGURE] If the
+	 *           configuration {@code c} already exists and c.location is not
+	 *           {@code null}
+	 */
+	public Configuration getConfiguration(String pid) throws IOException;
+
+    /**
+     * Get an existing or new {@code Configuration} object from the persistent
+     * store.
+     *
+     * The PID for this {@code Configuration} object is generated from the
+     * provided factory PID and the alias by starting with the factory PID
+     * appending the character # and then appending the alias.
+     *
+     * <p>
+     * If a {@code Configuration} with this PID already exists in Configuration
+     * Admin service return it. The location parameter is ignored in this case
+     * though it is still used for a security check.
+     *
+     * <p>
+     * Else, return a new {@code Configuration} object. This new object is bound
+     * to the location and the properties are set to {@code null}. If the
+     * location parameter is {@code null}, it will be set when a Managed Service
+     * with the corresponding PID is registered for the first time. If the
+     * location starts with {@code ?} then the configuration is bound to all
+     * targets that are registered with the corresponding PID.
+     *
+     * @param factoryPid PID of factory (not {@code null}).
+     * @param alias An alias for {@code Configuration} (not {@code null}).
+     * @param location The bundle location string, or {@code null}.
+     * @return An existing or new {@code Configuration} object.
+     * @throws IOException if access to persistent storage fails.
+     * @throws SecurityException when the require permissions are not available
+     * @security ConfigurationPermission[*,CONFIGURE] if location is
+     *           {@code null} or if the returned configuration {@code c} already
+     *           exists and c.location is {@code null}
+     * @security ConfigurationPermission[location,CONFIGURE] if location is not
+     *           {@code null}
+     * @security ConfigurationPermission[c.location,CONFIGURE] if the returned
+     *           configuration {@code c} already exists and c.location is not
+     *           {@code null}
+     * @since 1.6
+     */
+	public Configuration getFactoryConfiguration(String factoryPid, String alias, String location) throws IOException;
+
+    /**
+     * Get an existing or new {@code Configuration} object from the persistent
+     * store.
+     *
+     * The PID for this {@code Configuration} object is generated from the
+     * provided factory PID and the alias by starting with the factory PID
+     * appending the character # and then appending the alias.
+     *
+     * If the {@code Configuration} object for this PID does not exist, create a
+     * new {@code Configuration} object for that PID, where properties are
+     * {@code null}. Bind its location to the calling bundle's location.
+     *
+     * <p>
+     * Otherwise, if the location of the existing {@code Configuration} object
+     * is {@code null}, set it to the calling bundle's location.
+     *
+     * @param factoryPid PID of factory (not {@code null}).
+     * @param alias An alias for {@code Configuration} (not {@code null}).
+     * @return an existing or new {@code Configuration} matching the PID.
+     * @throws IOException if access to persistent storage fails.
+     * @throws SecurityException when the required permission is not available
+     * @security ConfigurationPermission[c.location,CONFIGURE] If the
+     *           configuration {@code c} already exists and c.location is not
+     *           {@code null}
+     * @since 1.6
+     */
+	public Configuration getFactoryConfiguration(String factoryPid, String alias) throws IOException;
+
+	/**
+	 * List the current {@code Configuration} objects which match the filter.
+	 *
+	 * <p>
+	 * Only {@code Configuration} objects with non- {@code null} properties are
+	 * considered current. That is, {@code Configuration.getProperties()} is
+	 * guaranteed not to return {@code null} for each of the returned
+	 * {@code Configuration} objects.
+	 *
+	 * <p>
+	 * When there is no security on then all configurations can be returned. If
+	 * security is on, the caller must have
+	 * ConfigurationPermission[location,CONFIGURE].
+	 *
+	 * <p>
+	 * The syntax of the filter string is as defined in the {@link Filter}
+	 * class. The filter can test any configuration properties including the
+	 * following:
+	 * <ul>
+	 * <li>{@code service.pid} - the persistent identity</li>
+	 * <li>{@code service.factoryPid} - the factory PID, if applicable</li>
+	 * <li>{@code service.bundleLocation} - the bundle location</li>
+	 * </ul>
+	 * The filter can also be {@code null}, meaning that all
+	 * {@code Configuration} objects should be returned.
+	 *
+	 * @param filter A filter string, or {@code null} to retrieve all
+	 *        {@code Configuration} objects.
+	 * @return All matching {@code Configuration} objects, or {@code null} if
+	 *         there aren't any.
+	 * @throws IOException if access to persistent storage fails
+	 * @throws InvalidSyntaxException if the filter string is invalid
+	 * @security ConfigurationPermission[c.location,CONFIGURE] Only
+	 *           configurations {@code c} are returned for which the caller has
+	 *           this permission
+	 */
+	public Configuration[] listConfigurations(String filter) throws IOException, InvalidSyntaxException;
+}

Propchange: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationAdmin.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationEvent.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationEvent.java?rev=1760997&view=auto
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationEvent.java (added)
+++ felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationEvent.java Fri Sep 16 06:11:25 2016
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2016). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A Configuration Event.
+ *
+ * <p>
+ * {@code ConfigurationEvent} objects are delivered to all registered
+ * {@code ConfigurationListener} service objects. ConfigurationEvents must be
+ * delivered in chronological order with respect to each listener.
+ *
+ * <p>
+ * A type code is used to identify the type of event. The following event types
+ * are defined:
+ * <ul>
+ * <li>{@link #CM_UPDATED}</li>
+ * <li>{@link #CM_DELETED}</li>
+ * <li>{@link #CM_LOCATION_CHANGED}</li>
+ * </ul>
+ * Additional event types may be defined in the future.
+ *
+ * <p>
+ * Security Considerations. {@code ConfigurationEvent} objects do not provide
+ * {@code Configuration} objects, so no sensitive configuration information is
+ * available from the event. If the listener wants to locate the
+ * {@code Configuration} object for the specified pid, it must use
+ * {@code ConfigurationAdmin}.
+ *
+ * @see ConfigurationListener
+ * @Immutable
+ * @author $Id$
+ * @since 1.2
+ */
+public class ConfigurationEvent {
+	/**
+	 * A {@code Configuration} has been updated.
+	 *
+	 * <p>
+	 * This {@code ConfigurationEvent} type that indicates that a
+	 * {@code Configuration} object has been updated with new properties.
+	 *
+	 * An event is fired when a call to {@link Configuration#update(Dictionary)}
+	 * successfully changes a configuration.
+	 */
+	public static final int								CM_UPDATED			= 1;
+	/**
+	 * A {@code Configuration} has been deleted.
+	 *
+	 * <p>
+	 * This {@code ConfigurationEvent} type that indicates that a
+	 * {@code Configuration} object has been deleted.
+	 *
+	 * An event is fired when a call to {@link Configuration#delete()}
+	 * successfully deletes a configuration.
+	 */
+	public static final int								CM_DELETED			= 2;
+
+	/**
+	 * The location of a {@code Configuration} has been changed.
+	 *
+	 * <p>
+	 * This {@code ConfigurationEvent} type that indicates that the location of
+	 * a {@code Configuration} object has been changed.
+	 *
+	 * An event is fired when a call to
+	 * {@link Configuration#setBundleLocation(String)} successfully changes the
+	 * location.
+	 *
+	 * @since 1.4
+	 */
+	public static final int								CM_LOCATION_CHANGED	= 3;
+	/**
+	 * Type of this event.
+	 *
+	 * @see #getType()
+	 */
+	private final int									type;
+	/**
+	 * The factory pid associated with this event.
+	 */
+	private final String								factoryPid;
+	/**
+	 * The pid associated with this event.
+	 */
+	private final String								pid;
+	/**
+	 * The ConfigurationAdmin service which created this event.
+	 */
+	private final ServiceReference<ConfigurationAdmin>	reference;
+
+	/**
+	 * Constructs a {@code ConfigurationEvent} object from the given
+	 * {@code ServiceReference} object, event type, and pids.
+	 *
+	 * @param reference The {@code ServiceReference} object of the Configuration
+	 *        Admin service that created this event.
+	 * @param type The event type. See {@link #getType()}.
+	 * @param factoryPid The factory pid of the associated configuration if the
+	 *        target of the configuration is a ManagedServiceFactory. Otherwise
+	 *        {@code null} if the target of the configuration is a
+	 *        ManagedService.
+	 * @param pid The pid of the associated configuration.
+	 */
+	public ConfigurationEvent(ServiceReference<ConfigurationAdmin> reference, int type, String factoryPid, String pid) {
+		this.reference = reference;
+		this.type = type;
+		this.factoryPid = factoryPid;
+		this.pid = pid;
+		if ((reference == null) || (pid == null)) {
+			throw new NullPointerException("reference and pid must not be null");
+		}
+	}
+
+	/**
+	 * Returns the factory pid of the associated configuration.
+	 *
+	 * @return Returns the factory pid of the associated configuration if the
+	 *         target of the configuration is a ManagedServiceFactory. Otherwise
+	 *         {@code null} if the target of the configuration is a
+	 *         ManagedService.
+	 */
+	public String getFactoryPid() {
+		return factoryPid;
+	}
+
+	/**
+	 * Returns the pid of the associated configuration.
+	 *
+	 * @return Returns the pid of the associated configuration.
+	 */
+	public String getPid() {
+		return pid;
+	}
+
+	/**
+	 * Return the type of this event.
+	 * <p>
+	 * The type values are:
+	 * <ul>
+	 * <li>{@link #CM_UPDATED}</li>
+	 * <li>{@link #CM_DELETED}</li>
+	 * <li>{@link #CM_LOCATION_CHANGED}</li>
+	 * </ul>
+	 *
+	 * @return The type of this event.
+	 */
+	public int getType() {
+		return type;
+	}
+
+	/**
+	 * Return the {@code ServiceReference} object of the Configuration Admin
+	 * service that created this event.
+	 *
+	 * @return The {@code ServiceReference} object for the Configuration Admin
+	 *         service that created this event.
+	 */
+	public ServiceReference<ConfigurationAdmin> getReference() {
+		return reference;
+	}
+}

Propchange: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationEvent.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationEvent.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationException.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationException.java?rev=1760997&view=auto
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationException.java (added)
+++ felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationException.java Fri Sep 16 06:11:25 2016
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) OSGi Alliance (2001, 2016). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+/**
+ * An {@code Exception} class to inform the Configuration Admin service of
+ * problems with configuration data.
+ *
+ * @author $Id$
+ */
+public class ConfigurationException extends Exception {
+	static final long		serialVersionUID	= -1690090413441769377L;
+
+	private final String	property;
+	private final String	reason;
+
+	/**
+	 * Create a {@code ConfigurationException} object.
+	 *
+	 * @param property name of the property that caused the problem,
+	 *        {@code null} if no specific property was the cause
+	 * @param reason reason for failure
+	 */
+	public ConfigurationException(String property, String reason) {
+		super(property + " : " + reason);
+		this.property = property;
+		this.reason = reason;
+	}
+
+	/**
+	 * Create a {@code ConfigurationException} object.
+	 *
+	 * @param property name of the property that caused the problem,
+	 *        {@code null} if no specific property was the cause
+	 * @param reason reason for failure
+	 * @param cause The cause of this exception.
+	 * @since 1.2
+	 */
+	public ConfigurationException(String property, String reason, Throwable cause) {
+		super(property + " : " + reason, cause);
+		this.property = property;
+		this.reason = reason;
+	}
+
+	/**
+	 * Return the property name that caused the failure or null.
+	 *
+	 * @return name of property or null if no specific property caused the
+	 *         problem
+	 */
+	public String getProperty() {
+		return property;
+	}
+
+	/**
+	 * Return the reason for this exception.
+	 *
+	 * @return reason of the failure
+	 */
+	public String getReason() {
+		return reason;
+	}
+
+	/**
+	 * Returns the cause of this exception or {@code null} if no cause was set.
+	 *
+	 * @return The cause of this exception or {@code null} if no cause was set.
+	 * @since 1.2
+	 */
+	@Override
+	public Throwable getCause() {
+		return super.getCause();
+	}
+
+	/**
+	 * Initializes the cause of this exception to the specified value.
+	 *
+	 * @param cause The cause of this exception.
+	 * @return This exception.
+	 * @throws IllegalArgumentException If the specified cause is this
+	 *         exception.
+	 * @throws IllegalStateException If the cause of this exception has already
+	 *         been set.
+	 * @since 1.2
+	 */
+	@Override
+	public Throwable initCause(Throwable cause) {
+		return super.initCause(cause);
+	}
+}

Propchange: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationException.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationListener.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationListener.java?rev=1760997&view=auto
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationListener.java (added)
+++ felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationListener.java Fri Sep 16 06:11:25 2016
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2016). All Rights Reserved.
+ *
+ * Licensed 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.osgi.service.cm;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Listener for Configuration Events. When a {@code ConfigurationEvent} is
+ * fired, it is asynchronously delivered to all {@code ConfigurationListener}s.
+ *
+ * <p>
+ * {@code ConfigurationListener} objects are registered with the Framework
+ * service registry and are notified with a {@code ConfigurationEvent} object
+ * when an event is fired.
+ * <p>
+ * {@code ConfigurationListener} objects can inspect the received
+ * {@code ConfigurationEvent} object to determine its type, the pid of the
+ * {@code Configuration} object with which it is associated, and the
+ * Configuration Admin service that fired the event.
+ *
+ * <p>
+ * Security Considerations. Bundles wishing to monitor configuration events will
+ * require {@code ServicePermission[ConfigurationListener,REGISTER]} to register
+ * a {@code ConfigurationListener} service.
+ *
+ * @author $Id$
+ * @since 1.2
+ * @ThreadSafe
+ */
+@ConsumerType
+public interface ConfigurationListener {
+	/**
+	 * Receives notification of a Configuration that has changed.
+	 *
+	 * @param event The {@code ConfigurationEvent}.
+	 */
+	public void configurationEvent(ConfigurationEvent event);
+}

Propchange: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/configadmin/src/main/java/org/osgi/service/cm/ConfigurationListener.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url