Adding configurability for registration of flow-based intent compilers.

Added configurability of the intent manager number of workers.

Change-Id: Id5e221e077ef3246a7f274bad2e40166313899f5
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
index 16f05d6..60b279f 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
@@ -85,19 +85,23 @@
     public static final String INTENT_NULL = "Intent cannot be null";
     public static final String INTENT_ID_NULL = "Intent key cannot be null";
 
-    private static final int NUM_THREADS = 12;
-
     private static final EnumSet<IntentState> RECOMPILE
             = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
     private static final EnumSet<IntentState> WITHDRAW
             = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
-    private static final boolean DEFAULT_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL = false;
 
+    private static final boolean DEFAULT_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL = false;
     @Property(name = "skipReleaseResourcesOnWithdrawal",
             boolValue = DEFAULT_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL,
             label = "Indicates whether skipping resource releases on withdrawal is enabled or not")
     private boolean skipReleaseResourcesOnWithdrawal = DEFAULT_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL;
 
+    private static final int DEFAULT_NUM_THREADS = 12;
+    @Property(name = "numThreads",
+            intValue = DEFAULT_NUM_THREADS,
+            label = "Number of worker threads")
+    private int numThreads = DEFAULT_NUM_THREADS;
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
 
@@ -119,7 +123,6 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ComponentConfigService configService;
 
-
     private ExecutorService batchExecutor;
     private ExecutorService workerExecutor;
 
@@ -147,7 +150,7 @@
         trackerService.setDelegate(topoDelegate);
         eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
         batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
-        workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
+        workerExecutor = newFixedThreadPool(numThreads, groupedThreads("onos/intent", "worker-%d"));
         idGenerator = coreService.getIdGenerator("intent-ids");
         Intent.bindIdGenerator(idGenerator);
         log.info("Started");
@@ -183,11 +186,25 @@
         if (skipReleaseResourcesOnWithdrawal && !newTestEnabled) {
             store.unsetDelegate(testOnlyDelegate);
             store.setDelegate(delegate);
-            logConfig("Reconfigured");
+            skipReleaseResourcesOnWithdrawal = false;
+            logConfig("Reconfigured skip release resources on withdrawal");
         } else if (!skipReleaseResourcesOnWithdrawal && newTestEnabled) {
             store.unsetDelegate(delegate);
             store.setDelegate(testOnlyDelegate);
-            logConfig("Reconfigured");
+            skipReleaseResourcesOnWithdrawal = true;
+            logConfig("Reconfigured skip release resources on withdrawal");
+        }
+
+        s = Tools.get(context.getProperties(), "numThreads");
+        int newNumThreads = isNullOrEmpty(s) ? numThreads : Integer.parseInt(s);
+        if (newNumThreads != numThreads) {
+            numThreads = newNumThreads;
+            ExecutorService oldWorkerExecutor = workerExecutor;
+            workerExecutor = newFixedThreadPool(numThreads, groupedThreads("onos/intent", "worker-%d"));
+            if (oldWorkerExecutor != null) {
+                oldWorkerExecutor.shutdown();
+            }
+            logConfig("Reconfigured number of worker threads");
         }
     }
 
