/*
* Copyright (c) 2011,2013 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.sdnplatform.core.util;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.sdnplatform.core.IListener;
import org.sdnplatform.core.annotations.LogMessageDoc;
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);
List<T> listeners = null;
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
*/
@LogMessageDoc(level="ERROR",
message="No listener dependency solution: " +
"No listeners without incoming dependencies",
explanation="The set of listeners installed " +
"have dependencies with no solution",
recommendation="Install a different set of listeners " +
"or install all dependencies. This is a defect in " +
"the controller installation.")
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;
}
}