Sketching out component configuration model & API.
Added initial cut of implementation.
Finished implementation; ready for merge.

Change-Id: I385181c0591604a5c44986b97fb881eba7e0528e
diff --git a/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommand.java b/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommand.java
new file mode 100644
index 0000000..910f7b1
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommand.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cli.cfg;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.cfg.ConfigProperty;
+import org.onosproject.cli.AbstractShellCommand;
+
+import java.util.Set;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+/**
+ * Manages application inventory.
+ */
+@Command(scope = "onos", name = "cfg",
+        description = "Manages component configuration")
+public class ComponentConfigCommand extends AbstractShellCommand {
+
+    static final String GET = "get";
+    static final String SET = "set";
+
+    private static final String FMT = "    name=%s, type=%s, value=%s, defaultValue=%s, description=%s";
+
+    @Argument(index = 0, name = "command",
+            description = "Command name (activate|deactivate|uninstall)",
+            required = false, multiValued = false)
+    String command = null;
+
+    @Argument(index = 1, name = "component", description = "Component name",
+            required = false, multiValued = false)
+    String component = null;
+
+    @Argument(index = 2, name = "name", description = "Property name",
+            required = false, multiValued = false)
+    String name = null;
+
+    @Argument(index = 3, name = "value", description = "Property value",
+            required = false, multiValued = false)
+    String value = null;
+
+    ComponentConfigService service;
+
+    @Override
+    protected void execute() {
+        service = get(ComponentConfigService.class);
+        if (isNullOrEmpty(command)) {
+            listComponents();
+        } else if (command.equals(GET) && isNullOrEmpty(component)) {
+            listAllComponentsProperties();
+        } else if (command.equals(GET) && isNullOrEmpty(name)) {
+            listComponentProperties(component);
+        } else if (command.equals(GET)) {
+            listComponentProperty(component, name);
+        } else if (command.equals(SET) && isNullOrEmpty(value)) {
+            service.unsetProperty(component, name);
+        } else if (command.equals(SET)) {
+            service.setProperty(component, name, value);
+        } else {
+            error("Illegal usage");
+        }
+    }
+
+    private void listAllComponentsProperties() {
+        service.getComponentNames().forEach(this::listComponentProperties);
+    }
+
+    private void listComponents() {
+        service.getComponentNames().forEach(n -> print("%s", n));
+    }
+
+    private void listComponentProperties(String component) {
+        Set<ConfigProperty> props = service.getProperties(component);
+        print("%s", component);
+        props.forEach(p -> print(FMT, p.name(), p.type().toString().toLowerCase(),
+                                 p.value(), p.defaultValue(), p.description()));
+    }
+
+    private void listComponentProperty(String component, String name) {
+        // FIXME: implement after getProperty is defined and implemented
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommandCompleter.java b/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommandCompleter.java
new file mode 100644
index 0000000..5506d81
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommandCompleter.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cli.cfg;
+
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+
+import java.util.List;
+import java.util.SortedSet;
+
+import static org.onosproject.cli.cfg.ComponentConfigCommand.GET;
+import static org.onosproject.cli.cfg.ComponentConfigCommand.SET;
+
+/**
+ * Component configuration command completer.
+ */
+public class ComponentConfigCommandCompleter implements Completer {
+    @Override
+    public int complete(String buffer, int cursor, List<String> candidates) {
+        // Delegate string completer
+        StringsCompleter delegate = new StringsCompleter();
+        SortedSet<String> strings = delegate.getStrings();
+        strings.add(GET);
+        strings.add(SET);
+
+        // Now let the completer do the work for figuring out what to offer.
+        return delegate.complete(buffer, cursor, candidates);
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/cfg/ComponentNameCompleter.java b/cli/src/main/java/org/onosproject/cli/cfg/ComponentNameCompleter.java
new file mode 100644
index 0000000..4883b99
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/cfg/ComponentNameCompleter.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cli.cfg;
+
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.cli.AbstractShellCommand;
+
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * Component name completer.
+ */
+public class ComponentNameCompleter implements Completer {
+    @Override
+    public int complete(String buffer, int cursor, List<String> candidates) {
+        // Delegate string completer
+        StringsCompleter delegate = new StringsCompleter();
+
+        // Fetch our service and feed it's offerings to the string completer
+        ComponentConfigService service = AbstractShellCommand.get(ComponentConfigService.class);
+        SortedSet<String> strings = delegate.getStrings();
+        service.getComponentNames().forEach(strings::add);
+
+        // Now let the completer do the work for figuring out what to offer.
+        return delegate.complete(buffer, cursor, candidates);
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/cfg/package-info.java b/cli/src/main/java/org/onosproject/cli/cfg/package-info.java
new file mode 100644
index 0000000..fe44d21
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/cfg/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * CLI commands for managing centralized component configuration.
+ */
+package org.onosproject.cli.cfg;
\ No newline at end of file
diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index adf831e..799e732 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -33,33 +33,16 @@
             </completers>
         </command>
 
-        <!--
         <command>
-            <action class="org.onosproject.cli.app.ApplicationActivateCommand"/>
+            <action class="org.onosproject.cli.cfg.ComponentConfigCommand"/>
             <completers>
-                <ref component-id="appNameCompleter"/>
+                <ref component-id="cfgCommandCompleter"/>
+                <ref component-id="componentNameCompleter"/>
                 <null/>
             </completers>
         </command>
 
         <command>
-            <action class="org.onosproject.cli.app.ApplicationDeactivateCommand"/>
-            <completers>
-                <ref component-id="appNameCompleter"/>
-                <null/>
-            </completers>
-        </command>
-
-        <command>
-            <action class="org.onosproject.cli.app.ApplicationUninstallCommand"/>
-            <completers>
-                <ref component-id="appNameCompleter"/>
-                <null/>
-            </completers>
-        </command>
-        -->
-
-        <command>
             <action class="org.onosproject.cli.MetricsListCommand"/>
         </command>
 
@@ -309,6 +292,8 @@
     <bean id="appCommandCompleter" class="org.onosproject.cli.app.ApplicationCommandCompleter"/>
     <bean id="appNameCompleter" class="org.onosproject.cli.app.ApplicationNameCompleter"/>
     <bean id="appIdNameCompleter" class="org.onosproject.cli.app.ApplicationIdNameCompleter"/>
+    <bean id="cfgCommandCompleter" class="org.onosproject.cli.cfg.ComponentConfigCommandCompleter"/>
+    <bean id="componentNameCompleter" class="org.onosproject.cli.cfg.ComponentNameCompleter"/>
     <bean id="nodeIdCompleter" class="org.onosproject.cli.NodeIdCompleter"/>
     <bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/>
     <bean id="clusterIdCompleter" class="org.onosproject.cli.net.ClusterIdCompleter"/>
diff --git a/core/api/src/main/java/org/onosproject/cfg/ComponentConfigEvent.java b/core/api/src/main/java/org/onosproject/cfg/ComponentConfigEvent.java
new file mode 100644
index 0000000..0f5a2ee
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/cfg/ComponentConfigEvent.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cfg;
+
+import org.onosproject.event.AbstractEvent;
+
+/**
+ * Describes a component configuration event.
+ */
+public class ComponentConfigEvent extends AbstractEvent<ComponentConfigEvent.Type, String> {
+
+    private final String name;
+    private final String value;
+
+    public enum Type {
+        /**
+         * Signifies that a configuration property has set.
+         */
+        PROPERTY_SET,
+
+        /**
+         * Signifies that a configuration property has been unset.
+         */
+        PROPERTY_UNSET
+    }
+
+    /**
+     * Creates an event of a given type and for the specified app and the
+     * current time.
+     *
+     * @param type          config property event type
+     * @param componentName component name event subject
+     * @param name          config property name
+     * @param value         config property value
+     */
+    public ComponentConfigEvent(Type type, String componentName,
+                                String name, String value) {
+        super(type, componentName);
+        this.name = name;
+        this.value = value;
+    }
+
+    /**
+     * Returns the property name.
+     *
+     * @return property name
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Returns the property value as a string.
+     *
+     * @return string value
+     */
+    public String value() {
+        return value;
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java b/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java
new file mode 100644
index 0000000..a311002
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cfg;
+
+import java.util.Set;
+
+/**
+ * Service for tracking system-wide configurations for various software components.
+ */
+public interface ComponentConfigService {
+
+    /**
+     * Returns names of all components that have registered their
+     * configuration properties.
+     *
+     * @return set of component names
+     */
+    Set<String> getComponentNames();
+
+    /**
+     * Registers configuration properties for the specified component.
+     *
+     * @param componentClass class of configurable component
+     */
+    void registerProperties(Class<?> componentClass);
+
+    /**
+     * Unregisters configuration properties for the specified component.
+     *
+     * @param componentClass class of configurable component
+     * @param clear          true indicates any settings should be cleared
+     */
+    void unregisterProperties(Class<?> componentClass, boolean clear);
+
+    /**
+     * Returns configuration properties of the named components.
+     *
+     * @param componentName component name
+     * @return set of configuration properties
+     */
+    Set<ConfigProperty> getProperties(String componentName);
+
+    /**
+     * Sets the value of the specified configuration property.
+     *
+     * @param componentName component name
+     * @param name          property name
+     * @param value         new property value
+     */
+    void setProperty(String componentName, String name, String value);
+
+    /**
+     * Clears the value of the specified configuration property thus making
+     * the property take on its default value.
+     *
+     * @param componentName component name
+     * @param name          property name
+     */
+    void unsetProperty(String componentName, String name);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java b/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java
new file mode 100644
index 0000000..05f58a4
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cfg;
+
+import org.onosproject.store.Store;
+
+/**
+ * Service for storing and distributing system-wide configurations for various
+ * software components.
+ */
+public interface ComponentConfigStore
+        extends Store<ComponentConfigEvent, ComponentConfigStoreDelegate> {
+
+    /**
+     * Sets the value of the specified configuration property.
+     *
+     * @param componentName component name
+     * @param name          property name
+     * @param value         new property value
+     */
+    void setProperty(String componentName, String name, String value);
+
+    /**
+     * Clears the value of the specified configuration property thus making
+     * the property take on its default value.
+     *
+     * @param componentName component name
+     * @param name          property name
+     */
+    void unsetProperty(String componentName, String name);
+
+}
diff --git a/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStoreDelegate.java b/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStoreDelegate.java
new file mode 100644
index 0000000..da26278
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStoreDelegate.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cfg;
+
+import org.onosproject.store.StoreDelegate;
+
+/**
+ * Configuration property store delegate abstraction.
+ */
+public interface ComponentConfigStoreDelegate extends StoreDelegate<ComponentConfigEvent> {
+}
diff --git a/core/api/src/main/java/org/onosproject/cfg/ConfigProperty.java b/core/api/src/main/java/org/onosproject/cfg/ConfigProperty.java
new file mode 100644
index 0000000..36cd22b
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/cfg/ConfigProperty.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cfg;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Component configuration property.
+ */
+public final class ConfigProperty {
+
+    private final String name;
+    private final Type type;
+    private final String value;
+    private final String defaultValue;
+    private final String description;
+    private final boolean isSet;
+
+    /**
+     * Representation of the type of property value.
+     */
+    public enum Type {
+        /**
+         * Indicates the value is a string.
+         */
+        STRING,
+
+        /**
+         * Indicates the value is an integer.
+         */
+        INTEGER,
+
+        /**
+         * Indicates the value is a long.
+         */
+        LONG,
+
+        /**
+         * Indicates the value is a float.
+         */
+        FLOAT,
+
+        /**
+         * Indicates the value is a double.
+         */
+        DOUBLE,
+
+        /**
+         * Indicates the value is a boolean.
+         */
+        BOOLEAN
+    }
+
+    /**
+     * Creates a new configuration property with its default value.
+     *
+     * @param name         property name
+     * @param type         value type
+     * @param defaultValue default value as a string
+     * @param description  property description
+     * @return newly defined property
+     */
+    public static ConfigProperty defineProperty(String name, Type type,
+                                                String defaultValue,
+                                                String description) {
+        return new ConfigProperty(name, type, description, defaultValue, defaultValue, false);
+    }
+
+    /**
+     * Creates a new configuration property as a copy of an existing one, but
+     * with a new value.
+     *
+     * @param property property to be changed
+     * @param newValue new value as a string
+     * @return newly updated property
+     */
+    public static ConfigProperty setProperty(ConfigProperty property, String newValue) {
+        return new ConfigProperty(property.name, property.type, property.description,
+                                  property.defaultValue, newValue, true);
+    }
+
+    /**
+     * Creates a new configuration property as a copy of an existing one, but
+     * without a specific value, thus making it take its default value.
+     *
+     * @param property property to be reset
+     * @return newly reset property
+     */
+    public static ConfigProperty resetProperty(ConfigProperty property) {
+        return new ConfigProperty(property.name, property.type, property.description,
+                                  property.defaultValue, property.defaultValue, false);
+    }
+
+    /**
+     * Creates a new configuration property with its default value.
+     *
+     * @param name         property name
+     * @param type         value type
+     * @param defaultValue default value as a string
+     * @param description  property description
+     * @param value        property value
+     * @param isSet        indicates whether the property is set or not
+     */
+    private ConfigProperty(String name, Type type, String description,
+                           String defaultValue, String value, boolean isSet) {
+        this.name = checkNotNull(name, "Property name cannot be null");
+        this.type = checkNotNull(type, "Property type cannot be null");
+        this.description = checkNotNull(description, "Property description cannot be null");
+        this.defaultValue = defaultValue;
+        this.value = value;
+        this.isSet = isSet;
+    }
+
+    /**
+     * Returns the property name.
+     *
+     * @return property name
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Returns the property type.
+     *
+     * @return property type
+     */
+    public Type type() {
+        return type;
+    }
+
+    /**
+     * Returns the property description.
+     *
+     * @return string value
+     */
+    public String description() {
+        return description;
+    }
+
+    /**
+     * Returns the property default value as a string.
+     *
+     * @return string default value
+     */
+    public String defaultValue() {
+        return defaultValue;
+    }
+
+    /**
+     * Returns the property value as a string.
+     *
+     * @return string value
+     */
+    public String value() {
+        return value;
+    }
+
+    /**
+     * Indicates whether the property is set or whether it assumes its
+     * default value.
+     *
+     * @return true if the property is set
+     */
+    public boolean isSet() {
+        return isSet;
+    }
+
+    /**
+     * Returns the property value as a string.
+     *
+     * @return string value
+     */
+    public String asString() {
+        return value;
+    }
+
+    /**
+     * Returns the property value as an integer.
+     *
+     * @return integer value
+     */
+    public int asInteger() {
+        checkState(type == Type.INTEGER, "Value is not an integer");
+        return Integer.parseInt(value);
+    }
+
+    /**
+     * Returns the property value as a long.
+     *
+     * @return long value
+     */
+    public long asLong() {
+        checkState(type == Type.INTEGER || type == Type.LONG, "Value is not a long or integer");
+        return Long.parseLong(value);
+    }
+
+    /**
+     * Returns the property value as a float.
+     *
+     * @return float value
+     */
+    public float asFloat() {
+        checkState(type == Type.FLOAT, "Value is not a float");
+        return Float.parseFloat(value);
+    }
+
+    /**
+     * Returns the property value as a double.
+     *
+     * @return double value
+     */
+    public double asDouble() {
+        checkState(type == Type.FLOAT || type == Type.DOUBLE, "Value is not a float or double");
+        return Double.parseDouble(value);
+    }
+
+    /**
+     * Returns the property value as a boolean.
+     *
+     * @return string value
+     */
+    public boolean asBoolean() {
+        checkState(type == Type.BOOLEAN, "Value is not a boolean");
+        return Boolean.parseBoolean(value);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Equality is considered only on the basis of property name.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ConfigProperty) {
+            final ConfigProperty other = (ConfigProperty) obj;
+            return Objects.equals(this.name, other.name);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("name", name)
+                .add("type", type)
+                .add("value", value)
+                .add("defaultValue", defaultValue)
+                .add("description", description)
+                .add("isSet", isSet)
+                .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/cfg/package-info.java b/core/api/src/main/java/org/onosproject/cfg/package-info.java
new file mode 100644
index 0000000..99fd5be
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/cfg/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * Set of abstractions for centrally managing component configurations.
+ * Configuration properties are registered for a component resource which is
+ * auto-generated during the build process based on information specified in
+ * the @Property annotations. This provides an overall inventory of all
+ * supported component configurations.
+ */
+package org.onosproject.cfg;
\ No newline at end of file
diff --git a/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java b/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java
new file mode 100644
index 0000000..a1abd18
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cfg;
+
+import java.util.Set;
+
+/**
+ * Adapter for testing against component configuration service.
+ */
+public class ComponentConfigAdapter implements ComponentConfigService {
+    @Override
+    public Set<String> getComponentNames() {
+        return null;
+    }
+
+    @Override
+    public void registerProperties(Class<?> componentClass) {
+
+    }
+
+    @Override
+    public void unregisterProperties(Class<?> componentClass, boolean clear) {
+
+    }
+
+    @Override
+    public Set<ConfigProperty> getProperties(String componentName) {
+        return null;
+    }
+
+    @Override
+    public void setProperty(String componentName, String name, String value) {
+
+    }
+
+    @Override
+    public void unsetProperty(String componentName, String name) {
+
+    }
+}
diff --git a/core/api/src/test/java/org/onosproject/cfg/ConfigPropertyTest.java b/core/api/src/test/java/org/onosproject/cfg/ConfigPropertyTest.java
new file mode 100644
index 0000000..b4ba863
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/cfg/ConfigPropertyTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cfg;
+
+import com.google.common.testing.EqualsTester;
+import org.junit.Test;
+import org.onosproject.cfg.ConfigProperty.Type;
+
+import static org.junit.Assert.*;
+import static org.onosproject.cfg.ConfigProperty.Type.*;
+import static org.onosproject.cfg.ConfigProperty.defineProperty;
+import static org.onosproject.cfg.ConfigProperty.resetProperty;
+import static org.onosproject.cfg.ConfigProperty.setProperty;
+
+/**
+ * Set of tests of the configuration property class.
+ */
+public class ConfigPropertyTest {
+
+    @Test
+    public void basics() {
+        ConfigProperty p = defineProperty("foo", STRING, "bar", "Foo Prop");
+        validate(p, "foo", STRING, "bar", "bar");
+        p = setProperty(p, "BAR");
+        validate(p, "foo", STRING, "BAR", "bar");
+        p = resetProperty(p);
+        validate(p, "foo", STRING, "bar", "bar");
+    }
+
+    @Test
+    public void equality() {
+        new EqualsTester()
+                .addEqualityGroup(defineProperty("foo", STRING, "bar", "Desc"),
+                                  defineProperty("foo", STRING, "goo", "Desc"))
+                .addEqualityGroup(defineProperty("bar", STRING, "bar", "Desc"),
+                                  defineProperty("bar", STRING, "goo", "Desc"))
+                .testEquals();
+    }
+
+    private void validate(ConfigProperty p, String name, Type type, String v, String dv) {
+        assertEquals("incorrect name", name, p.name());
+        assertEquals("incorrect type", type, p.type());
+        assertEquals("incorrect value", v, p.value());
+        assertEquals("incorrect default", dv, p.defaultValue());
+        assertEquals("incorrect description", "Foo Prop", p.description());
+    }
+
+    @Test
+    public void asInteger() {
+        ConfigProperty p = defineProperty("foo", INTEGER, "123", "Foo Prop");
+        validate(p, "foo", INTEGER, "123", "123");
+        assertEquals("incorrect value", 123, p.asInteger());
+        assertEquals("incorrect value", 123L, p.asLong());
+    }
+
+    @Test
+    public void asLong() {
+        ConfigProperty p = defineProperty("foo", LONG, "123", "Foo Prop");
+        validate(p, "foo", LONG, "123", "123");
+        assertEquals("incorrect value", 123L, p.asLong());
+    }
+
+    @Test
+    public void asFloat() {
+        ConfigProperty p = defineProperty("foo", FLOAT, "123.0", "Foo Prop");
+        validate(p, "foo", FLOAT, "123.0", "123.0");
+        assertEquals("incorrect value", 123.0, p.asFloat(), 0.01);
+        assertEquals("incorrect value", 123.0, p.asDouble(), 0.01);
+    }
+
+    @Test
+    public void asDouble() {
+        ConfigProperty p = defineProperty("foo", DOUBLE, "123.0", "Foo Prop");
+        validate(p, "foo", DOUBLE, "123.0", "123.0");
+        assertEquals("incorrect value", 123.0, p.asDouble(), 0.01);
+    }
+
+    @Test
+    public void asBoolean() {
+        ConfigProperty p = defineProperty("foo", BOOLEAN, "true", "Foo Prop");
+        validate(p, "foo", BOOLEAN, "true", "true");
+        assertEquals("incorrect value", true, p.asBoolean());
+    }
+}
\ No newline at end of file
diff --git a/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java b/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java
new file mode 100644
index 0000000..bab7ac1
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cfg.impl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.cfg.ComponentConfigEvent;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.cfg.ComponentConfigStore;
+import org.onosproject.cfg.ComponentConfigStoreDelegate;
+import org.onosproject.cfg.ConfigProperty;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the centralized component configuration service.
+ */
+@Component(immediate = true)
+@Service
+public class ComponentConfigManager implements ComponentConfigService {
+
+    private static final String COMPONENT_NULL = "Component name cannot be null";
+    private static final String PROPERTY_NULL = "Property name cannot be null";
+
+    private static final String RESOURCE_EXT = ".cfgdef";
+
+    private final Logger log = getLogger(getClass());
+
+    private final ComponentConfigStoreDelegate delegate = new InternalStoreDelegate();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigStore store;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ConfigurationAdmin cfgAdmin;
+
+    // Locally maintained catalog of definitions.
+    private final Map<String, Map<String, ConfigProperty>> properties =
+            Maps.newConcurrentMap();
+
+    @Activate
+    public void activate() {
+        store.setDelegate(delegate);
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        store.unsetDelegate(delegate);
+        log.info("Stopped");
+    }
+
+    @Override
+    public Set<String> getComponentNames() {
+        return ImmutableSet.copyOf(properties.keySet());
+    }
+
+    @Override
+    public void registerProperties(Class<?> componentClass) {
+        String componentName = componentClass.getName();
+        String resourceName = componentClass.getSimpleName() + RESOURCE_EXT;
+        try (InputStream ris = componentClass.getResourceAsStream(resourceName)) {
+            checkArgument(ris != null, "Property definitions not found at resource %s",
+                          resourceName);
+
+            // Read the definitions
+            Set<ConfigProperty> defs = ConfigPropertyDefinitions.read(ris);
+
+            // Produce a new map of the properties and register it.
+            Map<String, ConfigProperty> map = Maps.newConcurrentMap();
+            defs.forEach(p -> map.put(p.name(), p));
+
+            properties.put(componentName, map);
+            loadExistingValues(componentName);
+        } catch (IOException e) {
+            log.error("Unable to read property definitions from resource " + resourceName, e);
+        }
+    }
+
+    @Override
+    public void unregisterProperties(Class<?> componentClass, boolean clear) {
+        String componentName = componentClass.getName();
+        checkNotNull(componentName, COMPONENT_NULL);
+        Map<String, ConfigProperty> cps = properties.remove(componentName);
+        if (cps != null) {
+            cps.keySet().forEach(name -> store.unsetProperty(componentName, name));
+        }
+
+        if (clear) {
+            clearExistingValues(componentName);
+        }
+    }
+
+    // Clears any existing values that may have been set.
+    private void clearExistingValues(String componentName) {
+        triggerUpdate(componentName);
+    }
+
+    @Override
+    public Set<ConfigProperty> getProperties(String componentName) {
+        return ImmutableSet.copyOf(properties.get(componentName).values());
+    }
+
+    @Override
+    public void setProperty(String componentName, String name, String value) {
+        checkNotNull(componentName, COMPONENT_NULL);
+        checkNotNull(name, PROPERTY_NULL);
+        store.setProperty(componentName, name, value);
+    }
+
+    @Override
+    public void unsetProperty(String componentName, String name) {
+        checkNotNull(componentName, COMPONENT_NULL);
+        checkNotNull(name, PROPERTY_NULL);
+        store.unsetProperty(componentName, name);
+    }
+
+    private class InternalStoreDelegate implements ComponentConfigStoreDelegate {
+
+        @Override
+        public void notify(ComponentConfigEvent event) {
+            String componentName = event.subject();
+            String name = event.name();
+            String value = event.value();
+
+            switch (event.type()) {
+                case PROPERTY_SET:
+                    set(componentName, name, value);
+                    break;
+                case PROPERTY_UNSET:
+                    reset(componentName, name);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    // Locates the property in the component map and replaces it with an
+    // updated copy.
+    private void set(String componentName, String name, String value) {
+        Map<String, ConfigProperty> map = properties.get(componentName);
+        if (map != null) {
+            ConfigProperty prop = map.get(name);
+            if (prop != null) {
+                map.put(name, ConfigProperty.setProperty(prop, value));
+                triggerUpdate(componentName);
+                return;
+            }
+        }
+        log.warn("Unable to set non-existent property {} for component {}",
+                 name, componentName);
+    }
+
+    // Locates the property in the component map and replaces it with an
+    // reset copy.
+    private void reset(String componentName, String name) {
+        Map<String, ConfigProperty> map = properties.get(componentName);
+        if (map != null) {
+            ConfigProperty prop = map.get(name);
+            if (prop != null) {
+                map.put(name, ConfigProperty.resetProperty(prop));
+                triggerUpdate(componentName);
+                return;
+            }
+        }
+        log.warn("Unable to reset non-existent property {} for component {}",
+                 name, componentName);
+    }
+
+    // Loads existing property values that may have been set.
+    private void loadExistingValues(String componentName) {
+        // FIXME: implement this by talking to the config admin.
+        try {
+            Configuration cfg = cfgAdmin.getConfiguration(componentName);
+            Map<String, ConfigProperty> map = properties.get(componentName);
+            Dictionary<String, Object> props = cfg.getProperties();
+            if (props != null) {
+                Enumeration<String> it = props.keys();
+                while (it.hasMoreElements()) {
+                    String name = it.nextElement();
+                    ConfigProperty p = map.get(name);
+                    if (p != null) {
+                        map.put(name, ConfigProperty.setProperty(p, (String) props.get(name)));
+                    }
+                }
+            }
+        } catch (IOException e) {
+            log.error("Unable to get configuration for " + componentName, e);
+        }
+
+    }
+
+    // FIXME: This should be a slightly deferred execution to allow changing
+    // values just once per component when a number of updates arrive shortly
+    // after each other.
+    private void triggerUpdate(String componentName) {
+        try {
+            Configuration cfg = cfgAdmin.getConfiguration(componentName);
+            Map<String, ConfigProperty> map = properties.get(componentName);
+            Dictionary<String, Object> props = new Hashtable<>();
+            map.values().forEach(p -> props.put(p.name(), p.value()));
+            cfg.update(props);
+        } catch (IOException e) {
+            log.warn("Unable to update configuration for " + componentName, e);
+        }
+    }
+
+}
diff --git a/core/net/src/main/java/org/onosproject/cfg/impl/ConfigPropertyDefinitions.java b/core/net/src/main/java/org/onosproject/cfg/impl/ConfigPropertyDefinitions.java
new file mode 100644
index 0000000..0f416c7
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/cfg/impl/ConfigPropertyDefinitions.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cfg.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.cfg.ConfigProperty;
+import org.onosproject.cfg.ConfigProperty.Type;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Set;
+
+import static org.onosproject.cfg.ConfigProperty.defineProperty;
+
+/**
+ * Utility for writing and reading configuration property definition file.
+ */
+public final class ConfigPropertyDefinitions {
+
+    private static final String FMT = "%s|%s|%s|%s\n";
+    private static final String SEP = "\\|";
+    private static final String COMMENT = "#";
+
+    private ConfigPropertyDefinitions() {
+    }
+
+    /**
+     * Writes the specified set of property definitions into the given output
+     * stream.
+     *
+     * @param stream output stream
+     * @param props  properties whose definitions are to be written
+     * @throws java.io.IOException if unable to write the stream
+     */
+    public static void write(OutputStream stream, Set<ConfigProperty> props) throws IOException {
+        try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(stream))) {
+            props.forEach(p -> pw.format(FMT, p.name(), p.type(), p.description(), p.defaultValue()));
+        }
+    }
+
+    /**
+     * Reads the specified input stream and creates from its contents a
+     * set of property definitions.
+     *
+     * @param stream input stream
+     * @return properties whose definitions are contained in the stream
+     * @throws java.io.IOException if unable to read the stream
+     */
+    public static Set<ConfigProperty> read(InputStream stream) throws IOException {
+        ImmutableSet.Builder<ConfigProperty> builder = ImmutableSet.builder();
+        try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                if (!line.isEmpty() && !line.startsWith(COMMENT)) {
+                    String[] f = line.split(SEP, 4);
+                    builder.add(defineProperty(f[0], Type.valueOf(f[1]), f[2], f[3]));
+                }
+            }
+        }
+        return builder.build();
+    }
+
+}
diff --git a/core/net/src/main/java/org/onosproject/cfg/impl/package-info.java b/core/net/src/main/java/org/onosproject/cfg/impl/package-info.java
new file mode 100644
index 0000000..4f76c31
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/cfg/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * Subsystem for central management of component configurations.
+ */
+package org.onosproject.cfg.impl;
\ No newline at end of file
diff --git a/core/net/src/main/java/org/onosproject/net/topology/impl/DefaultTopologyProvider.java b/core/net/src/main/java/org/onosproject/net/topology/impl/DefaultTopologyProvider.java
index af40595..03a7169 100644
--- a/core/net/src/main/java/org/onosproject/net/topology/impl/DefaultTopologyProvider.java
+++ b/core/net/src/main/java/org/onosproject/net/topology/impl/DefaultTopologyProvider.java
@@ -40,6 +40,7 @@
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.util.AbstractAccumulator;
 import org.onlab.util.Accumulator;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.event.Event;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
@@ -59,13 +60,14 @@
 import com.google.common.collect.ImmutableList;
 
 /**
- * Default implementation of a network topology provider that feeds off device
- * and link subsystem events to trigger assembly and computation of new topology
- * snapshots.
+ * Default implementation of a network topology provider that feeds off
+ * device and link subsystem events to trigger assembly and computation of
+ * new topology snapshots.
  */
 @Component(immediate = true)
 @Service
-public class DefaultTopologyProvider extends AbstractProvider implements TopologyProvider {
+public class DefaultTopologyProvider extends AbstractProvider
+        implements TopologyProvider {
 
     private static final int MAX_THREADS = 8;
     private static final int DEFAULT_MAX_EVENTS = 1000;
@@ -73,8 +75,7 @@
     private static final int DEFAULT_MAX_BATCH_MS = 50;
 
     // FIXME: Replace with a system-wide timer instance;
-    // TODO: Convert to use HashedWheelTimer or produce a variant of that; then
-    // decide which we want to adopt
+    // TODO: Convert to use HashedWheelTimer or produce a variant of that; then decide which we want to adopt
     private static final Timer TIMER = new Timer("onos-topo-event-batching");
 
     @Property(name = "maxEvents", intValue = DEFAULT_MAX_EVENTS,
@@ -100,6 +101,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected LinkService linkService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService cfgService;
+
     private volatile boolean isStarted = false;
 
     private TopologyProviderService providerService;
@@ -118,8 +122,8 @@
 
     @Activate
     public synchronized void activate(ComponentContext context) {
-        executor = newFixedThreadPool(MAX_THREADS,
-                groupedThreads("onos/topo", "build-%d"));
+        cfgService.registerProperties(DefaultTopologyProvider.class);
+        executor = newFixedThreadPool(MAX_THREADS, groupedThreads("onos/topo", "build-%d"));
         accumulator = new TopologyChangeAccumulator();
         logConfig("Configured");
 
@@ -136,6 +140,7 @@
 
     @Deactivate
     public synchronized void deactivate(ComponentContext context) {
+        cfgService.unregisterProperties(DefaultTopologyProvider.class, false);
         isStarted = false;
 
         deviceService.removeListener(deviceListener);
@@ -175,23 +180,21 @@
             newMaxIdleMs = DEFAULT_MAX_IDLE_MS;
         }
 
-        if ((newMaxEvents != maxEvents) || (newMaxBatchMs != maxBatchMs)
-                || (newMaxIdleMs != maxIdleMs)) {
+        if (newMaxEvents != maxEvents || newMaxBatchMs != maxBatchMs || newMaxIdleMs != maxIdleMs) {
             maxEvents = newMaxEvents;
             maxBatchMs = newMaxBatchMs;
             maxIdleMs = newMaxIdleMs;
-            accumulator = maxEvents > 1 ? new TopologyChangeAccumulator()
-            : null;
+            accumulator = maxEvents > 1 ? new TopologyChangeAccumulator() : null;
             logConfig("Reconfigured");
         }
     }
 
     private void logConfig(String prefix) {
-        log.info(
-                "{} with maxEvents = {}; maxBatchMs = {}; maxIdleMs = {}; accumulator={}",
-                prefix, maxEvents, maxBatchMs, maxIdleMs, accumulator != null);
+        log.info("{} with maxEvents = {}; maxBatchMs = {}; maxIdleMs = {}; accumulator={}",
+                 prefix, maxEvents, maxBatchMs, maxIdleMs, accumulator != null);
     }
 
+
     @Override
     public void triggerRecompute() {
         triggerTopologyBuild(Collections.<Event>emptyList());
@@ -201,8 +204,7 @@
      * Triggers assembly of topology data citing the specified events as the
      * reason.
      *
-     * @param reasons
-     *            events which triggered the topology change
+     * @param reasons events which triggered the topology change
      */
     private synchronized void triggerTopologyBuild(List<Event> reasons) {
         if (executor != null) {
@@ -216,9 +218,9 @@
         if (isStarted) {
             GraphDescription desc =
                     new DefaultGraphDescription(System.nanoTime(),
-                            System.currentTimeMillis(),
-                            deviceService.getAvailableDevices(),
-                            linkService.getActiveLinks());
+                                                System.currentTimeMillis(),
+                                                deviceService.getAvailableDevices(),
+                                                linkService.getActiveLinks());
             providerService.topologyChanged(desc, reasons);
         }
     }
@@ -236,8 +238,8 @@
         @Override
         public void event(DeviceEvent event) {
             DeviceEvent.Type type = event.type();
-            if ((type == DEVICE_ADDED) || (type == DEVICE_REMOVED) ||
-                    (type == DEVICE_AVAILABILITY_CHANGED)) {
+            if (type == DEVICE_ADDED || type == DEVICE_REMOVED ||
+                    type == DEVICE_AVAILABILITY_CHANGED) {
                 processEvent(event);
             }
         }
@@ -276,8 +278,7 @@
             try {
                 buildTopology(reasons);
             } catch (Exception e) {
-                log.warn("Unable to compute topology due to: {}",
-                        e.getMessage());
+                log.warn("Unable to compute topology due to: {}", e.getMessage());
                 log.debug("Unable to compute topology", e);
             }
         }
diff --git a/core/net/src/main/resources/org/onosproject/net/topology/impl/DefaultTopologyProvider.cfgdef b/core/net/src/main/resources/org/onosproject/net/topology/impl/DefaultTopologyProvider.cfgdef
new file mode 100644
index 0000000..f7819dd
--- /dev/null
+++ b/core/net/src/main/resources/org/onosproject/net/topology/impl/DefaultTopologyProvider.cfgdef
@@ -0,0 +1,20 @@
+#
+# Copyright 2015 Open Networking Laboratory                                
+#                                                                          
+# 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.
+#
+
+# This is for temporary provision for testing purposes and will be auto-generated.
+maxEvents|INTEGER|1000|Maximum number of events to accumulate
+maxIdleMs|INTEGER|10|Maximum number of millis between events
+maxBatchMs|INTEGER|50|Maximum number of millis for whole batch
diff --git a/core/net/src/test/java/org/onosproject/cfg/impl/ConfigPropertyDefinitionsTest.java b/core/net/src/test/java/org/onosproject/cfg/impl/ConfigPropertyDefinitionsTest.java
new file mode 100644
index 0000000..66e9c7b
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/cfg/impl/ConfigPropertyDefinitionsTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.cfg.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.Test;
+import org.onosproject.cfg.ConfigProperty;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+import static org.onosproject.cfg.ConfigProperty.Type.STRING;
+import static org.onosproject.cfg.ConfigProperty.defineProperty;
+import static org.onosproject.cfg.impl.ConfigPropertyDefinitions.read;
+import static org.onosproject.cfg.impl.ConfigPropertyDefinitions.write;
+
+/**
+ * Tests of the config property definitions utility.
+ */
+public class ConfigPropertyDefinitionsTest {
+
+    @Test
+    public void basics() throws IOException {
+        Set<ConfigProperty> original = ImmutableSet
+                .of(defineProperty("foo", STRING, "dingo", "FOO"),
+                    defineProperty("bar", STRING, "bat", "BAR"));
+        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+        write(out, original);
+        Set<ConfigProperty> read = read(new ByteArrayInputStream(out.toByteArray()));
+        assertEquals("incorrect defs", original, read);
+    }
+
+}
\ No newline at end of file
diff --git a/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java b/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java
index 290ee55..4e2de2b 100644
--- a/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java
+++ b/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java
@@ -20,6 +20,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
 import org.onosproject.event.Event;
 import org.onosproject.event.impl.TestEventDispatcher;
 import org.onosproject.net.Device;
@@ -67,6 +68,7 @@
         provider.deviceService = deviceService;
         provider.linkService = linkService;
         provider.providerRegistry = topologyService;
+        provider.cfgService = new ComponentConfigAdapter();
         provider.activate(null);
     }
 
@@ -76,6 +78,7 @@
         provider.providerRegistry = null;
         provider.deviceService = null;
         provider.linkService = null;
+        provider.cfgService = null;
     }
 
     private void validateSubmission() {
diff --git a/core/store/dist/src/main/java/org/onosproject/store/cfg/GossipComponentConfigStore.java b/core/store/dist/src/main/java/org/onosproject/store/cfg/GossipComponentConfigStore.java
new file mode 100644
index 0000000..b70a291
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onosproject/store/cfg/GossipComponentConfigStore.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.store.cfg;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.cfg.ComponentConfigEvent;
+import org.onosproject.cfg.ComponentConfigStore;
+import org.onosproject.cfg.ComponentConfigStoreDelegate;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.store.AbstractStore;
+import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
+import org.onosproject.store.ecmap.EventuallyConsistentMap;
+import org.onosproject.store.ecmap.EventuallyConsistentMapEvent;
+import org.onosproject.store.ecmap.EventuallyConsistentMapImpl;
+import org.onosproject.store.ecmap.EventuallyConsistentMapListener;
+import org.onosproject.store.impl.WallclockClockManager;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.slf4j.Logger;
+
+import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_SET;
+import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_UNSET;
+import static org.onosproject.store.ecmap.EventuallyConsistentMapEvent.Type.PUT;
+import static org.onosproject.store.ecmap.EventuallyConsistentMapEvent.Type.REMOVE;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Manages inventory of component configurations in a distributed data store
+ * that uses optimistic replication and gossip based anti-entropy techniques.
+ */
+@Component(immediate = true)
+@Service
+public class GossipComponentConfigStore
+        extends AbstractStore<ComponentConfigEvent, ComponentConfigStoreDelegate>
+        implements ComponentConfigStore {
+
+    private static final String SEP = "#";
+
+    private final Logger log = getLogger(getClass());
+
+    private EventuallyConsistentMap<String, String> properties;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ClusterCommunicationService clusterCommunicator;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ClusterService clusterService;
+
+    @Activate
+    public void activate() {
+        KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
+                .register(KryoNamespaces.API);
+
+        properties = new EventuallyConsistentMapImpl<>("cfg", clusterService,
+                                                       clusterCommunicator,
+                                                       serializer,
+                                                       new WallclockClockManager<>());
+        properties.addListener(new InternalPropertiesListener());
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    @Override
+    public void setProperty(String componentName, String name, String value) {
+        properties.put(key(componentName, name), value);
+
+    }
+
+    @Override
+    public void unsetProperty(String componentName, String name) {
+        properties.remove(key(componentName, name));
+    }
+
+    /**
+     * Listener to component configuration properties distributed map changes.
+     */
+    private final class InternalPropertiesListener
+            implements EventuallyConsistentMapListener<String, String> {
+
+        @Override
+        public void event(EventuallyConsistentMapEvent<String, String> event) {
+            String[] keys = event.key().split(SEP);
+            String value = event.value();
+            if (event.type() == PUT) {
+                delegate.notify(new ComponentConfigEvent(PROPERTY_SET, keys[0], keys[1], value));
+            } else if (event.type() == REMOVE) {
+                delegate.notify(new ComponentConfigEvent(PROPERTY_UNSET, keys[0], keys[1], null));
+            }
+        }
+    }
+
+    // Generates a key from component name and property name.
+    private String key(String componentName, String name) {
+        return componentName + SEP + name;
+    }
+
+}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/cfg/package-info.java b/core/store/dist/src/main/java/org/onosproject/store/cfg/package-info.java
new file mode 100644
index 0000000..f8f8509
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onosproject/store/cfg/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * Implementation of distributed component configuration store.
+ */
+package org.onosproject.store.cfg;
diff --git a/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleComponentConfigStore.java b/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleComponentConfigStore.java
new file mode 100644
index 0000000..ba9d29b
--- /dev/null
+++ b/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleComponentConfigStore.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.onosproject.store.trivial.impl;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.cfg.ComponentConfigEvent;
+import org.onosproject.cfg.ComponentConfigStore;
+import org.onosproject.cfg.ComponentConfigStoreDelegate;
+import org.onosproject.store.AbstractStore;
+import org.slf4j.Logger;
+
+import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_SET;
+import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_UNSET;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Manages inventory of component configuration properties.
+ */
+@Component(immediate = true)
+@Service
+public class SimpleComponentConfigStore
+        extends AbstractStore<ComponentConfigEvent, ComponentConfigStoreDelegate>
+        implements ComponentConfigStore {
+
+    private final Logger log = getLogger(getClass());
+
+    @Activate
+    public void activate() {
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    @Override
+    public void setProperty(String componentName, String name, String value) {
+        delegate.notify(new ComponentConfigEvent(PROPERTY_SET, componentName, name, value));
+    }
+
+    @Override
+    public void unsetProperty(String componentName, String name) {
+        delegate.notify(new ComponentConfigEvent(PROPERTY_UNSET, componentName, name, null));
+    }
+}
diff --git a/docs/pom.xml b/docs/pom.xml
index 5b34499..6da4036 100644
--- a/docs/pom.xml
+++ b/docs/pom.xml
@@ -61,7 +61,7 @@
                         <group>
                             <title>Core Subsystems</title>
                             <packages>
-                                org.onosproject.impl:org.onosproject.core.impl:org.onosproject.cluster.impl:org.onosproject.net.device.impl:org.onosproject.net.link.impl:org.onosproject.net.host.impl:org.onosproject.net.topology.impl:org.onosproject.net.packet.impl:org.onosproject.net.flow.impl:org.onosproject.net.*.impl:org.onosproject.event.impl:org.onosproject.net.intent.impl*:org.onosproject.net.proxyarp.impl:org.onosproject.mastership.impl:org.onosproject.net.resource.impl:org.onosproject.json:org.onosproject.json.*:org.onosproject.provider.host.impl:org.onosproject.provider.lldp.impl:org.onosproject.net.statistic.impl:org.onosproject.app.impl:org.onosproject.common.*:org.onosproject.net.group.impl
+                                org.onosproject.impl:org.onosproject.core.impl:org.onosproject.cluster.impl:org.onosproject.net.device.impl:org.onosproject.net.link.impl:org.onosproject.net.host.impl:org.onosproject.net.topology.impl:org.onosproject.net.packet.impl:org.onosproject.net.flow.impl:org.onosproject.net.*.impl:org.onosproject.event.impl:org.onosproject.net.intent.impl*:org.onosproject.net.proxyarp.impl:org.onosproject.mastership.impl:org.onosproject.net.resource.impl:org.onosproject.json:org.onosproject.json.*:org.onosproject.provider.host.impl:org.onosproject.provider.lldp.impl:org.onosproject.net.statistic.impl:org.onosproject.app.impl:org.onosproject.common.*:org.onosproject.net.group.impl:org.onosproject.cfg.impl
                             </packages>
                         </group>
                         <group>