SLING-7468 - Allow to configure the Distribution Resource Provider
diff --git a/src/main/java/org/apache/sling/distribution/component/impl/DefaultDistributionConfigurationManager.java b/src/main/java/org/apache/sling/distribution/component/impl/DefaultDistributionConfigurationManager.java
index 5d50910..a14bb8b 100644
--- a/src/main/java/org/apache/sling/distribution/component/impl/DefaultDistributionConfigurationManager.java
+++ b/src/main/java/org/apache/sling/distribution/component/impl/DefaultDistributionConfigurationManager.java
@@ -63,6 +63,9 @@
     @Reference
     ConfigurationAdmin configurationAdmin;
 
+    @Reference
+    private DistributionComponentFactoryMap componentFactoryMap;
+
     private DistributionConfigurationManager osgiManager;
     private DistributionConfigurationManager resourceManager;
 
@@ -86,7 +89,7 @@
             resourceManager = new ResourceConfigurationManager(configRoot, configProperties, configDefaults);
         }
 
-        osgiManager = new OsgiConfigurationManager(configurationAdmin);
+        osgiManager = new OsgiConfigurationManager(configurationAdmin, componentFactoryMap);
     }
 
     @Deactivate
diff --git a/src/main/java/org/apache/sling/distribution/component/impl/DistributionComponentFactoryMap.java b/src/main/java/org/apache/sling/distribution/component/impl/DistributionComponentFactoryMap.java
new file mode 100644
index 0000000..e2b029f
--- /dev/null
+++ b/src/main/java/org/apache/sling/distribution/component/impl/DistributionComponentFactoryMap.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.distribution.component.impl;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.distribution.agent.impl.ForwardDistributionAgentFactory;
+import org.apache.sling.distribution.agent.impl.PrivilegeDistributionRequestAuthorizationStrategy;
+import org.apache.sling.distribution.agent.impl.QueueDistributionAgentFactory;
+import org.apache.sling.distribution.agent.impl.ReverseDistributionAgentFactory;
+import org.apache.sling.distribution.agent.impl.SimpleDistributionAgentFactory;
+import org.apache.sling.distribution.agent.impl.SyncDistributionAgentFactory;
+import org.apache.sling.distribution.packaging.impl.exporter.AgentDistributionPackageExporterFactory;
+import org.apache.sling.distribution.packaging.impl.exporter.LocalDistributionPackageExporterFactory;
+import org.apache.sling.distribution.packaging.impl.exporter.RemoteDistributionPackageExporterFactory;
+import org.apache.sling.distribution.packaging.impl.importer.LocalDistributionPackageImporterFactory;
+import org.apache.sling.distribution.packaging.impl.importer.RemoteDistributionPackageImporterFactory;
+import org.apache.sling.distribution.serialization.impl.vlt.VaultDistributionPackageBuilderFactory;
+import org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider;
+import org.apache.sling.distribution.trigger.impl.DistributionEventDistributeDistributionTriggerFactory;
+import org.apache.sling.distribution.trigger.impl.JcrEventDistributionTriggerFactory;
+import org.apache.sling.distribution.trigger.impl.PersistedJcrEventDistributionTriggerFactory;
+import org.apache.sling.distribution.trigger.impl.ResourceEventDistributionTriggerFactory;
+import org.apache.sling.distribution.trigger.impl.ScheduledDistributionTriggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static java.lang.String.format;
+import static org.apache.sling.commons.osgi.PropertiesUtil.*;
+import static org.apache.sling.distribution.component.impl.DistributionComponentKind.*;
+
+@Service(value = DistributionComponentFactoryMap.class)
+@Component(metatype = false)
+public class DistributionComponentFactoryMap {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private static final String[] MAPPING_AGENT_DEFAULT = {
+            format("simple:%s", SimpleDistributionAgentFactory.class.getName()),
+            format("sync:%s", SyncDistributionAgentFactory.class.getName()),
+            format("forward:%s", ForwardDistributionAgentFactory.class.getName()),
+            format("reverse:%s", ReverseDistributionAgentFactory.class.getName()),
+            format("queue:%s", QueueDistributionAgentFactory.class.getName()) };
+
+    private static final String[] MAPPING_IMPORTER_DEFAULT = {
+            format("local:%s", LocalDistributionPackageImporterFactory.class.getName()),
+            format("remote:%s", RemoteDistributionPackageImporterFactory.class.getName()) };
+
+    private static final String[] MAPPING_EXPORTER_DEFAULT = {
+            format("local:%s", LocalDistributionPackageExporterFactory.class.getName()),
+            format("remote:%s", RemoteDistributionPackageExporterFactory.class.getName()),
+            format("agent:%s", AgentDistributionPackageExporterFactory.class.getName()) };
+
+    private static final String[] MAPPING_QUEUE_PROVIDER_DEFAULT = {
+            format("simple:%s", SimpleDistributionAgentFactory.class.getName()),
+            format("sync:%s", SyncDistributionAgentFactory.class.getName()),
+            format("forward:%s", ForwardDistributionAgentFactory.class.getName()),
+            format("reverse:%s", ReverseDistributionAgentFactory.class.getName()),
+            format("queue:%s", QueueDistributionAgentFactory.class.getName()) };
+
+    private static final String[] MAPPING_QUEUE_STRATEGY_DEFAULT = {
+            format("simple:%s", SimpleDistributionAgentFactory.class.getName()),
+            format("sync:%s", SyncDistributionAgentFactory.class.getName()),
+            format("forward:%s", ForwardDistributionAgentFactory.class.getName()),
+            format("reverse:%s", ReverseDistributionAgentFactory.class.getName()),
+            format("queue:%s", QueueDistributionAgentFactory.class.getName()) };
+
+    private static final String[] MAPPING_TRANSPORT_SECRET_PROVIDER_DEFAULT = {
+            format("user:%s", UserCredentialsDistributionTransportSecretProvider.class.getName()) };
+
+    private static final String[] MAPPING_PACKAGE_BUILDER_DEFAULT = {
+            format("filevlt:%s", VaultDistributionPackageBuilderFactory.class.getName()),
+            format("jcrvlt:%s", VaultDistributionPackageBuilderFactory.class.getName()) };
+
+    private static final String[] MAPPING_REQUEST_AUTHORIZATION_DEFAULT = {
+            format("privilege:%s", PrivilegeDistributionRequestAuthorizationStrategy.class.getName()) };
+
+    private static final String[] MAPPING_TRIGGER_DEFAULT = {
+            format("resourceEvent:%s", ResourceEventDistributionTriggerFactory.class.getName()),
+            format("scheduledEvent:%s", ScheduledDistributionTriggerFactory.class.getName()),
+            format("distributionEvent:%s", DistributionEventDistributeDistributionTriggerFactory.class.getName()),
+            format("persistedJcrEvent:%s", PersistedJcrEventDistributionTriggerFactory.class.getName()),
+            format("jcrEvent:%s", JcrEventDistributionTriggerFactory.class.getName()) };
+
+
+    @Property(unbounded = PropertyUnbounded.ARRAY)
+    private static final String MAPPING_AGENT = "mapping.agent";
+
+    @Property(unbounded = PropertyUnbounded.ARRAY)
+    private static final String MAPPING_IMPORTER = "mapping.importer";
+
+    @Property(unbounded = PropertyUnbounded.ARRAY)
+    private static final String MAPPING_EXPORTER = "mapping.exporter";
+
+    @Property(unbounded = PropertyUnbounded.ARRAY)
+    private static final String MAPPING_QUEUE_PROVIDER = "mapping.queueProvider";
+
+    @Property(unbounded = PropertyUnbounded.ARRAY)
+    private static final String MAPPING_QUEUE_STRATEGY = "mapping.queueStrategy";
+
+    @Property(unbounded = PropertyUnbounded.ARRAY)
+    private static final String MAPPING_TRANSPORT_SECRET_PROVIDER = "mapping.transportSecretProvider";
+
+    @Property(unbounded = PropertyUnbounded.ARRAY)
+    private static final String MAPPING_PACKAGE_BUILDER = "mapping.packageBuilder";
+
+    @Property(unbounded = PropertyUnbounded.ARRAY)
+    private static final String MAPPING_REQUEST_AUTHORIZATION = "mapping.requestAuthorization";
+
+    @Property(unbounded = PropertyUnbounded.ARRAY)
+    private static final String MAPPING_TRIGGER = "mapping.trigger";
+
+    private final Map<DistributionComponentKind, Map<String, String>> mapping =
+            new HashMap<DistributionComponentKind, Map<String, String>>();
+
+    @Activate
+    protected void activate(Map<String, Object> config) {
+        mapping.put(AGENT, parse(toStringArray(config.get(MAPPING_AGENT)), MAPPING_AGENT_DEFAULT));
+        mapping.put(IMPORTER, parse(toStringArray(config.get(MAPPING_IMPORTER)), MAPPING_IMPORTER_DEFAULT));
+        mapping.put(EXPORTER, parse(toStringArray(config.get(MAPPING_EXPORTER)), MAPPING_EXPORTER_DEFAULT));
+        mapping.put(QUEUE_PROVIDER, parse(toStringArray(config.get(MAPPING_QUEUE_PROVIDER)), MAPPING_QUEUE_PROVIDER_DEFAULT));
+        mapping.put(QUEUE_STRATEGY, parse(toStringArray(config.get(MAPPING_QUEUE_STRATEGY)), MAPPING_QUEUE_STRATEGY_DEFAULT));
+        mapping.put(TRANSPORT_SECRET_PROVIDER, parse(toStringArray(config.get(MAPPING_TRANSPORT_SECRET_PROVIDER)), MAPPING_TRANSPORT_SECRET_PROVIDER_DEFAULT));
+        mapping.put(PACKAGE_BUILDER, parse(toStringArray(config.get(MAPPING_PACKAGE_BUILDER)), MAPPING_PACKAGE_BUILDER_DEFAULT));
+        mapping.put(REQUEST_AUTHORIZATION, parse(toStringArray(config.get(MAPPING_REQUEST_AUTHORIZATION)), MAPPING_REQUEST_AUTHORIZATION_DEFAULT));
+        mapping.put(TRIGGER, parse(toStringArray(config.get(MAPPING_TRIGGER)), MAPPING_TRIGGER_DEFAULT));
+    }
+
+    String getType(DistributionComponentKind kind, @Nonnull String factoryPid) {
+        Map<String,String> entries = getEntries(kind);
+        for (Map.Entry<String, String> entry : entries.entrySet()) {
+            if (factoryPid.equals(entry.getValue())) {
+                return entry.getKey();
+            }
+        }
+        return null;
+    }
+
+    String getFactoryPid(DistributionComponentKind kind, String type) {
+        return getEntries(kind).get(type);
+    }
+
+    List<String> getFactoryPids(DistributionComponentKind kind) {
+        return new ArrayList<String>(getEntries(kind).values());
+    }
+
+    //
+
+    private Map<String,String> parse(@Nullable String[] mappings, @Nonnull String[] defaultMappings) {
+        Map<String,String> parsed = new HashMap<String, String>();
+        parsed.putAll(parse(defaultMappings));
+        if (mappings != null) {
+            parsed.putAll(parse(mappings));
+        }
+        return parsed;
+    }
+
+    private Map<String,String> parse(@Nonnull String[] mappings) {
+        Map<String, String> map = new HashMap<String, String>();
+        for (String mapping : mappings) {
+            String[] chunks = mapping.split(":");
+            if (chunks.length != 2) {
+                log.info(format("Skipping invalid mapping entry %s", mapping));
+            } else {
+                map.put(chunks[0], chunks[1]);
+            }
+        }
+        return map;
+    }
+
+    private Map<String,String> getEntries(DistributionComponentKind kind) {
+        Map<String,String> entries = mapping.get(kind);
+        if (entries == null) {
+            throw new IllegalArgumentException(format("No mapping for components kind %s", kind));
+        }
+        return entries;
+    }
+}
diff --git a/src/main/java/org/apache/sling/distribution/component/impl/DistributionComponentKind.java b/src/main/java/org/apache/sling/distribution/component/impl/DistributionComponentKind.java
index 12c3d32..043662f 100644
--- a/src/main/java/org/apache/sling/distribution/component/impl/DistributionComponentKind.java
+++ b/src/main/java/org/apache/sling/distribution/component/impl/DistributionComponentKind.java
@@ -28,39 +28,15 @@
 import static org.apache.sling.distribution.resources.DistributionResourceTypes.TRIGGER_LIST_RESOURCE_TYPE;
 import static org.apache.sling.distribution.resources.DistributionResourceTypes.TRIGGER_RESOURCE_TYPE;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
 import org.apache.sling.distribution.agent.spi.DistributionAgent;
 import org.apache.sling.distribution.agent.impl.DistributionRequestAuthorizationStrategy;
