Move adsal into its own subdirectory.
[controller.git] / opendaylight / adsal / sal / api / src / main / java / org / opendaylight / controller / sal / utils / ListenerDispatcher.java
diff --git a/opendaylight/adsal/sal/api/src/main/java/org/opendaylight/controller/sal/utils/ListenerDispatcher.java b/opendaylight/adsal/sal/api/src/main/java/org/opendaylight/controller/sal/utils/ListenerDispatcher.java
new file mode 100644 (file)
index 0000000..282bac6
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2011 Big Switch Networks, Inc.
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html
+ *
+ * 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 file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ *    Originally created by David Erickson, Stanford University
+ *
+ *    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.opendaylight.controller.sal.utils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Maintain lists of listeners ordered by dependency.
+ *
+ * @author readams
+ *
+ */
+public class ListenerDispatcher<U, T extends IListener<U>> {
+    protected static Logger logger = LoggerFactory
+            .getLogger(ListenerDispatcher.class);
+    volatile List<T> listeners = new ArrayList<T>();
+
+    private void visit(List<T> newlisteners, U type, HashSet<T> visited,
+            List<T> ordering, T listener) {
+        if (!visited.contains(listener)) {
+            visited.add(listener);
+
+            for (T i : newlisteners) {
+                if (ispre(type, i, listener)) {
+                    visit(newlisteners, type, visited, ordering, i);
+                }
+            }
+            ordering.add(listener);
+        }
+    }
+
+    private boolean ispre(U type, T l1, T l2) {
+        return (l2.isCallbackOrderingPrereq(type, l1.getName()) || l1
+                .isCallbackOrderingPostreq(type, l2.getName()));
+    }
+
+    /**
+     * Add a listener to the list of listeners
+     *
+     * @param listener
+     */
+    public void addListener(U type, T listener) {
+        List<T> newlisteners = new ArrayList<T>();
+        if (listeners != null)
+            newlisteners.addAll(listeners);
+
+        newlisteners.add(listener);
+        // Find nodes without outgoing edges
+        List<T> terminals = new ArrayList<T>();
+        for (T i : newlisteners) {
+            boolean isterm = true;
+            for (T j : newlisteners) {
+                if (ispre(type, i, j)) {
+                    isterm = false;
+                    break;
+                }
+            }
+            if (isterm) {
+                terminals.add(i);
+            }
+        }
+
+        if (terminals.size() == 0) {
+            logger.error("No listener dependency solution: "
+                    + "No listeners without incoming dependencies");
+            listeners = newlisteners;
+            return;
+        }
+
+        // visit depth-first traversing in the opposite order from
+        // the dependencies. Note we will not generally detect cycles
+        HashSet<T> visited = new HashSet<T>();
+        List<T> ordering = new ArrayList<T>();
+        for (T term : terminals) {
+            visit(newlisteners, type, visited, ordering, term);
+        }
+        listeners = ordering;
+    }
+
+    /**
+     * Remove the given listener
+     *
+     * @param listener
+     *            the listener to remove
+     */
+    public void removeListener(T listener) {
+        if (listeners != null) {
+            List<T> newlisteners = new ArrayList<T>();
+            newlisteners.addAll(listeners);
+            newlisteners.remove(listener);
+            listeners = newlisteners;
+        }
+    }
+
+    /**
+     * Clear all listeners
+     */
+    public void clearListeners() {
+        listeners = new ArrayList<T>();
+    }
+
+    /**
+     * Get the ordered list of listeners ordered by dependencies
+     *
+     * @return
+     */
+    public List<T> getOrderedListeners() {
+        return listeners;
+    }
+}