blob: f716f4b9e654d26b2f3e2bbebd1f7d46c64d6072 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
Ray Milkey269ffb92014-04-03 14:43:30 -07002 * 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 **/
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080017
18package net.floodlightcontroller.core.util;
19
20import java.util.ArrayList;
21import java.util.HashSet;
22import java.util.List;
23
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080024import net.floodlightcontroller.core.IListener;
25import net.floodlightcontroller.core.annotations.LogMessageDoc;
26
Jonathan Harta99ec672014-04-03 11:30:34 -070027import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080030/**
Ray Milkey269ffb92014-04-03 14:43:30 -070031 * Maintain lists of listeners ordered by dependency.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080032 *
Ray Milkey269ffb92014-04-03 14:43:30 -070033 * @author readams
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080034 */
35public class ListenerDispatcher<U, T extends IListener<U>> {
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070036 protected final static Logger logger = LoggerFactory.getLogger(ListenerDispatcher.class);
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080037 List<T> listeners = null;
Ray Milkey269ffb92014-04-03 14:43:30 -070038
39 private void visit(List<T> newlisteners, U type, HashSet<T> visited,
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080040 List<T> ordering, T listener) {
41 if (!visited.contains(listener)) {
42 visited.add(listener);
Ray Milkey269ffb92014-04-03 14:43:30 -070043
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080044 for (T i : newlisteners) {
45 if (ispre(type, i, listener)) {
46 visit(newlisteners, type, visited, ordering, i);
47 }
48 }
49 ordering.add(listener);
50 }
51 }
Ray Milkey269ffb92014-04-03 14:43:30 -070052
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080053 private boolean ispre(U type, T l1, T l2) {
54 return (l2.isCallbackOrderingPrereq(type, l1.getName()) ||
55 l1.isCallbackOrderingPostreq(type, l2.getName()));
56 }
Ray Milkey269ffb92014-04-03 14:43:30 -070057
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080058 /**
59 * Add a listener to the list of listeners
Ray Milkey269ffb92014-04-03 14:43:30 -070060 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080061 * @param listener
62 */
Ray Milkey269ffb92014-04-03 14:43:30 -070063 @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.")
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080071 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
Ray Milkey269ffb92014-04-03 14:43:30 -070078 List<T> terminals = new ArrayList<T>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080079 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 }
Ray Milkey269ffb92014-04-03 14:43:30 -070091
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080092 if (terminals.size() == 0) {
93 logger.error("No listener dependency solution: " +
Ray Milkey269ffb92014-04-03 14:43:30 -070094 "No listeners without incoming dependencies");
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080095 listeners = newlisteners;
96 return;
97 }
Ray Milkey269ffb92014-04-03 14:43:30 -070098
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080099 // 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>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700102 List<T> ordering = new ArrayList<T>();
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800103 for (T term : terminals) {
104 visit(newlisteners, type, visited, ordering, term);
105 }
106 listeners = ordering;
107 }
108
109 /**
110 * Remove the given listener
Ray Milkey269ffb92014-04-03 14:43:30 -0700111 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800112 * @param listener the listener to remove
113 */
114 public void removeListener(T listener) {
115 if (listeners != null) {
116 List<T> newlisteners = new ArrayList<T>();
117 newlisteners.addAll(listeners);
118 newlisteners.remove(listener);
119 listeners = newlisteners;
120 }
121 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700122
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800123 /**
124 * Clear all listeners
125 */
126 public void clearListeners() {
127 listeners = new ArrayList<T>();
128 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700129
130 /**
131 * Get the ordered list of listeners ordered by dependencies
132 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800133 * @return
134 */
135 public List<T> getOrderedListeners() {
136 return listeners;
137 }
138}