package hudson.plugins.im;
import hudson.model.Computer;
import hudson.model.Executor;
import hudson.model.Hudson;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.listeners.RunListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
@SuppressWarnings("unchecked")
public class HudsonIsBusyListener extends RunListener {
private static final Logger LOGGER = Logger.getLogger(HudsonIsBusyListener.class.getName());
private static HudsonIsBusyListener INSTANCE;
private transient final List<IMConnectionProvider> connectionProviders = new ArrayList<IMConnectionProvider>();
private transient final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private transient int lastBusyExecutors = -1;
private transient int lastTotalExecutors = -1;
private final Runnable updateRunner = new Runnable() {
@Override
public void run() {
updateIMStatus();
}
};
public static synchronized HudsonIsBusyListener getInstance() {
if (INSTANCE == null) {
INSTANCE = new HudsonIsBusyListener();
// registration via @Extension didn't seem to work!
// Have to retry it sometime.
INSTANCE.register();
}
return INSTANCE;
}
private HudsonIsBusyListener() {
super(Run.class);
this.executor.scheduleAtFixedRate(this.updateRunner, 10, 60, TimeUnit.SECONDS);
LOGGER.info("Executor busy listener created");
}
public synchronized void addConnectionProvider(IMConnectionProvider provider) {
this.connectionProviders.add(provider);
LOGGER.fine("Added connection provider: " + provider);
}
public synchronized void removeConnectionProvider(IMConnectionProvider provider) {
this.connectionProviders.remove(provider);
LOGGER.fine("Removed connection provider: " + provider);
if (this.connectionProviders.isEmpty()) {
LOGGER.info("Last connection provider removed. Unregistering this instance.");
unregister();
INSTANCE = null;
}
}
@Override
public void onCompleted(Run r, TaskListener listener) {
updateLater();
}
@Override
public void onDeleted(Run r) {
updateLater();
}
@Override
public void onStarted(Run r, TaskListener listener) {
updateLater();
}
private void updateLater() {
// schedule update 1 second into the future
// otherwise calculation is often incorrect
this.executor.schedule(new Runnable() {
@Override
public void run() {
updateIMStatus();
}
}, 1L, TimeUnit.SECONDS);
}
private synchronized void updateIMStatus() {
int totalExecutors = getTotalExecutors();
int busyExecutors = getBusyExecutors();
if (totalExecutors != this.lastTotalExecutors || busyExecutors != this.lastBusyExecutors) {
for (IMConnectionProvider provider : connectionProviders) {
setStatus(provider, busyExecutors, totalExecutors);
}
}
this.lastTotalExecutors = totalExecutors;
this.lastBusyExecutors = busyExecutors;
}
private void setStatus(IMConnectionProvider provider, int busyExecutors, int totalExecutors) {
try {
IMConnection conn = provider.currentConnection();
if (busyExecutors == 0) {
conn.setPresence(IMPresence.AVAILABLE, "Yawn, I'm so bored. Don't you have some work for me?");
} else if (busyExecutors == totalExecutors) {
conn.setPresence(IMPresence.DND,
"Please give me some rest! All " + totalExecutors + " executors are busy, "
+ Hudson.getInstance().getQueue().getItems().length + " job(s) in queue.");
} else {
String msg = "Working: " + busyExecutors + " out of " + totalExecutors +
" executors are busy.";
int queueItems = Hudson.getInstance().getQueue().getItems().length;
if (queueItems > 0) {
msg += " " + queueItems + " job(s) in queue.";
}
conn.setPresence(IMPresence.OCCUPIED, msg);
}
} catch (IMException e) {
// ignore
}
}
private int getBusyExecutors() {
int busyExecutors = 0;
//boolean stillRunningExecutorFound = false;
Computer[] computers = Hudson.getInstance().getComputers();
for (Computer compi : computers) {
for (Executor executor : compi.getExecutors()) {
if (executor.isBusy()) {
busyExecutors++;
}
}
}
return busyExecutors;
}
private int getTotalExecutors() {
int totalExecutors = 0;
Computer[] computers = Hudson.getInstance().getComputers();
for (Computer compi : computers) {
if (compi.isOnline()) {
totalExecutors += compi.getNumExecutors();
}
}
return totalExecutors;
}
}