DirectoryObserverManager.java
package emissary.directory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* This class is used by DirectoryPlace to manage the interaction with the different types of observers that need to be
* called on the various observable change events.
*/
public class DirectoryObserverManager {
/** Our logger */
protected static final Logger logger = LoggerFactory.getLogger(DirectoryObserverManager.class);
/** Directory key that this observer mananger acts for */
String directoryKey;
/** The observers that are registered */
List<DirectoryObserver> observers = new CopyOnWriteArrayList<>();
/** The types of actions that observers can register for */
public enum Action {
PEER_GROUP_CHANGE, PLACE_ADD, PLACE_REMOVE, PLACE_COST_CHANGE
}
/**
* Construct with key
*
* @param key the key of the directory we work on behalf of
*/
public DirectoryObserverManager(final String key) {
this.directoryKey = key;
}
/**
* Add an observer
*
* @param observer the new observer to add
*/
public void addObserver(final DirectoryObserver observer) {
this.observers.add(observer);
}
/**
* Remove an observer
*
* @param observer the object to remove
* @return true if it was found on the list
*/
public boolean deleteObserver(final DirectoryObserver observer) {
return this.observers.remove(observer);
}
/**
* Count the observers
*
* @return count of how many observers are being managed
*/
public int getObserverCount() {
return this.observers.size();
}
/**
* Count how many peer observers are being managed
*
* @return count of observers on the peer list
*/
public int getPeerObserverCount() {
int count = 0;
for (final DirectoryObserver d : this.observers) {
if (d instanceof PeerObserver) {
count++;
}
}
return count;
}
/**
* Count how many place observers are being managed
*
* @return count of observers on the place list
*/
public int getPlaceObserverCount() {
int count = 0;
for (final DirectoryObserver d : this.observers) {
if (d instanceof PlaceObserver) {
count++;
}
}
return count;
}
/**
* Notify all peer observers of peer list change
*
* @param peers the current list of peers to our directory
*/
public void peerUpdate(final Set<DirectoryEntry> peers) {
int count = 0;
for (final DirectoryObserver d : this.observers) {
if (d instanceof PeerObserver) {
((PeerObserver) d).peerUpdate(this.directoryKey, peers);
count++;
}
}
logger.debug("Notified {} PeerObserver instances", count);
}
/**
* Notify all matching place observers of place add
*
* @param placeKey the key that was added
*/
public void placeAdd(final String placeKey) {
logger.debug("Received notice of {} added", placeKey);
placeUpdate(Action.PLACE_ADD, placeKey);
}
/**
* Notify all matching place observers of place adds
*
* @param placeKeys the list of keys added
*/
public void placeAdd(final List<String> placeKeys) {
logger.debug("Received notice of {} added", placeKeys.size());
for (final String key : placeKeys) {
placeUpdate(Action.PLACE_ADD, key);
}
}
/**
* Notify all matching place observers of place adds
*
* @param placeEntries the list of entries added
*/
public void placeAddEntries(final List<DirectoryEntry> placeEntries) {
logger.debug("Received notice of {} added", placeEntries.size());
for (final DirectoryEntry entry : placeEntries) {
placeUpdate(Action.PLACE_ADD, entry.getFullKey());
}
}
/**
* Notify all matching place observers of place remove
*
* @param placeKey the key what was removed
*/
public void placeRemove(final String placeKey) {
logger.debug("Received notice of {} removed", placeKey);
placeUpdate(Action.PLACE_REMOVE, placeKey);
}
/**
* Notify all matching place observers of place removes
*
* @param placeKeys the list of keys removed
*/
public void placeRemove(final List<String> placeKeys) {
logger.debug("Received notice of {} removed", placeKeys.size());
for (final String key : placeKeys) {
placeUpdate(Action.PLACE_REMOVE, key);
}
}
/**
* Notify all matching place observers of place removes
*
* @param placeEntries the list of entries removed
*/
public void placeRemoveEntries(final List<DirectoryEntry> placeEntries) {
logger.debug("Received notice of {} removed", placeEntries.size());
for (final DirectoryEntry entry : placeEntries) {
placeUpdate(Action.PLACE_REMOVE, entry.getFullKey());
}
}
/**
* Notify all matching place observers of place cost change
*
* @param placeKey the revised key
*/
public void placeCostChange(final String placeKey) {
placeUpdate(Action.PLACE_COST_CHANGE, placeKey);
}
/**
* Notify all matching place observers of place cost changes
*
* @param placeKeys the list of keys with changed cost
*/
public void placeCostChange(final List<String> placeKeys) {
logger.debug("Received notice of {} cost changes", placeKeys.size());
for (final String key : placeKeys) {
placeUpdate(Action.PLACE_COST_CHANGE, key);
}
}
/**
* Notify all matching place observers of place cost changes
*
* @param placeEntries the list of entries with changed cost
*/
public void placeCostChangeEntries(final List<DirectoryEntry> placeEntries) {
logger.debug("Received notice of {} cost changes", placeEntries.size());
for (final DirectoryEntry entry : placeEntries) {
placeUpdate(Action.PLACE_COST_CHANGE, entry.getFullKey());
}
}
/**
* Notify all matching place observers of change
*
* @param action PLACE_ADD or PLACE_REMOVE
* @param placeKey the key that was added or removed
*/
protected void placeUpdate(final Action action, final String placeKey) {
int obcount = 0;
int matchcount = 0;
for (final DirectoryObserver d : this.observers) {
if (d instanceof PlaceObserver) {
final PlaceObserver p = (PlaceObserver) d;
obcount++;
if (KeyManipulator.gmatch(placeKey, p.getPattern())) {
matchcount++;
logger.debug("Match! Doing {} for {}", action, placeKey);
switch (action) {
case PEER_GROUP_CHANGE:
// TODO: remove this ordinal?
break;
case PLACE_ADD:
p.placeRegistered(this.directoryKey, placeKey);
break;
case PLACE_REMOVE:
p.placeDeregistered(this.directoryKey, placeKey);
break;
case PLACE_COST_CHANGE:
p.placeCostChanged(this.directoryKey, placeKey);
break;
}
} else {
logger.debug("No match for {} using pattern {}", placeKey, p.getPattern());
}
}
}
if (logger.isDebugEnabled()) {
logger.debug("Notified {} of {} place observers of place {} -- {} #all={}", matchcount, obcount, placeKey, action, this.observers.size());
}
}
}