/* * This file is part of the OpenNMS(R) Application. * * OpenNMS(R) is Copyright (C) 2004-2006 The OpenNMS Group, Inc. All rights reserved. * OpenNMS(R) is a derivative work, containing both original code, included code and modified * code that was published under the GNU General Public License. Copyrights for modified * and included code are below. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * Modifications: * * Created December 31, 2004 * * Copyright (C) 2004-2006 The OpenNMS Group, Inc. All rights reserved. * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information contact: * OpenNMS Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ */ package org.infosec.ismp.poller.pollable; 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.infosec.ismp.model.poller.PollStatus; /** * Represents a PollableContainer * * @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a> */ abstract public class PollableContainer extends PollableElement { private final Map<Object, PollableElement> m_members = new HashMap<Object, PollableElement>(); public PollableContainer(PollableContainer parent, Scope scope) { super(parent, scope); } /** * @param integer * @return */ protected synchronized PollableElement getMember(Object key) { return m_members.get(key); } protected synchronized int getMemberCount() { return m_members.size(); } protected synchronized Collection<PollableElement> getMembers() { return new ArrayList<PollableElement>(m_members.values()); } /** * @param member * @return */ abstract protected Object createMemberKey(PollableElement member); /** * @param node */ protected synchronized void addMember(PollableElement member) { Object key = createMemberKey(member); m_members.put(key, member); } public synchronized void removeMember(PollableElement member) { Object key = createMemberKey(member); m_members.remove(key); } public void deleteMember(PollableElement member) { removeMember(member); if (m_members.size() == 0) this.delete(); } @Override public void delete() { Runnable r = new Runnable() { @Override 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); } @Override public void visit(PollableVisitor v) { visitThis(v); visitMembers(v); } @Override protected void visitThis(PollableVisitor v) { super.visitThis(v); v.visitContainer(this); } /** * @param v */ 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); } @Override public void forEachElement(PollableElement element) { setResult(processNextMember(element, getResult())); } abstract T processNextMember(PollableElement member, T currentValue); } protected void forEachMember(Iter iter) { forEachMember(false, iter); } protected <T> T deriveValueFromMembers(SimpleIter<T> iter) { return deriveValueFromMembers(false, iter); } protected <T> T deriveValueFromMembers(boolean withTreeLock, SimpleIter<T> iter) { forEachMember(withTreeLock, iter); return iter.getResult(); } protected void forEachMember(boolean withTreeLock, final Iter iter) { Runnable r = new Runnable() { @Override 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(); } } @Override public void recalculateStatus() { Runnable r = new Runnable() { @Override public void run() { SimpleIter<PollStatus> iter = new SimpleIter<PollStatus>( PollStatus.down()) { @Override public void forEachElement(PollableElement elem) { elem.recalculateStatus(); if (elem.getStatus().isUp()) setResult(PollStatus.up()); } }; forEachMember(iter); updateStatus(iter.getResult()); } }; withTreeLock(r); } @Override public void resetStatusChanged() { Runnable r = new Runnable() { @Override public void run() { PollableContainer.super.resetStatusChanged(); Iter iter = new Iter() { @Override 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; } @Override protected PollStatus poll(final PollableElement elem) { final PollStatus retVal[] = new PollStatus[1]; Runnable r = new Runnable() { @Override 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]; } /** * @param member * @return */ public PollStatus pollRemainingMembers(final PollableElement member) { SimpleIter<PollStatus> iter = new SimpleIter<PollStatus>( member.getStatus()) { @Override public void forEachElement(PollableElement elem) { if (elem != member) { if (elem.poll().isUp()) setResult(PollStatus.up()); } } }; forEachMember(iter); return iter.getResult(); } public PollStatus getMemberStatus() { SimpleIter<PollStatus> iter = new SimpleIter<PollStatus>( PollStatus.down()) { @Override public void forEachElement(PollableElement elem) { if (elem.getStatus().isUp()) setResult(PollStatus.up()); } }; forEachMember(iter); return iter.getResult(); } @Override public PollStatus poll() { PollableElement leaf = selectPollElement(); if (leaf == null) return PollStatus.up(); return poll(leaf); } /** * @return */ @Override public PollableElement selectPollElement() { if (getMemberCount() == 0) return null; PollableElement member = getMembers().iterator().next(); return member.selectPollElement(); } @Override public void processStatusChange(final Date date) { Runnable r = new Runnable() { @Override public void run() { if (isStatusChanged()) { PollableContainer.super.processStatusChange(date); } else if (getStatus().isUp()) { processMemberStatusChanges(date); } } }; withTreeLock(r); } public void processMemberStatusChanges(final Date date) { Iter iter = new Iter() { @Override public void forEachElement(PollableElement elem) { elem.processStatusChange(date); } }; forEachMember(iter); } @Override 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() { @Override public void forEachElement(PollableElement elem) { elem.processLingeringCauses(resolvedCause, resolution); } }; forEachMember(iter); } @Override protected void processCause(final PollEvent cause) { super.processCause(cause); Iter iter = new Iter() { @Override public void forEachElement(PollableElement elem) { elem.processCause(cause); } }; forEachMember(iter); } @Override protected void resolveAllOutages(final PollEvent resolvedCause, final PollEvent resolution) { super.resolveAllOutages(resolvedCause, resolution); Iter iter = new Iter() { @Override public void forEachElement(PollableElement elem) { if (!hasOpenOutage()) elem.resolveAllOutages(resolvedCause, resolution); } }; forEachMember(iter); } @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; } @Override protected void doInheritParentalCause() { super.doInheritParentalCause(); for (PollableElement member : getMembers()) { member.inheritParentalCause(); } } }