/* * This file is part of the OpenNMS(R) Application. * * OpenNMS(R) is Copyright (C) 2005-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 January 7, 2005 * * Copyright (C) 2005-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.net.InetAddress; import java.util.Date; import org.infosec.ismp.model.event.Event; import org.infosec.ismp.model.event.EventConstants; import org.infosec.ismp.model.poller.IPv4NetworkInterface; import org.infosec.ismp.model.poller.MonitoredService; import org.infosec.ismp.model.poller.NetworkInterface; import org.infosec.ismp.model.poller.PollStatus; import org.infosec.ismp.util.ThreadCategory; import org.infosec.ismp.util.scheduler.PostponeNecessary; import org.infosec.ismp.util.scheduler.ReadyRunnable; import org.infosec.ismp.util.scheduler.Schedule; /** * Represents a PollableService * * @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a> */ public class PollableService extends PollableElement implements ReadyRunnable, MonitoredService { private final class PollRunner implements Runnable { private volatile PollStatus m_pollStatus; @Override public void run() { doPoll(); getNode().processStatusChange(new Date()); m_pollStatus = getStatus(); } public PollStatus getPollStatus() { return m_pollStatus; } } private final String m_svcName; private final IPv4NetworkInterface m_netInterface; private volatile PollConfig m_pollConfig; private volatile PollStatus m_oldStatus; private volatile Schedule m_schedule; private volatile long m_statusChangeTime = 0L; /** * @param svcName * @param iface * */ public PollableService(PollableInterface iface, String svcName) { super(iface, Scope.SERVICE); m_svcName = svcName; m_netInterface = new IPv4NetworkInterface(iface.getAddress()); } public PollableInterface getInterface() { return (PollableInterface) getParent(); } public PollableNode getNode() { return getInterface().getNode(); } public PollableNetwork getNetwork() { return getInterface().getNetwork(); } @Override public PollContext getContext() { return getInterface().getContext(); } /** * @return */ @Override public String getSvcName() { return m_svcName; } /** * @return */ @Override public String getIpAddr() { return getInterface().getIpAddr(); } /** * @return */ @Override public int getNodeId() { return getInterface().getNodeId(); } @Override public String getNodeLabel() { return getInterface().getNodeLabel(); } @Override protected void visitThis(PollableVisitor v) { super.visitThis(v); v.visitService(this); } /** * @param pollConfig */ public void setPollConfig(PollableServiceConfig pollConfig) { m_pollConfig = pollConfig; } /** * */ @Override public PollStatus poll() { PollStatus newStatus = m_pollConfig.poll(); if (!newStatus.isUnknown()) { updateStatus(newStatus); } return getStatus(); } /** * @return * @throws UnknownHostException */ @Override public NetworkInterface getNetInterface() { return m_netInterface; } /** * @return */ @Override public InetAddress getAddress() { return getInterface().getAddress(); } /** * @return the top changed element whose status changes needs to be processed */ public PollStatus doPoll() { if (getContext().isNodeProcessingEnabled()) { return getParent().doPoll(this); } else { resetStatusChanged(); return poll(); } } @Override public Event createDownEvent(Date date) { return getContext().createEvent( EventConstants.NODE_LOST_SERVICE_EVENT_UEI, getNodeId(), getAddress(), getSvcName(), date, getStatus().getReason()); } @Override public Event createUpEvent(Date date) { return getContext().createEvent( EventConstants.NODE_REGAINED_SERVICE_EVENT_UEI, getNodeId(), getAddress(), getSvcName(), date, getStatus().getReason()); } public Event createUnresponsiveEvent(Date date) { return getContext().createEvent( EventConstants.SERVICE_UNRESPONSIVE_EVENT_UEI, getNodeId(), getAddress(), getSvcName(), date, getStatus().getReason()); } public Event createResponsiveEvent(Date date) { return getContext().createEvent( EventConstants.SERVICE_RESPONSIVE_EVENT_UEI, getNodeId(), getAddress(), getSvcName(), date, getStatus().getReason()); } // @Override // public void createOutage(PollEvent cause) { // super.createOutage(cause); // getContext().openOutage(this, cause); // } // // @Override // protected void resolveOutage(PollEvent resolution) { // super.resolveOutage(resolution); // getContext().resolveOutage(this, resolution); // } @Override public String toString() { return getInterface() + ":" + getSvcName(); } @Override public void processStatusChange(Date date) { if (getContext().isServiceUnresponsiveEnabled()) { if (isStatusChanged() && getStatus().equals(PollStatus.unresponsive())) { getContext().sendEvent(createUnresponsiveEvent(date)); if (m_oldStatus.equals(PollStatus.up())) resetStatusChanged(); } else if (isStatusChanged() && m_oldStatus.equals(PollStatus.unresponsive())) { getContext().sendEvent(createResponsiveEvent(date)); if (getStatus().equals(PollStatus.up())) resetStatusChanged(); } } super.processStatusChange(date); } @Override public void updateStatus(PollStatus newStatus) { if (!getContext().isServiceUnresponsiveEnabled()) { if (newStatus.equals(PollStatus.unresponsive())) newStatus = PollStatus.down(); } PollStatus currentStatus = getStatus(); if (!currentStatus.equals(newStatus)) { m_oldStatus = getStatus(); setStatusChangeTime(m_pollConfig.getCurrentTime()); } super.updateStatus(newStatus); if (!currentStatus.equals(newStatus)) { getSchedule().adjustSchedule(); } } /** * @param schedule */ public synchronized void setSchedule(Schedule schedule) { m_schedule = schedule; } public synchronized Schedule getSchedule() { return m_schedule; } public long getStatusChangeTime() { return m_statusChangeTime; } private void setStatusChangeTime(long statusChangeTime) { m_statusChangeTime = statusChangeTime; } @Override public boolean isReady() { /* FIXME: There is a bug in the Scheduler that only checks the first service in a queue. * If a thread hangs the below line will cause all services with the same interval to get * hang behind a service that is blocked if it has the same polling interval. The below would * be the optimal way to do it to promote fairness but... not for now. */ // return isTreeLockAvailable(); return true; } /* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { doRun(500); } public PollStatus doRun() { return doRun(0); } private PollStatus doRun(int timeout) { long startDate = System.currentTimeMillis(); log().debug("Start Scheduled Poll of service " + this); PollStatus status; if (getContext().isNodeProcessingEnabled()) { PollRunner r = new PollRunner(); try { withTreeLock(r, timeout); } catch (LockUnavailable e) { log().info("Postponing poll for " + this + " because " + e); throw new PostponeNecessary("LockUnavailable postpone poll"); } status = r.getPollStatus(); } else { doPoll(); processStatusChange(new Date()); status = getStatus(); } if (log().isDebugEnabled()) log().debug( "Finish Scheduled Poll of service " + this + ", started at " + new Date(startDate)); return status; } private ThreadCategory log() { return ThreadCategory.getInstance(PollableService.class); } @Override public void delete() { Runnable r = new Runnable() { @Override public void run() { PollableService.super.delete(); m_schedule.unschedule(); } }; withTreeLock(r); } /** * */ public void schedule() { if (m_schedule == null) throw new IllegalStateException( "Cannot schedule a service whose schedule is set to null"); m_schedule.schedule(); } /** * */ public void sendDeleteEvent() { getContext().sendEvent( getContext().createEvent( EventConstants.DELETE_SERVICE_EVENT_UEI, getNodeId(), getAddress(), getSvcName(), new Date(), getStatus().getReason())); } public void refreshConfig() { m_pollConfig.refresh(); } public void refreshThresholds() { m_pollConfig.refreshThresholds(); } }