/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2008-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.ovapi;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import org.opennms.nnm.swig.NNM;
import org.opennms.nnm.swig.OVsPMDCommand;
import org.opennms.nnm.swig.fd_set;
import org.opennms.nnm.swig.timeval;
public abstract class OVsDaemon {
Logger log = Logger.getLogger(getClass());
public abstract static class ScheduledTask implements Runnable {
long m_nextRuntimeInMillis = -1;
long m_period = 0;
public long getNextRuntimeMillis() {
return m_nextRuntimeInMillis;
}
public void setNextRuntimeMillis(long nextRunTimeMillis) {
m_nextRuntimeInMillis = nextRunTimeMillis;
}
public long getPeriod() {
return m_period;
}
public void setPeriod(long period) {
m_period = period;
}
public abstract void run();
public void setTimeout(long now, timeval tm) {
long remaining = (m_nextRuntimeInMillis - now);
if (remaining < tm.getTimeInMillis()) {
tm.setTimeInMillis(remaining);
}
}
public boolean isReady(long now) {
return now > m_nextRuntimeInMillis;
}
boolean setNextPeriod() {
if (!isPeriodic()) {
return false;
} else {
setNextRuntimeMillis(getNextRuntimeMillis()+getPeriod());
return true;
}
}
private boolean isPeriodic() {
return getPeriod() > 0;
}
}
static class DefaultOVsDaemon extends OVsDaemon {
protected String onInit() {
ScheduledTask statusReporter = new ScheduledTask() {
long m_lastRun = System.currentTimeMillis();
public void run() {
long now = System.currentTimeMillis();
setStatus("Timer run at "+now+" after " + (now - m_lastRun) + " millis. Period is "+getPeriod());
m_lastRun = now;
}
};
schedule(statusReporter, 10000, 20000);
return "DefaultOVsDaemon has finished initializing.";
}
protected String onStop() {
return "DefaultOVsDaemon has exited successfully.";
}
}
private int m_ovspmdFd;
private boolean m_finished = false;
private List<ScheduledTask> m_scheduledTasks = new LinkedList<ScheduledTask>();
private long m_selectedMillis;
protected abstract String onInit();
protected abstract String onStop();
public int getPmdFd() {
return m_ovspmdFd;
}
public void execute() {
int[] sp = new int[1];
if (NNM.OVsInit(sp) < 0) {
log("error calling OVsInit");
}
m_ovspmdFd = sp[0];
String initResponse = "";
int success = NNM.OVS_RSP_FAILURE;
try {
initResponse = onInit();
success = NNM.OVS_RSP_SUCCESS;
} catch (Throwable t) {
initResponse = "Exception occurred initializing "+this+": "+t;
log(initResponse, t);
}
if (initComplete(initResponse, success) < 0) {
log("error calling OVsInitComplete");
}
String callmsg;
try {
callmsg = (String)call();
} catch (Throwable t) {
callmsg = "Exception occurred calling "+this+": "+t;
log(callmsg, t);
}
if (NNM.OVsDone(callmsg) < 0) {
log("error occurred calling OVsDone");
}
}
private int initComplete(String initResponse, int success) {
log("OVsInitComlete("+initResponse+", \""+success+"\")");
return NNM.OVsInitComplete(success, initResponse);
}
public void setStatus(String message) {
log("OVsResponse(OVS_RSP_LAST_MSG, \""+message+"\")");
if (NNM.OVsResponse(NNM.OVS_RSP_LAST_MSG, message) < 0) {
log("error calling OVsResponse");
}
}
public int readPmdCmd() {
OVsPMDCommand command = new OVsPMDCommand();
if (NNM.OVsReceive(command) < 0) {
log("error calling OVsReceive");
}
return command.getCode();
}
boolean isFinished() {
return m_finished;
}
void setFinished(boolean finished) {
m_finished = finished;
}
public Object call() throws Exception {
long start = System.currentTimeMillis();
long end = start;
fd_set fdset = new fd_set();
timeval tm = new timeval();
while (!isFinished()) {
fdset.zero();
tm.setTimeInMillis(Integer.MAX_VALUE);
int maxFDs = getRetryInfo(fdset, tm);
m_selectedMillis = tm.getTimeInMillis();
long selectStart = System.currentTimeMillis();
int fds = NNM.select(maxFDs, fdset, null, null, tm);
long selectEnd = System.currentTimeMillis();
log("Returned from select after "+(selectEnd - selectStart)+" ms.");
if (fds > 0) {
processReads(fdset);
}
processTimeouts();
}
end = System.currentTimeMillis();
return onStop();
}
protected void processTimeouts() {
// we clone the list so we don't have concurrent modifications if tasks add new tasks
List<ScheduledTask> tasks = new LinkedList<ScheduledTask>(m_scheduledTasks);
long now = System.currentTimeMillis();
for(ScheduledTask task : tasks) {
if (task.isReady(now)) {
task.run();
if (task.setNextPeriod()) {
// reschedule it for next time
m_scheduledTasks.add(task);
}
}
}
}
protected void processReads(fd_set fdset) {
if (fdset.isSet(getPmdFd())) {
int code = readPmdCmd();
setStatus("Received cmd code "+code+" from pmd");
if (code == NNM.OVS_CMD_EXIT) {
setFinished(true);
}
}
}
public void schedule(ScheduledTask task, long delay) {
schedule(task, delay, 0);
}
public void schedule(ScheduledTask task, long delay, long period) {
task.setNextRuntimeMillis(System.currentTimeMillis()+delay);
task.setPeriod(period);
m_scheduledTasks.add(task);
}
protected int getRetryInfo(fd_set fdset, timeval tm) {
fdset.set(getPmdFd());
setTimeout(tm);
return getPmdFd()+1;
}
private void setTimeout(timeval tm) {
long now = System.currentTimeMillis();
for(ScheduledTask task : m_scheduledTasks) {
task.setTimeout(now, tm);
}
}
public void log(String msg) {
log.info(msg);
}
public synchronized void log(String msg, Throwable t) {
log.info(msg, t);
}
}