package ControllerWorker; import java.io.IOException; import java.lang.Thread; import java.util.concurrent.ExecutionException; import java.util.Date; import java.util.HashMap; import java.util.StringTokenizer; import java.util.Vector; import org.gearman.client.GearmanClient; import org.gearman.client.GearmanClientImpl; import org.gearman.client.GearmanJob; import org.gearman.client.GearmanJobImpl; import org.gearman.client.GearmanJobResult; import org.gearman.client.GearmanJobStatus; import org.gearman.common.GearmanJobServerConnection; import org.gearman.common.GearmanNIOJobServerConnection; import org.gearman.util.ByteUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONValue; public class Shutdown extends Thread { private long beginTime; private long timeTaken; private long timeLeft; private Boolean finished; private Boolean error; private final int updateRate; private final long updatePeriod; private long waitTime; private String[] statusText; private HashMap pingJobs; private HashMap whoJobs; private HashMap doShutdownJobs; private HashMap pingShutdownJobs; private HashMap psJobs; private HashMap status; private HashMap errors; private HashMap pingShutdownTime; private Vector psWhitelist; private Vector psBlacklist; private Vector> clients; private final GearmanJobServerConnection gearmanConnection; private GearmanClient gearmanClient; public Shutdown(String serverAddress, int port, Vector> clients, int updateRate, long waitTime, Vector psWhitelist, Vector psBlacklist) { this.pingJobs = new HashMap(); this.whoJobs = new HashMap(); this.doShutdownJobs = new HashMap(); this.pingShutdownJobs = new HashMap(); this.psJobs = new HashMap(); this.status = new HashMap(); this.errors = new HashMap(); this.pingShutdownTime = new HashMap(); this.psWhitelist = psWhitelist; this.psBlacklist = psBlacklist; this.updateRate = updateRate; // updates per second this.updatePeriod = 1000000000L / this.updateRate; // nanoseconds this.gearmanConnection = new GearmanNIOJobServerConnection( serverAddress, port); this.gearmanClient = new GearmanClientImpl(); gearmanClient.addJobServer(this.gearmanConnection); this.waitTime = waitTime * 1000; this.clients = clients; for (HashMap client : clients) { int clientID = Integer.parseInt(client.get("id")); status.put(clientID, 0); // no work } this.finished = false; this.error = false; this.statusText = new String[14]; this.statusText[0] = "The shutdown process of the client has been started."; this.statusText[1] = "The ping has been started."; this.statusText[2] = "The client is alive."; this.statusText[3] = "The check if a user is logged in has been started."; this.statusText[4] = "No user is logged in."; this.statusText[5] = "A shutdown of the client has been triggered."; this.statusText[6] = "The shutdown command has been sent."; this.statusText[7] = "The ping after shutdown has been started."; this.statusText[8] = "Doing ping after shutdown again and again, until client is not alive or two minutes has been elapsed"; this.statusText[9] = "A user is logged in."; this.statusText[10] = "The check if the user is working has been started."; this.statusText[11] = "The user is working."; this.statusText[12] = "Shutdown of the client has not been finished, due to an error."; this.statusText[13] = "Shutdown of the client has been finished."; } public void run() { workerLoop(); } private void workerLoop() { Boolean run = true; while (run) { try { beginTime = System.nanoTime(); run = update(); timeTaken = System.nanoTime() - beginTime; timeLeft = (updatePeriod - timeTaken) / 1000000; if (timeLeft < 10) timeLeft = 10; Thread.sleep(timeLeft); } catch (Exception e) { e.printStackTrace(); } } this.finished = true; } private Boolean update() throws IllegalStateException, IOException, InterruptedException, ExecutionException { Boolean allFinished = false; for (HashMap client : clients) { String ipAddress = client.get("ip"); int clientID = Integer.parseInt(client.get("id")); int clientStatus = status.get(clientID); switch (clientStatus) { case 0: ping(client); break; case 1: GearmanJob pingJob = pingJobs.get(clientID); if (pingJob != null) { GearmanJobStatus jobStatus = gearmanClient .getJobStatus(pingJob); if (!jobStatus.isKnown() && pingJob.isDone()) { GearmanJobResult pingJobRes = pingJob.get(); String result = ByteUtils.fromUTF8Bytes(pingJobRes .getResults()); if (!result.isEmpty()) { JSONObject resultObj = (JSONObject) JSONValue .parse(result); if (!resultObj.containsKey("err")) { String alive = resultObj.get("alive") .toString(); if (alive.equals("true")) { System.out.println(ipAddress + " alive"); status.put(clientID, 2); // alive, check // Users pingJobs.remove(clientID); } else if (alive.equals("false")) { System.out .println(ipAddress + " not alive"); // not alive, go in successState status.put(clientID, 13); pingJobs.remove(clientID); } } else { System.out.println(ipAddress + " Cannot send the ping message."); this.errors .put(clientID, "Sending the ping message has been failed."); // sending the ping message has been failed status.put(clientID, 12); pingJobs.remove(clientID); } } } } break; case 2: who(client); break; case 3: GearmanJob whoJob = whoJobs.get(clientID); if (whoJob != null) { GearmanJobStatus jobStatus = gearmanClient .getJobStatus(whoJob); if (!jobStatus.isKnown() && whoJob.isDone()) { GearmanJobResult whoJobRes = whoJob.get(); String result = ByteUtils.fromUTF8Bytes(whoJobRes .getResults()); if (!result.isEmpty()) { JSONObject resultObj = (JSONObject) JSONValue .parse(result); if (!resultObj.containsKey("err")) { String rawoutput = resultObj.get("rawoutput") .toString(); StringTokenizer str = new StringTokenizer( rawoutput, " "); String user = ""; if (str.hasMoreTokens()) { user = str.nextToken(); } if (user.isEmpty()) { System.out.println(ipAddress + " no user is logged in"); // no user is logged in status.put(clientID, 4); whoJobs.remove(clientID); } else { System.out.println(ipAddress + " a user is logged in"); // a user is logged in status.put(clientID, 9); whoJobs.remove(clientID); } } else { System.out .println(ipAddress + " Cannot check if a user is logged in."); this.errors .put(clientID, "The check if a user is logged in has been failed."); /* * cannot check if a user is logged in, go in * errorState */ status.put(clientID, 12); whoJobs.remove(clientID); } } } } break; case 4: doShutdown(client); break; case 5: GearmanJob doShutdownJob = doShutdownJobs.get(clientID); if (doShutdownJob != null) { GearmanJobStatus jobStatus = gearmanClient .getJobStatus(doShutdownJob); if (!jobStatus.isKnown() && doShutdownJob.isDone()) { GearmanJobResult wolJobRes = doShutdownJob.get(); String result = ByteUtils.fromUTF8Bytes(wolJobRes .getResults()); if (!result.isEmpty()) { JSONObject resultObj = (JSONObject) JSONValue .parse(result); if (!resultObj.containsKey("err")) { System.out.println(ipAddress + " Shutdown command send"); status.put(clientID, 6); // shutdown command // send doShutdownJobs.remove(clientID); } else { System.out.println(ipAddress + " Cannot send shutdown command"); this.errors .put(clientID, "Sending the shutdown command has been failed."); /* * cannot send shutdown command, go in / * errorState */ status.put(clientID, 12); doShutdownJobs.remove(clientID); } } } } break; case 6: Date date = new Date(); Long timestamp = date.getTime(); pingShutdownTime.put(clientID, timestamp); status.put(clientID, 7); // ping after shutdown break; case 7: pingShutdown(client); break; case 8: GearmanJob pingJobShutdown = pingShutdownJobs.get(clientID); if (pingJobShutdown != null) { Date currentDate = new Date(); Long currentTimestamp = currentDate.getTime(); // wait 2 min until shutdown Long expectedTimestamp = this.pingShutdownTime .get(clientID) + waitTime; if (expectedTimestamp >= currentTimestamp) { GearmanJobStatus jobStatus = gearmanClient .getJobStatus(pingJobShutdown); if (!jobStatus.isKnown() && pingJobShutdown.isDone()) { GearmanJobResult pingJobRes = pingJobShutdown.get(); String result = ByteUtils.fromUTF8Bytes(pingJobRes .getResults()); if (!result.isEmpty()) { JSONObject resultObj = (JSONObject) JSONValue .parse(result); if (!resultObj.containsKey("err")) { String alive = resultObj.get("alive") .toString(); if (alive.equals("false")) { System.out .println(ipAddress + " is not alive after shutdown"); // not alive, go in successState status.put(clientID, 13); pingShutdownJobs.remove(clientID); } else if (alive.equals("true")) { System.out .println(ipAddress + " is still alive after shutdown"); // still alive, ping again status.put(clientID, 7); } } else { System.out .println(ipAddress + " Cannot send the ping after shutdown message."); this.errors .put(clientID, "Sending the ping after shutdown message has been failed."); /* * sending the ping after shutdown message * has been failed */ status.put(clientID, 12); pingJobs.remove(clientID); } } } } else { System.out.println(ipAddress + " is alive after shutdown"); this.errors.put(clientID, "Client is still alive after shutdown."); // still alive, go in errorState status.put(clientID, 12); pingShutdownJobs.remove(clientID); } } break; case 9: ps(client); break; case 10: GearmanJob psJob = psJobs.get(clientID); if (psJob != null) { GearmanJobStatus jobStatus = gearmanClient .getJobStatus(psJob); if (!jobStatus.isKnown() && psJob.isDone()) { GearmanJobResult whoJobRes = psJob.get(); String result = ByteUtils.fromUTF8Bytes(whoJobRes .getResults()); if (!result.isEmpty()) { JSONObject resultObj = (JSONObject) JSONValue .parse(result); if (!resultObj.containsKey("err")) { JSONArray ps = (JSONArray) resultObj.get("ps"); boolean whitelistFound = false; boolean blacklistFound = false; for (String blackEntry : psBlacklist) { if (ps.toString().contains(blackEntry)) { blacklistFound = true; } } for (String whiteEntry : psWhitelist) { if (ps.toString().contains(whiteEntry)) { whitelistFound = true; } } // LOGIC_TESTS /* * System.out.println("######"); * System.out.println("######"); * System.out.println("firefox: " + * ps.toString().contains("firefox-bin")); // * browser firefox * System.out.println("chromium: " + * ps.toString().contains("chromium-browse")); * // browser chromium * System.out.println("email: " + * ps.toString().contains("thunderbird-bi")); // * email System.out.println("pdf-viewer: " + * ps.toString().contains("evince")); // * pdf-viewer System.out.println("office: " + * ps.toString().contains("soffice.bin")); // * office System.out.println("eclipse: " + * ps.toString().contains("eclipse")); // * eclipse System.out.println("######"); * System.out.println("gnome screensaver: " + * ps.toString().contains("gnome-screensav")); * // gnome screensaver * System.out.println("kde screensaver: " + * ps.toString().contains("Kscreensaver")); // * kde screensaver System.out.println("######"); */ if (blacklistFound) { System.out.println(ipAddress + " is working"); status.put(clientID, 11); // is working psJobs.remove(clientID); } else if (whitelistFound) { System.out.println(ipAddress + " is not working"); status.put(clientID, 4); // is not working psJobs.remove(clientID); } } else { System.out.println(ipAddress + " Cannot check if user is working."); this.errors .put(clientID, "The check if a user is working has been failed."); /* * cannot check if user is working, go in * errorState */ status.put(clientID, 12); psJobs.remove(clientID); } } } } break; case 11: this.errors.put(clientID, "The user is working."); // user is working, go in errorState status.put(clientID, 12); break; case 12: System.out.println("Shutdown failed"); // errorState break; case 13: System.out.println("Shutdown finished"); // successState break; } if (clientStatus == 12) { allFinished = true; } else if (clientStatus == 13) { allFinished = true; this.error = true; } else { allFinished = false; } } if (allFinished) { return false; } else { return true; } } private void ping(HashMap client) { String ipAddress = client.get("ip"); int clientID = Integer.parseInt(client.get("id")); GearmanJob job = GearmanJobImpl.createJob("ping", ipAddress.getBytes(), "ping" + clientID); gearmanClient.submit(job); status.put(clientID, 1); // ping started pingJobs.put(clientID, job); System.out.println("ping " + ipAddress); } private void who(HashMap client) { String ipAddress = client.get("ip"); int clientID = Integer.parseInt(client.get("id")); GearmanJob job = GearmanJobImpl.createJob("who", ipAddress.getBytes(), "who" + clientID); gearmanClient.submit(job); status.put(clientID, 3); // who started whoJobs.put(clientID, job); System.out.println("who " + ipAddress); } private void doShutdown(HashMap client) { String ipAddress = client.get("ip"); int clientID = Integer.parseInt(client.get("id")); GearmanJob job = GearmanJobImpl.createJob("doShutdown", ipAddress .getBytes(), "doShutdown" + clientID); gearmanClient.submit(job); status.put(clientID, 5); // shutdown started doShutdownJobs.put(clientID, job); System.out.println("doShutdown " + ipAddress); } private void pingShutdown(HashMap client) { String ipAddress = client.get("ip"); int clientID = Integer.parseInt(client.get("id")); GearmanJob job = GearmanJobImpl.createJob("ping", ipAddress.getBytes(), "ping" + clientID); gearmanClient.submit(job); status.put(clientID, 8); // pingShutdown started pingShutdownJobs.put(clientID, job); System.out.println("ping " + ipAddress); } private void ps(HashMap client) { String ipAddress = client.get("ip"); int clientID = Integer.parseInt(client.get("id")); GearmanJob job = GearmanJobImpl.createJob("ps", ipAddress.getBytes(), "ps" + clientID); gearmanClient.submit(job); status.put(clientID, 10); // ps started psJobs.put(clientID, job); System.out.println("ps " + ipAddress); } public String getStatusText(HashMap client) { int clientID = Integer.parseInt(client.get("id")); int clientStatus = this.status.get(clientID); return this.statusText[clientStatus]; } public String getError(HashMap client) { int clientID = Integer.parseInt(client.get("id")); String clientError = this.errors.get(clientID); return clientError; } public Boolean isFinished() { return finished; } public Boolean isFinishedWithErrors() { return finished && error; } public Vector> getClients() { return clients; } }