-import org.apache.sling.distribution.agent.impl.ForwardDistributionAgentFactory;
-import org.apache.sling.distribution.agent.impl.PrivilegeDistributionRequestAuthorizationStrategy;
-import org.apache.sling.distribution.agent.impl.QueueDistributionAgentFactory;
-import org.apache.sling.distribution.agent.impl.ReverseDistributionAgentFactory;
-import org.apache.sling.distribution.agent.impl.SimpleDistributionAgentFactory;
-import org.apache.sling.distribution.agent.impl.SyncDistributionAgentFactory;
 import org.apache.sling.distribution.packaging.DistributionPackageBuilder;
 import org.apache.sling.distribution.packaging.impl.DistributionPackageExporter;
 import org.apache.sling.distribution.packaging.impl.DistributionPackageImporter;
-import org.apache.sling.distribution.packaging.impl.exporter.AgentDistributionPackageExporterFactory;
-import org.apache.sling.distribution.packaging.impl.exporter.LocalDistributionPackageExporterFactory;
-import org.apache.sling.distribution.packaging.impl.exporter.RemoteDistributionPackageExporterFactory;
-import org.apache.sling.distribution.packaging.impl.importer.LocalDistributionPackageImporterFactory;
-import org.apache.sling.distribution.packaging.impl.importer.RemoteDistributionPackageImporterFactory;
 import org.apache.sling.distribution.queue.impl.DistributionQueueProvider;
 import org.apache.sling.distribution.queue.impl.DistributionQueueDispatchingStrategy;