@@ -281,7 +298,6 @@
     @Override
     public Iterable<Intent> getPending() {
         checkPermission(INTENT_READ);
-
         return store.getPending();
     }
 
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
new file mode 100644
index 0000000..397963c
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 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.net.intent.impl.compiler;
+
+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.Modified;
+import org.apache.felix.scr.annotations.Property;
+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.Tools;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentCompiler;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+
+import java.util.Map;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Auxiliary utility to register either flow-rule compilers or flow-objective
+ * compilers.
+ */
+@Component
+@Service(value = IntentConfigurableRegistrator.class)
+public class IntentConfigurableRegistrator {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentExtensionService extensionService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService cfgService;
+
+    private static final boolean DEFAULT_FLOW_OBJECTIVES = false;
+    @Property(name = "useFlowObjectives",
+            boolValue = DEFAULT_FLOW_OBJECTIVES,
+            label = "Indicates whether to use flow objective-based compilers")
+    private boolean useFlowObjectives = DEFAULT_FLOW_OBJECTIVES;
+
+    private final Map<Class<Intent>, IntentCompiler<Intent>> flowRuleBased = Maps.newConcurrentMap();
+    private final Map<Class<Intent>, IntentCompiler<Intent>> flowObjectiveBased = Maps.newConcurrentMap();
+
+    @Activate
+    public void activate() {
+        cfgService.registerProperties(getClass());
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        cfgService.unregisterProperties(getClass(), false);
+        log.info("Stopped");
+    }
+
+    @Modified
+    public void modified(ComponentContext context) {
+        if (context == null) {
+            log.info("Default config");
+            return;
+        }
+
+        boolean newFlowObjectives;
+        try {
+            String s = Tools.get(context.getProperties(), "useFlowObjectives");
+            newFlowObjectives = isNullOrEmpty(s) ? useFlowObjectives : Boolean.parseBoolean(s.trim());
+        } catch (ClassCastException e) {
+            newFlowObjectives = useFlowObjectives;
+        }
+
+        if (useFlowObjectives != newFlowObjectives) {
+            useFlowObjectives = newFlowObjectives;
+            changeCompilers();
+            log.info("Reconfigured use of flow objectives");
+        }
+    }
+
+    /**
+     * Registers the specified compiler for the given intent class.
+     *
+     * @param cls       intent class
+     * @param compiler  intent compiler
+     * @param flowBased true if the compiler is flow based
+     * @param <T>       the type of intent
+     */
+    @SuppressWarnings("unchecked")
+    <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler,
+                                             boolean flowBased) {
+        if (flowBased) {
+            flowObjectiveBased.put((Class<Intent>) cls, (IntentCompiler<Intent>) compiler);
+        } else {
+            flowRuleBased.put((Class<Intent>) cls, (IntentCompiler<Intent>) compiler);
+        }
+        if (flowBased == useFlowObjectives) {
+            extensionService.registerCompiler(cls, compiler);
+        }
+    }
+
+    /**
+     * Unregisters the compiler for the specified intent class.
+     *
+     * @param cls       intent class
+     * @param flowBased true if the compiler is flow based
+     * @param <T>       the type of intent
+     */
+    @SuppressWarnings("unchecked")
+    <T extends Intent> void unregisterCompiler(Class<T> cls, boolean flowBased) {
+        if (flowBased) {
+            flowObjectiveBased.remove(cls);
+        } else {
+            flowRuleBased.remove(cls);
+        }
+        if (flowBased == useFlowObjectives) {
+            extensionService.unregisterCompiler(cls);
+        }
+    }
+
+    private void changeCompilers() {
+        if (useFlowObjectives) {
+            flowRuleBased.forEach((cls, compiler) -> extensionService.unregisterCompiler(cls));
+            flowObjectiveBased.forEach((cls, compiler) -> extensionService.registerCompiler(cls, compiler));
+        } else {
+            flowObjectiveBased.forEach((cls, compiler) -> extensionService.unregisterCompiler(cls));
+            flowRuleBased.forEach((cls, compiler) -> extensionService.registerCompiler(cls, compiler));
+        }
+    }
+
+}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java
index 76c5736..e1bed15 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java
@@ -37,7 +37,6 @@
 import org.onosproject.net.intent.FlowRuleIntent;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentCompiler;
-import org.onosproject.net.intent.IntentExtensionService;
 import org.onosproject.net.intent.LinkCollectionIntent;
 import org.onosproject.net.resource.link.LinkResourceAllocations;
 
