package org.hyperic.hq.notifications.filtering;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.notifications.DefaultEndpoint;
import org.hyperic.hq.notifications.NotificationEndpoint;
import org.hyperic.hq.notifications.model.BaseNotification;
public abstract class DestinationEvaluator<N extends BaseNotification> {
private final Log log = LogFactory.getLog(DestinationEvaluator.class);
// TODO~ change to write through versioning (each node would have versioning - write on one version, read another,
// then sync between them), o/w will pose problems in scale
protected Map<NotificationEndpoint,FilterChain<N>> destToFilter = new HashMap<NotificationEndpoint,FilterChain<N>>();
protected abstract FilterChain<N> instantiateFilterChain(Collection<Filter<N,? extends FilteringCondition<?>>> filters);
/**
* append filters
*
* @param dest
* @param filters
*/
public void register(NotificationEndpoint endpoint, Collection<Filter<N,? extends FilteringCondition<?>>> filters) {
if (filters == null || filters.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("no filters were passed to be registered with destination " + endpoint);
}
}
synchronized (destToFilter) {
FilterChain<N> filterChain = destToFilter.get(endpoint);
if (filterChain==null) {
filterChain = instantiateFilterChain(filters);
destToFilter.put(endpoint, filterChain);
if (log.isDebugEnabled()) {
log.debug("registering the following filters to destination " + endpoint +
" (no previous filters were assigned to it):\n" + filters);
}
} else {
filterChain.addAll(filters);
if (log.isDebugEnabled()) {
log.debug("appending the following filters to destination " + endpoint + ":\n" + filters);
}
}
}
}
/**
* unregister all filters assigned to this destination
* @param dest
*/
public void unregisterAll(NotificationEndpoint endpoint) {
FilterChain<N> filterChain = null;
synchronized (destToFilter) {
filterChain = destToFilter.remove(endpoint);
}
if (log.isDebugEnabled()) {
if (filterChain == null) {
log.debug("no filters were previously registered with destination " + endpoint);
} else {
// TODO~ remove all filter chain filters from it
log.debug("un-registering all previously regitered filters from destination " + endpoint + ":\n" + filterChain);
}
}
}
public FilterChain<N> getRegistration(String registrationID) {
FilterChain<N> filterChain = destToFilter.get(new DefaultEndpoint(registrationID));
return filterChain;
}
/**
*
* @param dest
* @param filters
*/
public void unregister(NotificationEndpoint endpoint, List<Filter<N,? extends FilteringCondition<?>>> filters) {
if (filters==null || filters.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("no filters were passed to be un-registered from endpoint " + endpoint);
}
return;
}
synchronized (destToFilter) {
FilterChain<N> filterChain = destToFilter.get(endpoint);
if (filterChain==null) {
if (log.isDebugEnabled()) {
log.debug("no filters were previously registered with endpoint " + endpoint);
}
} else {
filterChain.removeAll(filters);
if (log.isDebugEnabled()) {
log.debug("un-registering the following filters from endpoint " + endpoint + ":\n" + filters);
}
if (filterChain.isEmpty()) {
destToFilter.remove(endpoint);
if (log.isDebugEnabled()) {
log.debug("un-registering the following endpoint " + endpoint);
}
}
}
}
}
public Map<NotificationEndpoint, Collection<N>> evaluate(List<N> entities) {
final Map<NotificationEndpoint, Collection<N>> rtn = new HashMap<NotificationEndpoint, Collection<N>>();
final Map<NotificationEndpoint, FilterChain<N>> tmp;
synchronized (destToFilter) {
tmp = new HashMap<NotificationEndpoint, FilterChain<N>>(destToFilter);
}
for (final Entry<NotificationEndpoint,FilterChain<N>> entry : tmp.entrySet()) {
final FilterChain<N> filterChain = entry.getValue();
final Collection<N> filteredEntities = ((Collection<N>) filterChain.filter(entities));
if (filteredEntities != null && !filteredEntities.isEmpty()) {
final NotificationEndpoint endpoint = entry.getKey();
Collection<N> list = rtn.get(endpoint);
if (list == null) {
list = new ArrayList<N>();
rtn.put(endpoint, list);
}
list.addAll(filteredEntities);
}
}
Set<N> set = new HashSet<N>();
for (Entry<NotificationEndpoint, Collection<N>> entry : rtn.entrySet()) {
Collection<N> values = entry.getValue();
for (N v : values) {
boolean added = set.add(v);
if (!added) {
log.debug(v);
}
}
}
return rtn;
}
}