-import org.apache.sling.distribution.serialization.impl.vlt.VaultDistributionPackageBuilderFactory;
 import org.apache.sling.distribution.transport.DistributionTransportSecretProvider;
-import org.apache.sling.distribution.transport.impl.UserCredentialsDistributionTransportSecretProvider;
 import org.apache.sling.distribution.trigger.DistributionTrigger;
-import org.apache.sling.distribution.trigger.impl.DistributionEventDistributeDistributionTriggerFactory;
-import org.apache.sling.distribution.trigger.impl.JcrEventDistributionTriggerFactory;
-import org.apache.sling.distribution.trigger.impl.PersistedJcrEventDistributionTriggerFactory;
-import org.apache.sling.distribution.trigger.impl.ResourceEventDistributionTriggerFactory;
-import org.apache.sling.distribution.trigger.impl.ScheduledDistributionTriggerFactory;
 
 /**
  * Enum that represents the main distribution component kinds that can be configured for distribution.
@@ -68,81 +44,23 @@
 @SuppressWarnings( "serial" )
 public enum DistributionComponentKind {
 
-    // TODO Do we need to have this concept of "allowed" components ?
+    AGENT("agent", AGENT_RESOURCE_TYPE, AGENT_LIST_RESOURCE_TYPE, DistributionAgent.class),
 
-    AGENT("agent", AGENT_RESOURCE_TYPE, AGENT_LIST_RESOURCE_TYPE, DistributionAgent.class, new HashMap<String, String>() {
-        {
-            put("simple", SimpleDistributionAgentFactory.class.getName());
-            put("sync", SyncDistributionAgentFactory.class.getName());
-            put("forward", ForwardDistributionAgentFactory.class.getName());
-            put("reverse", ReverseDistributionAgentFactory.class.getName());
-            put("queue", QueueDistributionAgentFactory.class.getName());
-        }
-    }),
+    IMPORTER("importer", IMPORTER_RESOURCE_TYPE, IMPORTER_LIST_RESOURCE_TYPE, DistributionPackageImporter.class),
 
-    IMPORTER("importer", IMPORTER_RESOURCE_TYPE, IMPORTER_LIST_RESOURCE_TYPE, DistributionPackageImporter.class, new HashMap<String, String>() {
-        {
-            put("local", LocalDistributionPackageImporterFactory.class.getName());
-            put("remote", RemoteDistributionPackageImporterFactory.class.getName());
-        }
-    }),
+    EXPORTER("exporter", EXPORTER_RESOURCE_TYPE, EXPORTER_LIST_RESOURCE_TYPE, DistributionPackageExporter.class),
 
-    EXPORTER("exporter", EXPORTER_RESOURCE_TYPE, EXPORTER_LIST_RESOURCE_TYPE, DistributionPackageExporter.class, new HashMap<String, String>() {
-        {
-            put("local", LocalDistributionPackageExporterFactory.class.getName());
-            put("remote", RemoteDistributionPackageExporterFactory.class.getName());
-            put("agent", AgentDistributionPackageExporterFactory.class.getName());
-        }
-    }),
+    QUEUE_PROVIDER("queueProvider", DEFAULT_SERVICE_RESOURCE_TYPE, DEFAULT_SERVICE_RESOURCE_TYPE, DistributionQueueProvider.class),
 
-    QUEUE_PROVIDER("queueProvider", DEFAULT_SERVICE_RESOURCE_TYPE, DEFAULT_SERVICE_RESOURCE_TYPE, DistributionQueueProvider.class, new HashMap<String, String>() {
-        {
-            put("simple", SimpleDistributionAgentFactory.class.getName());
-            put("sync", SyncDistributionAgentFactory.class.getName());
-            put("forward", ForwardDistributionAgentFactory.class.getName());
-            put("reverse", ReverseDistributionAgentFactory.class.getName());
-            put("queue", QueueDistributionAgentFactory.class.getName());
-        }
-    }),
+    QUEUE_STRATEGY("queueStrategy", DEFAULT_SERVICE_RESOURCE_TYPE, DEFAULT_SERVICE_RESOURCE_TYPE, DistributionQueueDispatchingStrategy.class),
 
-    QUEUE_STRATEGY("queueStrategy", DEFAULT_SERVICE_RESOURCE_TYPE, DEFAULT_SERVICE_RESOURCE_TYPE, DistributionQueueDispatchingStrategy.class, new HashMap<String, String>() {
-        {
-            put("simple", SimpleDistributionAgentFactory.class.getName());
-            put("sync", SyncDistributionAgentFactory.class.getName());
-            put("forward", ForwardDistributionAgentFactory.class.getName());
-            put("reverse", ReverseDistributionAgentFactory.class.getName());
-            put("queue", QueueDistributionAgentFactory.class.getName());
-        }
-    }),
+    TRANSPORT_SECRET_PROVIDER("transportSecretProvider", DEFAULT_SERVICE_RESOURCE_TYPE, DEFAULT_SERVICE_RESOURCE_TYPE, DistributionTransportSecretProvider.class),
 
-    TRANSPORT_SECRET_PROVIDER("transportSecretProvider", DEFAULT_SERVICE_RESOURCE_TYPE, DEFAULT_SERVICE_RESOURCE_TYPE, DistributionTransportSecretProvider.class, new HashMap<String, String>() {
-        {
-            put("user", UserCredentialsDistributionTransportSecretProvider.class.getName());
-        }
-    }),
+    PACKAGE_BUILDER("packageBuilder", DEFAULT_SERVICE_RESOURCE_TYPE, DEFAULT_SERVICE_RESOURCE_TYPE, DistributionPackageBuilder.class),
 
-    PACKAGE_BUILDER("packageBuilder", DEFAULT_SERVICE_RESOURCE_TYPE, DEFAULT_SERVICE_RESOURCE_TYPE, DistributionPackageBuilder.class, new HashMap<String, String>() {
-        {
-            put("filevlt", VaultDistributionPackageBuilderFactory.class.getName());
-            put("jcrvlt", VaultDistributionPackageBuilderFactory.class.getName());
-        }
-    }),
+    REQUEST_AUTHORIZATION("requestAuthorization", DEFAULT_SERVICE_RESOURCE_TYPE, DEFAULT_SERVICE_RESOURCE_TYPE, DistributionRequestAuthorizationStrategy.class),
 
-    REQUEST_AUTHORIZATION("requestAuthorization", DEFAULT_SERVICE_RESOURCE_TYPE, DEFAULT_SERVICE_RESOURCE_TYPE, DistributionRequestAuthorizationStrategy.class, new HashMap<String, String>() {
-        {
-            put("privilege", PrivilegeDistributionRequestAuthorizationStrategy.class.getName());
-        }
-    }),
-
-    TRIGGER("trigger", TRIGGER_RESOURCE_TYPE, TRIGGER_LIST_RESOURCE_TYPE, DistributionTrigger.class, new HashMap<String, String>() {
-        {
-            put("resourceEvent", ResourceEventDistributionTriggerFactory.class.getName());
-            put("scheduledEvent", ScheduledDistributionTriggerFactory.class.getName());
-            put("distributionEvent", DistributionEventDistributeDistributionTriggerFactory.class.getName());
-            put("persistedJcrEvent", PersistedJcrEventDistributionTriggerFactory.class.getName());
-            put("jcrEvent", JcrEventDistributionTriggerFactory.class.getName());
-        }
-    });
+    TRIGGER("trigger", TRIGGER_RESOURCE_TYPE, TRIGGER_LIST_RESOURCE_TYPE, DistributionTrigger.class);
 
     private final String name;
 
@@ -152,18 +70,14 @@
 
     private final Class<?> type;
 
-    private final Map<String, String> factoryMap;
-
     DistributionComponentKind(String name,
                               String resourceType,
                               String rootResourceType,
-                              Class<?> type,
-                              Map<String, String> factoryMap) {
+                              Class<?> type) {
         this.name = name;
         this.resourceType = resourceType;
         this.rootResourceType = rootResourceType;
         this.type = type;
-        this.factoryMap = factoryMap;
     }
 
     public Class<?> asClass() {
@@ -205,32 +119,4 @@
         return rootResourceType;
     }
 
-    public String getFactory(String type) {
-        String factory = factoryMap.get(type);
-        if (factory != null) {
-            return factory;
-        }
-        return null;
-    }
-
-    public List<String> getFactories() {
-        List<String> result = new ArrayList<String>();
-        for (String factory : factoryMap.values()) {
-            result.add(factory);
-        }
-        return result;
-    }
-
-    public String getType(String factory) {
-        for (Entry<String, String> factoryEntry : factoryMap.entrySet()) {
-            String type = factoryEntry.getKey();
-            String factoryClass = factoryEntry.getValue();
-
-            if (factoryClass.equals(factory)) {
-                return type;
-            }
-        }
-        return null;
-    }
-
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/distribution/component/impl/OsgiConfigurationManager.java b/src/main/java/org/apache/sling/distribution/component/impl/OsgiConfigurationManager.java
index 681af10..145457a 100644
--- a/src/main/java/org/apache/sling/distribution/component/impl/OsgiConfigurationManager.java
+++ b/src/main/java/org/apache/sling/distribution/component/impl/OsgiConfigurationManager.java
@@ -46,9 +46,12 @@
     private final ConfigurationAdmin configurationAdmin;
     private final Logger log = LoggerFactory.getLogger(getClass());
 
-    public OsgiConfigurationManager(ConfigurationAdmin configurationAdmin) {
+    private final DistributionComponentFactoryMap componentFactoryMap;
+
+    public OsgiConfigurationManager(ConfigurationAdmin configurationAdmin, DistributionComponentFactoryMap componentFactoryMap) {
 
         this.configurationAdmin = configurationAdmin;
+        this.componentFactoryMap = componentFactoryMap;
     }
 
 
@@ -95,7 +98,7 @@
             Map<String, Object> result = OsgiUtils.fromDictionary(properties);
 
             String factoryPid = PropertiesUtil.toString(result.get(ConfigurationAdmin.SERVICE_FACTORYPID), null);
-            String type = kind.getType(factoryPid);
+            String type = componentFactoryMap.getType(kind, factoryPid);
 
             result.put(DistributionComponentConstants.PN_TYPE, type);
             result = filterBeforeRead(result);
@@ -115,7 +118,7 @@
             throw new IllegalArgumentException("kind and type are required " + componentKind + componentType);
         }
 
-        String factoryPid = componentKind.getFactory(componentType);
+        String factoryPid = componentFactoryMap.getFactoryPid(componentKind, componentType);
         if (factoryPid != null) {
 
             // SLING-5872 - Management of agent configurations must identify configurations by name
@@ -159,7 +162,7 @@
     }
 
     private List<Configuration> getOsgiConfigurations(DistributionComponentKind kind, String componentName) {
-        List<String> factoryPids = kind.getFactories();
+        List<String> factoryPids = componentFactoryMap.getFactoryPids(kind);
 
         List<Configuration> allConfigurations = new ArrayList<Configuration>();
         for (String factoryPid : factoryPids) {
diff --git a/src/test/java/org/apache/sling/distribution/component/impl/DistributionComponentFactoryMapTest.java b/src/test/java/org/apache/sling/distribution/component/impl/DistributionComponentFactoryMapTest.java
new file mode 100644
index 0000000..3cbb9f3
--- /dev/null
+++ b/src/test/java/org/apache/sling/distribution/component/impl/DistributionComponentFactoryMapTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.distribution.component.impl;
+
+import java.util.Collections;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class DistributionComponentFactoryMapTest {
+
+    @Test
+    public void testGetDefaultType() throws Exception {
+        DistributionComponentFactoryMap dcfm = new DistributionComponentFactoryMap();
+        dcfm.activate(Collections.<String,Object>emptyMap());
+        String type = dcfm.getType(DistributionComponentKind.AGENT,
+                "org.apache.sling.distribution.agent.impl.SimpleDistributionAgentFactory");
+        assertEquals("simple", type);
+    }
+
+    @Test
+    public void testGetDefaultFactoryPid() throws Exception {
+        DistributionComponentFactoryMap dcfm = new DistributionComponentFactoryMap();
+        dcfm.activate(Collections.<String,Object>emptyMap());
+        String factoryPid = dcfm.getFactoryPid(DistributionComponentKind.AGENT, "simple");
+        assertEquals("org.apache.sling.distribution.agent.impl.SimpleDistributionAgentFactory",
+                factoryPid);
+    }
+
+    @Test
+    public void testGetDefaultFactoryPids() throws Exception {
+        DistributionComponentFactoryMap dcfm = new DistributionComponentFactoryMap();
+        dcfm.activate(Collections.<String,Object>emptyMap());
+        assertEquals(5, dcfm.getFactoryPids(DistributionComponentKind.AGENT).size());
+    }
+
+    @Test
+    public void testAddMapping() throws Exception {
+        DistributionComponentFactoryMap dcfm = new DistributionComponentFactoryMap();
+        String customFactoryPid = "org.test.CustomAgentFactory";
+        dcfm.activate(Collections.<String, Object>singletonMap("mapping.agent", String.format("custom:%s", customFactoryPid)));
+        assertEquals(6, dcfm.getFactoryPids(DistributionComponentKind.AGENT).size());
+        String type = dcfm.getType(DistributionComponentKind.AGENT, customFactoryPid);
+        assertEquals("custom", type);
+    }
+
+    @Test
+    public void testAddWrongMapping() throws Exception {
+        DistributionComponentFactoryMap dcfm = new DistributionComponentFactoryMap();
+        String customFactoryPid = "org.test.CustomAgentFactory";
+        dcfm.activate(Collections.<String, Object>singletonMap("mapping.agent", String.format("custom-%s", customFactoryPid)));
+        assertEquals(5, dcfm.getFactoryPids(DistributionComponentKind.AGENT).size());
+        String type = dcfm.getType(DistributionComponentKind.AGENT, customFactoryPid);
+        assertNull(type);
+    }
+}
\ No newline at end of file