@@ -51,7 +50,7 @@
 public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollectionIntent> {
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected IntentExtensionService intentManager;
+    protected IntentConfigurableRegistrator registrator;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
@@ -61,12 +60,12 @@
     @Activate
     public void activate() {
         appId = coreService.registerApplication("org.onosproject.net.intent");
-        intentManager.registerCompiler(LinkCollectionIntent.class, this);
+        registrator.registerCompiler(LinkCollectionIntent.class, this, false);
     }
 
     @Deactivate
     public void deactivate() {
-        intentManager.unregisterCompiler(LinkCollectionIntent.class);
+        registrator.unregisterCompiler(LinkCollectionIntent.class, false);
     }
 
     @Override
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectivesCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectivesCompiler.java
index d978e69..1ef3ee2 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectivesCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectivesCompiler.java
@@ -15,12 +15,8 @@
  */
 package org.onosproject.net.intent.impl.compiler;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -42,12 +38,14 @@
 import org.onosproject.net.intent.FlowObjectiveIntent;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentCompiler;
-import org.onosproject.net.intent.IntentExtensionService;
 import org.onosproject.net.intent.LinkCollectionIntent;
 import org.onosproject.net.resource.link.LinkResourceAllocations;
 
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.SetMultimap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Compiler to produce flow objectives from link collections.
@@ -56,7 +54,7 @@
 public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompiler<LinkCollectionIntent> {
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected IntentExtensionService intentManager;
+    protected IntentConfigurableRegistrator registrator;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
@@ -66,12 +64,12 @@
     @Activate
     public void activate() {
         appId = coreService.registerApplication("org.onosproject.net.intent");
-        //intentManager.registerCompiler(LinkCollectionIntent.class, this);
+        registrator.registerCompiler(LinkCollectionIntent.class, this, true);
     }
 
     @Deactivate
     public void deactivate() {
-        //intentManager.unregisterCompiler(LinkCollectionIntent.class);
+        registrator.unregisterCompiler(LinkCollectionIntent.class, true);
     }
 
     @Override
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java
index 045b0ef..039a1f5 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java
@@ -37,7 +37,6 @@
 import org.onosproject.net.intent.FlowRuleIntent;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentCompiler;
-import org.onosproject.net.intent.IntentExtensionService;
 import org.onosproject.net.intent.PathIntent;
 import org.onosproject.net.newresource.ResourceService;
 import org.onosproject.net.resource.link.LinkResourceAllocations;
@@ -59,7 +58,7 @@
     protected CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected IntentExtensionService intentManager;
+    protected IntentConfigurableRegistrator registrator;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ResourceService resourceService;
@@ -69,12 +68,12 @@
     @Activate
     public void activate() {
         appId = coreService.registerApplication("org.onosproject.net.intent");
-        intentManager.registerCompiler(PathIntent.class, this);
+        registrator.registerCompiler(PathIntent.class, this, false);
     }
 
     @Deactivate
     public void deactivate() {
-        intentManager.unregisterCompiler(PathIntent.class);
+        registrator.unregisterCompiler(PathIntent.class, false);
     }
 
     @Override
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java
index 25cae18..d1ab1cf 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java
@@ -38,7 +38,6 @@
 import org.onosproject.net.intent.FlowObjectiveIntent;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentCompiler;
-import org.onosproject.net.intent.IntentExtensionService;
 import org.onosproject.net.intent.PathIntent;
 import org.onosproject.net.newresource.ResourceService;
 import org.onosproject.net.resource.link.LinkResourceAllocations;
@@ -60,7 +59,7 @@
     protected CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected IntentExtensionService intentManager;
+    protected IntentConfigurableRegistrator registrator;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ResourceService resourceService;
@@ -70,12 +69,12 @@
     @Activate
     public void activate() {
         appId = coreService.registerApplication("org.onosproject.net.intent");
-        //intentManager.registerCompiler(PathIntent.class, this);
+        registrator.registerCompiler(PathIntent.class, this, true);
     }
 
     @Deactivate
     public void deactivate() {
-        //intentManager.unregisterCompiler(PathIntent.class);
+        registrator.unregisterCompiler(PathIntent.class, true);
     }
 
     @Override
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java
index 48f0580..8f84f5c 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java
@@ -20,6 +20,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onosproject.TestApplicationId;
+import org.onosproject.cfg.ComponentConfigAdapter;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.core.IdGenerator;
@@ -74,6 +75,7 @@
 
     private CoreService coreService;
     private IntentExtensionService intentExtensionService;
+    private IntentConfigurableRegistrator registrator;
     private IdGenerator idGenerator = new MockIdGenerator();
 
     private LinkCollectionIntent intent;
@@ -101,7 +103,13 @@
         intentExtensionService = createMock(IntentExtensionService.class);
         intentExtensionService.registerCompiler(LinkCollectionIntent.class, sut);
         intentExtensionService.unregisterCompiler(LinkCollectionIntent.class);
-        sut.intentManager = intentExtensionService;
+
+        registrator = new IntentConfigurableRegistrator();
+        registrator.extensionService = intentExtensionService;
+        registrator.cfgService = new ComponentConfigAdapter();
+        registrator.activate();
+
+        sut.registrator = registrator;
 
         replay(coreService, intentExtensionService);
     }
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
index 007c132..17b173a 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
@@ -21,6 +21,7 @@
 import org.junit.Test;
 import org.onlab.packet.VlanId;
 import org.onosproject.TestApplicationId;
+import org.onosproject.cfg.ComponentConfigAdapter;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.core.IdGenerator;
@@ -67,6 +68,7 @@
 
     private CoreService coreService;
     private IntentExtensionService intentExtensionService;
+    private IntentConfigurableRegistrator registrator;
     private IdGenerator idGenerator = new MockIdGenerator();
     private PathIntentCompiler sut;
 
@@ -142,7 +144,13 @@
         intentExtensionService = createMock(IntentExtensionService.class);
         intentExtensionService.registerCompiler(PathIntent.class, sut);
         intentExtensionService.unregisterCompiler(PathIntent.class);
-        sut.intentManager = intentExtensionService;
+
+        registrator = new IntentConfigurableRegistrator();
+        registrator.extensionService = intentExtensionService;
+        registrator.cfgService = new ComponentConfigAdapter();
+        registrator.activate();
+
+        sut.registrator = registrator;
 
         replay(coreService, intentExtensionService);
     }