blob: 58b543c65d6cc79c154576ae3b521c3101c514b7 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
2* Copyright 2011, Big Switch Networks, Inc.
3* Originally created by David Erickson, Stanford University
4*
5* Licensed under the Apache License, Version 2.0 (the "License"); you may
6* not use this file except in compliance with the License. You may obtain
7* a copy of the License at
8*
9* http://www.apache.org/licenses/LICENSE-2.0
10*
11* Unless required by applicable law or agreed to in writing, software
12* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14* License for the specific language governing permissions and limitations
15* under the License.
16**/
17
18package net.floodlightcontroller.core.util;
19
20import java.util.ArrayList;
21import java.util.HashSet;
22import java.util.List;
23
24import org.slf4j.Logger;
25import org.slf4j.LoggerFactory;
26
27import net.floodlightcontroller.core.IListener;
28import net.floodlightcontroller.core.annotations.LogMessageDoc;
29
30/**
31 * Maintain lists of listeners ordered by dependency.
32 *
33 * @author readams
34 *
35 */
36public class ListenerDispatcher<U, T extends IListener<U>> {
37 protected static Logger logger = LoggerFactory.getLogger(ListenerDispatcher.class);
38 List<T> listeners = null;
39
40 private void visit(List<T> newlisteners, U type, HashSet<T> visited,
41 List<T> ordering, T listener) {
42 if (!visited.contains(listener)) {
43 visited.add(listener);
44
45 for (T i : newlisteners) {
46 if (ispre(type, i, listener)) {
47 visit(newlisteners, type, visited, ordering, i);
48 }
49 }
50 ordering.add(listener);
51 }
52 }
53
54 private boolean ispre(U type, T l1, T l2) {
55 return (l2.isCallbackOrderingPrereq(type, l1.getName()) ||
56 l1.isCallbackOrderingPostreq(type, l2.getName()));
57 }
58
59 /**
60 * Add a listener to the list of listeners
61 * @param listener
62 */
63 @LogMessageDoc(level="ERROR",
64 message="No listener dependency solution: " +
65 "No listeners without incoming dependencies",
66 explanation="The set of listeners installed " +
67 "have dependencies with no solution",
68 recommendation="Install a different set of listeners " +
69 "or install all dependencies. This is a defect in " +
70 "the controller installation.")
71 public void addListener(U type, T listener) {
72 List<T> newlisteners = new ArrayList<T>();
73 if (listeners != null)
74 newlisteners.addAll(listeners);
75
76 newlisteners.add(listener);
77 // Find nodes without outgoing edges
78 List<T> terminals = new ArrayList<T>();
79 for (T i : newlisteners) {
80 boolean isterm = true;
81 for (T j : newlisteners) {
82 if (ispre(type, i, j)) {
83 isterm = false;
84 break;
85 }
86 }
87 if (isterm) {
88 terminals.add(i);
89 }
90 }
91
92 if (terminals.size() == 0) {
93 logger.error("No listener dependency solution: " +
94 "No listeners without incoming dependencies");
95 listeners = newlisteners;
96 return;
97 }
98
99 // visit depth-first traversing in the opposite order from
100 // the dependencies. Note we will not generally detect cycles
101 HashSet<T> visited = new HashSet<T>();
102 List<T> ordering = new ArrayList<T>();
103 for (T term : terminals) {
104 visit(newlisteners, type, visited, ordering, term);
105 }
106 listeners = ordering;
107 }
108
109 /**
110 * Remove the given listener
111 * @param listener the listener to remove
112 */
113 public void removeListener(T listener) {
114 if (listeners != null) {
115 List<T> newlisteners = new ArrayList<T>();
116 newlisteners.addAll(listeners);
117 newlisteners.remove(listener);
118 listeners = newlisteners;
119 }
120 }
121
122 /**
123 * Clear all listeners
124 */
125 public void clearListeners() {
126 listeners = new ArrayList<T>();
127 }
128
129 /**
130 * Get the ordered list of listeners ordered by dependencies
131 * @return
132 */
133 public List<T> getOrderedListeners() {
134 return listeners;
135 }
136}