/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2006-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.poller.pollables; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.opennms.netmgt.model.PollStatus; /** * Represents a PollableContainer * * @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a> * @version $Id: $ */ abstract public class PollableContainer extends PollableElement { private final Map<Object, PollableElement> m_members = new HashMap<Object, PollableElement>(); /** * <p>Constructor for PollableContainer.</p> * * @param parent a {@link org.opennms.netmgt.poller.pollables.PollableContainer} object. * @param scope a {@link org.opennms.netmgt.poller.pollables.Scope} object. */ public PollableContainer(PollableContainer parent, Scope scope) { super(parent, scope); } /** * <p>getMember</p> * * @param key a {@link java.lang.Object} object. * @return a {@link org.opennms.netmgt.poller.pollables.PollableElement} object. */ protected synchronized PollableElement getMember(Object key) { return m_members.get(key); } /** * <p>getMemberCount</p> * * @return a int. */ protected synchronized int getMemberCount() { return m_members.size(); } /** * <p>getMembers</p> * * @return a {@link java.util.Collection} object. */ protected synchronized Collection<PollableElement> getMembers() { return new ArrayList<PollableElement>(m_members.values()); } /** * <p>createMemberKey</p> * * @param member a {@link org.opennms.netmgt.poller.pollables.PollableElement} object. * @return a {@link java.lang.Object} object. */ abstract protected Object createMemberKey(PollableElement member); /** * <p>addMember</p> * * @param member a {@link org.opennms.netmgt.poller.pollables.PollableElement} object. */ protected synchronized void addMember(PollableElement member) { Object key = createMemberKey(member); m_members.put(key, member); } /** * <p>removeMember</p> * * @param member a {@link org.opennms.netmgt.poller.pollables.PollableElement} object. */ public synchronized void removeMember(PollableElement member) { Object key = createMemberKey(member); m_members.remove(key); } /** * <p>deleteMember</p> * * @param member a {@link org.opennms.netmgt.poller.pollables.PollableElement} object. */ public void deleteMember(PollableElement member) { removeMember(member); if (m_members.size() == 0) this.delete(); } /** * <p>delete</p> */ public void delete() { Runnable r = new Runnable() { public void run() { Collection<PollableElement> members = getMembers(); for (Iterator<PollableElement> it = members.iterator(); it.hasNext();) { PollableElement member = it.next(); member.delete(); } PollableContainer.super.delete(); } }; withTreeLock(r); } /** {@inheritDoc} */ public void visit(PollableVisitor v) { visitThis(v); visitMembers(v); } /** {@inheritDoc} */ protected void visitThis(PollableVisitor v) { super.visitThis(v); v.visitContainer(this); } /** * <p>visitMembers</p> * * @param v a {@link org.opennms.netmgt.poller.pollables.PollableVisitor} object. */ protected void visitMembers(PollableVisitor v) { for (Iterator<PollableElement> it = getMembers().iterator(); it.hasNext();) { PollableElement element = it.next(); element.visit(v); } } protected interface Iter { public void forEachElement(PollableElement element); } abstract protected class SimpleIter<T> implements Iter { private T result; public SimpleIter(T initial) { result = initial; } public SimpleIter() { this(null); } public T getResult() { return result; } public void setResult(T newResult) { result = newResult; } } abstract protected class Accumulator<T> extends SimpleIter<T> { public Accumulator(T initial) { super(initial); } public Accumulator() { super(null); } public void forEachElement(PollableElement element) { setResult(processNextMember(element, getResult())); } abstract T processNextMember(PollableElement member, T currentValue); } /** * <p>forEachMember</p> * * @param iter a {@link org.opennms.netmgt.poller.pollables.PollableContainer.Iter} object. */ protected void forEachMember(Iter iter) { forEachMember(false, iter); } /** * <p>deriveValueFromMembers</p> * * @param iter a {@link org.opennms.netmgt.poller.pollables.PollableContainer.SimpleIter} object. * @param <T> a T object. * @return a T object. */ protected <T> T deriveValueFromMembers(SimpleIter<T> iter) { return deriveValueFromMembers(false, iter); } /** * <p>deriveValueFromMembers</p> * * @param withTreeLock a boolean. * @param iter a {@link org.opennms.netmgt.poller.pollables.PollableContainer.SimpleIter} object. * @param <T> a T object. * @return a T object. */ protected <T> T deriveValueFromMembers(boolean withTreeLock, SimpleIter<T> iter) { forEachMember(withTreeLock, iter); return iter.getResult(); } /** * <p>forEachMember</p> * * @param withTreeLock a boolean. * @param iter a {@link org.opennms.netmgt.poller.pollables.PollableContainer.Iter} object. */ protected void forEachMember(boolean withTreeLock, final Iter iter) { Runnable r = new Runnable() { public void run() { for (Iterator<PollableElement> it = getMembers().iterator(); it.hasNext(); ) { PollableElement element = it.next(); iter.forEachElement(element); } } }; if (withTreeLock) { withTreeLock(r); } else { r.run(); } } /** * <p>recalculateStatus</p> */ public void recalculateStatus() { Runnable r = new Runnable() { public void run() { SimpleIter<PollStatus> iter = new SimpleIter<PollStatus>(PollStatus.down()) { public void forEachElement(PollableElement elem) { elem.recalculateStatus(); if (elem.getStatus().isUp()) setResult(PollStatus.up()); } }; forEachMember(iter); updateStatus(iter.getResult()); } }; withTreeLock(r); } /** * <p>resetStatusChanged</p> */ public void resetStatusChanged() { Runnable r = new Runnable() { public void run() { PollableContainer.super.resetStatusChanged(); Iter iter = new Iter() { public void forEachElement(PollableElement elem) { elem.resetStatusChanged(); } }; forEachMember(iter); } }; withTreeLock(r); } PollableElement findMemberWithDescendent(PollableElement elem) { PollableElement member = elem; while (member != null && member.getParent() != this) { member = member.getParent(); } return member; } /** {@inheritDoc} */ protected PollStatus poll(final PollableElement elem) { final PollStatus retVal[] = new PollStatus[1]; Runnable r = new Runnable() { public void run() { PollableElement member = findMemberWithDescendent(elem); PollStatus memberStatus = member.poll(elem); if (memberStatus.isUp() != getStatus().isUp() && member.isStatusChanged()) { updateStatus(pollRemainingMembers(member)); } retVal[0] = getStatus(); } }; elem.withTreeLock(r); return retVal[0]; } /** * <p>pollRemainingMembers</p> * * @param member a {@link org.opennms.netmgt.poller.pollables.PollableElement} object. * @return a {@link org.opennms.netmgt.model.PollStatus} object. */ public PollStatus pollRemainingMembers(final PollableElement member) { SimpleIter<PollStatus> iter = new SimpleIter<PollStatus>(member.getStatus()) { public void forEachElement(PollableElement elem) { if (elem != member) { if (elem.poll().isUp()) setResult(PollStatus.up()); } } }; forEachMember(iter); return iter.getResult(); } /** * <p>getMemberStatus</p> * * @return a {@link org.opennms.netmgt.model.PollStatus} object. */ public PollStatus getMemberStatus() { SimpleIter<PollStatus> iter = new SimpleIter<PollStatus>(PollStatus.down()) { public void forEachElement(PollableElement elem) { if (elem.getStatus().isUp()) setResult(PollStatus.up()); } }; forEachMember(iter); return iter.getResult(); } /** * <p>poll</p> * * @return a {@link org.opennms.netmgt.model.PollStatus} object. */ public PollStatus poll() { PollableElement leaf = selectPollElement(); if (leaf == null) return PollStatus.up(); return poll(leaf); } /** * <p>selectPollElement</p> * * @return a {@link org.opennms.netmgt.poller.pollables.PollableElement} object. */ public PollableElement selectPollElement() { if (getMemberCount() == 0) return null; PollableElement member = (PollableElement)getMembers().iterator().next(); return member.selectPollElement(); } /** {@inheritDoc} */ public void processStatusChange(final Date date) { Runnable r = new Runnable() { public void run() { if (isStatusChanged()) { PollableContainer.super.processStatusChange(date); } else if (getStatus().isUp()) { processMemberStatusChanges(date); } } }; withTreeLock(r); } /** * <p>processMemberStatusChanges</p> * * @param date a {@link java.util.Date} object. */ public void processMemberStatusChanges(final Date date) { Iter iter = new Iter() { public void forEachElement(PollableElement elem) { elem.processStatusChange(date); } }; forEachMember(iter); } /** {@inheritDoc} */ protected void processResolution(PollEvent resolvedCause, PollEvent resolution) { super.processResolution(resolvedCause, resolution); processLingeringMemberCauses(resolvedCause, resolution); } private void processLingeringMemberCauses(final PollEvent resolvedCause, final PollEvent resolution) { Iter iter = new Iter() { public void forEachElement(PollableElement elem) { elem.processLingeringCauses(resolvedCause, resolution); } }; forEachMember(iter); } /** {@inheritDoc} */ protected void processCause(final PollEvent cause) { super.processCause(cause); Iter iter = new Iter() { public void forEachElement(PollableElement elem) { elem.processCause(cause); } }; forEachMember(iter); } /** {@inheritDoc} */ protected void resolveAllOutages(final PollEvent resolvedCause, final PollEvent resolution) { super.resolveAllOutages(resolvedCause, resolution); Iter iter = new Iter() { public void forEachElement(PollableElement elem) { if (!hasOpenOutage()) elem.resolveAllOutages(resolvedCause, resolution); } }; forEachMember(iter); } /** {@inheritDoc} */ @Override protected PollEvent doExtrapolateCause() { // find the member cause with the largest scope PollEvent cause = extrapolateMemberCauseWithLargestScope(); // use this largest scope as the cause for the container setCause(cause); if (cause != null) { // we must be down set set status appropriately updateStatus(PollStatus.down()); } // return the cause to parent container return cause; } private PollEvent extrapolateMemberCauseWithLargestScope() { PollEvent cause = null; for(PollableElement member : getMembers()) { PollEvent memberCause = member.extrapolateCause(); if (memberCause != null && !memberCause.hasScopeSmallerThan(getScope())) { // a cause has been found that exceeds the scope of the members // choose between the current scope and the newly found scope be taking // the cause with the largest scope cause = PollEvent.withLargestScope(cause, memberCause); } } return cause; } /** {@inheritDoc} */ @Override protected void doInheritParentalCause() { super.doInheritParentalCause(); for(PollableElement member : getMembers()) { member.inheritParentalCause(); } } }