Consolidating null providers and making them fully configurable and integrated with the ConfigProvider to allow arbitrary topologies.

Change-Id: I899e27a9771af4013a3ce6da7f683a4927ffb438
diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/NullFlowRuleProvider.java b/providers/null/src/main/java/org/onosproject/provider/nil/NullFlowRuleProvider.java
new file mode 100644
index 0000000..9b01d12
--- /dev/null
+++ b/providers/null/src/main/java/org/onosproject/provider/nil/NullFlowRuleProvider.java
@@ -0,0 +1,132 @@
+/*
+ * 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.provider.nil;
+
+import com.google.common.collect.Sets;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.jboss.netty.util.Timeout;
+import org.jboss.netty.util.TimerTask;
+import org.onlab.util.Timer;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.CompletedBatchOperation;
+import org.onosproject.net.flow.DefaultFlowEntry;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleBatchEntry;
+import org.onosproject.net.flow.FlowRuleBatchOperation;
+import org.onosproject.net.flow.FlowRuleProvider;
+import org.onosproject.net.flow.FlowRuleProviderService;
+import org.slf4j.Logger;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Null provider to accept any flow and report them.
+ */
+class NullFlowRuleProvider extends NullProviders.AbstractNullProvider
+        implements FlowRuleProvider {
+
+    private final Logger log = getLogger(getClass());
+
+    private ConcurrentMap<DeviceId, Set<FlowEntry>> flowTable = new ConcurrentHashMap<>();
+
+    private FlowRuleProviderService providerService;
+
+    private HashedWheelTimer timer = Timer.getTimer();
+    private Timeout timeout;
+
+    /**
+     * Starts the flow rule provider simulation.
+     *
+     * @param providerService flow rule provider service
+     */
+    void start(FlowRuleProviderService providerService) {
+        this.providerService = providerService;
+        timeout = timer.newTimeout(new StatisticTask(), 5, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Stops the flow rule provider simulation.
+     */
+    void stop() {
+        timeout.cancel();
+    }
+
+    @Override
+    public void applyFlowRule(FlowRule... flowRules) {
+        // FIXME: invoke executeBatch
+    }
+
+    @Override
+    public void removeFlowRule(FlowRule... flowRules) {
+        // FIXME: invoke executeBatch
+    }
+
+    @Override
+    public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
+        throw new UnsupportedOperationException("Cannot remove by appId from null provider");
+    }
+
+    @Override
+    public void executeBatch(FlowRuleBatchOperation batch) {
+        // TODO: consider checking mastership
+        Set<FlowEntry> entries =
+                flowTable.getOrDefault(batch.deviceId(),
+                                       Sets.newConcurrentHashSet());
+        for (FlowRuleBatchEntry fbe : batch.getOperations()) {
+            switch (fbe.operator()) {
+                case ADD:
+                    entries.add(new DefaultFlowEntry(fbe.target()));
+                    break;
+                case REMOVE:
+                    entries.remove(new DefaultFlowEntry(fbe.target()));
+                    break;
+                case MODIFY:
+                    FlowEntry entry = new DefaultFlowEntry(fbe.target());
+                    entries.remove(entry);
+                    entries.add(entry);
+                    break;
+                default:
+                    log.error("Unknown flow operation: {}", fbe);
+            }
+        }
+        flowTable.put(batch.deviceId(), entries);
+        CompletedBatchOperation op =
+                new CompletedBatchOperation(true, Collections.emptySet(),
+                                            batch.deviceId());
+        providerService.batchOperationCompleted(batch.id(), op);
+    }
+
+    // Periodically reports flow rule statistics.
+    private class StatisticTask implements TimerTask {
+        @Override
+        public void run(Timeout to) throws Exception {
+            for (DeviceId devId : flowTable.keySet()) {
+                Set<FlowEntry> entries =
+                        flowTable.getOrDefault(devId, Collections.emptySet());
+                providerService.pushFlowMetrics(devId, entries);
+            }
+            timeout = timer.newTimeout(to.getTask(), 5, TimeUnit.SECONDS);
+        }
+    }
+}