00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 package org.objectweb.proactive.scheduler;
00032
00033 import java.io.BufferedReader;
00034 import java.io.File;
00035 import java.io.IOException;
00036 import java.io.InputStreamReader;
00037 import java.net.InetAddress;
00038 import java.net.UnknownHostException;
00039 import java.util.Date;
00040 import java.util.Iterator;
00041 import java.util.Vector;
00042
00043 import org.apache.log4j.Appender;
00044 import org.apache.log4j.Layout;
00045 import org.apache.log4j.Logger;
00046 import org.apache.log4j.PatternLayout;
00047 import org.apache.log4j.RollingFileAppender;
00048 import org.apache.log4j.WriterAppender;
00049 import org.apache.log4j.nt.NTEventLogAppender;
00050 import org.objectweb.proactive.core.node.Node;
00051 import org.objectweb.proactive.core.node.NodeException;
00052 import org.objectweb.proactive.core.node.NodeInformation;
00053 import org.objectweb.proactive.core.util.log.Loggers;
00054 import org.objectweb.proactive.core.util.log.ProActiveLogger;
00055
00056
00064 public class Communicator {
00065 private static Logger logger = ProActiveLogger.getLogger(Loggers.SCHEDULER_COMMAND_LISTENER);
00066
00067
00068 private static final String LOG_DIR = "." + File.separator + "logs" +
00069 File.separator;
00070 private static final String MAX_SIZE = "100KB";
00071 private static final String LOG_PATTERN = "%d %c %x %m\n\n";
00072 private static WriterAppender writerAppender;
00073 private static String hostname = null;
00074
00075 static {
00076 configureLogging();
00077 }
00078
00079
00080 private static final String LOG_HEADER = "[Scheduler] ";
00081 private static final String SUB_CMD = "sub";
00082 private static final String STAT_CMD = "stat";
00083 private static final String DEL_CMD = "del";
00084 private static final String NODES_CMD = "nodes";
00085 private static final String KILL_CMD = "kill";
00086 private static final String EXIT_CMD = "exit";
00087 private static final String SUB_PROTO = SUB_CMD + " XMLDescriptorOfTheJob";
00088 private static final String STAT_PROTO = STAT_CMD + " [jobId]";
00089 private static final String DEL_PROTO = DEL_CMD + " jobId";
00090 private static final String NODES_PROTO = NODES_CMD + " [nodeURL]";
00091 private static final String KILL_PROTO = KILL_CMD;
00092 private static final String EXIT_PROTO = EXIT_CMD;
00093 private Scheduler scheduler;
00094
00100 public Communicator(String schedulerURL) {
00101 try {
00102 this.scheduler = Scheduler.connectTo(schedulerURL);
00103 startCommandListener();
00104 } catch (Exception e) {
00105 flush("Cannot create command listener");
00106 System.exit(1);
00107 }
00108 }
00109
00114 public static void main(String[] args) {
00115
00116 if (args.length == 1) {
00117 String schedulerURL = args[0];
00118 new Communicator(schedulerURL);
00119 }
00120 System.err.println("Usage <java_command> Scheduler_URL");
00121 }
00122
00132 private String pad(String s, int pad_len) {
00133 if (s.length() >= pad_len) {
00134 return (s);
00135 } else {
00136 int nblanks = pad_len - s.length();
00137 StringBuilder blanks = new StringBuilder(nblanks);
00138
00139 blanks.setLength(nblanks);
00140 for (int k = 0; k < blanks.length(); ++k)
00141 blanks.setCharAt(k, ' ');
00142 return (blanks + s);
00143 }
00144 }
00145
00155 private String center(String s, int pad_len) {
00156 if (s.length() >= pad_len) {
00157 return (s);
00158 } else {
00159 int nblanks = pad_len - s.length();
00160 int half = nblanks / 2;
00161 StringBuilder blanks = new StringBuilder(half);
00162
00163 blanks.setLength(half);
00164 for (int k = 0; k < blanks.length(); ++k)
00165 blanks.setCharAt(k, ' ');
00166
00167 String end = "";
00168 if ((nblanks % 2) == 1) {
00169 end = " ";
00170 }
00171
00172 return (blanks + s + blanks + end);
00173 }
00174 }
00175
00182 private static void log(String msg, boolean isError) {
00183 msg = LOG_HEADER + msg;
00184
00185 try {
00186 if (isError) {
00187 logger.error(msg);
00188 } else {
00189 logger.info(msg);
00190 }
00191 } catch (Exception e) {
00192
00193 System.out.println(e.getMessage() + " when logging : " + msg);
00194 }
00195 }
00196
00201 public static String getLocalHostName() {
00202 if (hostname == null) {
00203 try {
00204 hostname = InetAddress.getLocalHost().getCanonicalHostName()
00205 .toLowerCase();
00206 } catch (UnknownHostException e) {
00207 e.printStackTrace();
00208 hostname = "localhost";
00209 }
00210 }
00211
00212 return hostname;
00213 }
00214
00219 private static void configureLogging() {
00220 Appender appender;
00221
00222 try {
00223 appender = new NTEventLogAppender("ProActiveScheduler");
00224 } catch (java.lang.UnsatisfiedLinkError e) {
00225 String hostname = getLocalHostName();
00226
00227 Layout layout = new PatternLayout(LOG_PATTERN);
00228 String filename = LOG_DIR + hostname;
00229 RollingFileAppender rfa;
00230
00231 try {
00232 new File(LOG_DIR).mkdir();
00233 rfa = new RollingFileAppender(layout, filename, true);
00234 } catch (IOException ioe) {
00235 ioe.printStackTrace();
00236
00237 return;
00238 }
00239
00240 rfa.setMaxBackupIndex(0);
00241 rfa.setMaxFileSize(MAX_SIZE);
00242 rfa.setImmediateFlush(false);
00243 writerAppender = rfa;
00244 appender = rfa;
00245 }
00246
00247 Logger root = Logger.getRootLogger();
00248 root.addAppender(appender);
00249
00250
00251 log("Starting Scheduler command listener", false);
00252 }
00253
00258 private static void flush(String message) {
00259 if (writerAppender != null) {
00260 writerAppender.setImmediateFlush(true);
00261 }
00262
00263 log(message, false);
00264
00265 if (writerAppender != null) {
00266 writerAppender.setImmediateFlush(false);
00267 }
00268 }
00269
00277 public void helpScreen(String command) {
00278 String result = "";
00279
00280 if (!command.endsWith(SUB_CMD) && !command.endsWith(STAT_CMD) &&
00281 !command.endsWith(DEL_CMD) && !command.endsWith(NODES_CMD) &&
00282 !command.endsWith(KILL_CMD) && !command.endsWith(EXIT_CMD) &&
00283 !command.equals("?")) {
00284 System.out.println("No such command: " + command.substring(1));
00285 log("No help available for " + command, true);
00286
00287 return;
00288 }
00289
00290 result = "\n";
00291
00292 if (!command.equals("?")) {
00293 String keyword = command.substring(2);
00294
00295 result += "This command's prototype is: ";
00296
00297 if (keyword.equals(SUB_CMD)) {
00298 result += SUB_PROTO;
00299 result += "\n\n";
00300 result += "This command is used to submit a job to the scheduler.\n\n";
00301 result += ("XMLDescriptorOfTheJob is the absolute path to the " +
00302 "XML Deployment Descriptor of the job to be submitted\n");
00303 } else if (keyword.equals(STAT_CMD)) {
00304 result += STAT_PROTO;
00305 result += "\n\n";
00306 result += ("This command is used to get additionnal information on one " +
00307 "or all the jobs submitted.\n\n");
00308 result += ("jobId is the id of the job that we want to know its " +
00309 "caracteristics. This argument is optional and if not submitted " +
00310 "this means that we need to get the information on all the jobs\n");
00311 } else if (keyword.equals(DEL_CMD)) {
00312 result += DEL_PROTO;
00313 result += "\n\n";
00314 result += ("This command is used to delete a specific job. " +
00315 "If the job is already deployed this may cause a brutal interruption " +
00316 "of the job.\n\n");
00317 result += "jobId is the id of the job that we want to delete.\n";
00318 } else if (keyword.equals(NODES_CMD)) {
00319 result += NODES_PROTO;
00320 result += "\n\n";
00321 result += ("This command is used to get information of one or all " +
00322 "the nodes that have been submitted.\n\n");
00323 result += ("nodeURL is the URL of the node that we need to fetch it's " +
00324 "characteristics. This argument is optional and if not submitted " +
00325 "this means that we need to get the information on all the jobs\n");
00326 } else if (keyword.equals(KILL_CMD)) {
00327 result += KILL_PROTO;
00328 result += "\n\n";
00329 result += "This command is used kill the scheduler abruptly.\n";
00330 } else if (keyword.equals(EXIT_CMD)) {
00331 result += EXIT_PROTO;
00332 result += "\n\n";
00333 result += "This command is used to exit this session.\n";
00334 }
00335
00336 result += "\n";
00337 } else {
00338 result += ("The commands available are: " + SUB_CMD + ", " +
00339 STAT_CMD + ", " + DEL_CMD + ", " + NODES_CMD + ", " + KILL_CMD +
00340 ", " + EXIT_CMD);
00341 }
00342
00343 result += "\n";
00344 System.out.println(result);
00345 }
00346
00353 private boolean handleCommand(String command) {
00354 if (command.equals(EXIT_CMD)) {
00355 System.exit(0);
00356 }
00357 if (command.equals("")) {
00358 return true;
00359 }
00360
00361 if (command.startsWith("?")) {
00362 this.helpScreen(command);
00363 return true;
00364 }
00365
00366 if (!command.startsWith(SUB_CMD) && !command.startsWith(STAT_CMD) &&
00367 !command.startsWith(DEL_CMD) && !command.startsWith(NODES_CMD) &&
00368 !command.startsWith(KILL_CMD)) {
00369 System.out.println("UNKNOWN COMMAND!!...");
00370 log("unknown command submitted: " + command, true);
00371
00372 return false;
00373 }
00374
00375 String error = null;
00376
00377 if (command.startsWith(SUB_CMD)) {
00378 flush(command);
00379
00380 if (command.equals(SUB_CMD)) {
00381 error = SUB_PROTO + "\n";
00382 } else {
00383
00384 String XMLDescriptorFile = command.substring(command.indexOf(
00385 ' ') + 1);
00386 this.scheduler.fetchJobDescription(XMLDescriptorFile);
00387 }
00388 }
00389
00390 if (command.startsWith(STAT_CMD)) {
00391 flush(command);
00392
00393 String jobId = null;
00394 int indexOfWhite = command.indexOf(" ");
00395
00396
00397
00398 if (indexOfWhite != -1) {
00399 jobId = command.substring(indexOfWhite + 1);
00400 }
00401
00402 Vector result = this.scheduler.stat(jobId);
00403 this.viewJobs(result, (jobId != null));
00404
00405
00406 }
00407
00408 if (command.startsWith(DEL_CMD)) {
00409 flush(command);
00410
00411 if (command.equals(DEL_CMD)) {
00412 error = DEL_PROTO + "\n";
00413 } else {
00414 System.out.println("DEL command invoked ....");
00415 String jobID = command.substring(command.indexOf(' ') + 1);
00416 this.scheduler.del(jobID);
00417 }
00418
00419
00420 }
00421
00422 if (command.startsWith(NODES_CMD)) {
00423 flush(command);
00424
00425 String nodeURL = null;
00426 int indexOfWhite = command.indexOf(" ");
00427
00428
00429
00430 if (indexOfWhite != -1) {
00431 nodeURL = command.substring(indexOfWhite + 1);
00432 }
00433
00434 Vector result = this.scheduler.nodes(nodeURL);
00435 this.viewNodes(result, (nodeURL != null));
00436
00437
00438 }
00439
00440 if (error != null) {
00441 System.out.println("Error using the command. Usage: " + error);
00442 log("Error using the command " +
00443 error.substring(0, error.indexOf(' ')), true);
00444 return false;
00445 }
00446
00447 if (KILL_CMD.equals(command)) {
00448 flush(command);
00449 System.exit(0);
00450 }
00451
00452 return true;
00453 }
00454
00459 private void startCommandListener() {
00460 InputStreamReader isr = new InputStreamReader(System.in);
00461 BufferedReader reader = new BufferedReader(isr);
00462
00463 for (;;) {
00464 try {
00465 System.out.print(" > ");
00466 String line = reader.readLine();
00467 handleCommand(line);
00468 } catch (IOException ioe) {
00469
00470 ioe.printStackTrace();
00471 }
00472 }
00473 }
00474
00483 public void viewNodes(Vector nodes, boolean specific) {
00484 Iterator iterator = nodes.iterator();
00485 int nbOfNodes = 0;
00486 int nbOfBusyNodes = 0;
00487 int nbOfReservedNodes = 0;
00488 String result = "";
00489 String header = this.center("Node URL", 45) + this.center("JobId", 74) +
00490 this.pad("status", 14) + "\n" +
00491 "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" +
00492 " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n";
00493
00494 result += header;
00495
00496 while (iterator.hasNext()) {
00497 Node node = (Node) iterator.next();
00498
00499 NodeInformation nodeInformation = node.getNodeInformation();
00500 String jobId = nodeInformation.getJobID();
00501 String nodeURL = nodeInformation.getURL();
00502 String status = "";
00503 nbOfNodes++;
00504
00505 try {
00506 if (jobId.equals("-")) {
00507 status = "free";
00508 } else {
00509 int aoNb = node.getNumberOfActiveObjects();
00510 if (aoNb == 0) {
00511 status = "reserved";
00512 nbOfReservedNodes++;
00513 } else {
00514 status = "busy";
00515 nbOfBusyNodes++;
00516 }
00517 }
00518 } catch (NodeException e) {
00519
00520 e.printStackTrace();
00521 }
00522
00523 result += (this.center(nodeURL, 45) + this.center(jobId, 74) +
00524 this.center(status, 22) + "\n");
00525 }
00526
00527 String addition = "\nDisplaying all nodes information: ";
00528 if (!specific) {
00529 addition += (nbOfBusyNodes + "/" + nbOfNodes + " busy nodes and " +
00530 nbOfReservedNodes + "/" + nbOfNodes + " reserved nodes");
00531 }
00532 addition += "\n\n";
00533 result = addition + result;
00534
00535 System.out.println(result);
00536 }
00537
00546 public void viewJobs(Vector jobs, boolean specific) {
00547 Iterator iterator = jobs.iterator();
00548 String result = "";
00549 String header = this.center("Job ID", 74) +
00550 this.center("submit date", 30) + this.center("estimated time", 18) +
00551 this.center("ressource number", 20) + this.center("status", 10) +
00552 "\n" +
00553 "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" +
00554 " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n";
00555
00556 result += header;
00557
00558 while (iterator.hasNext()) {
00559 GenericJob jobDescription = (GenericJob) iterator.next();
00560
00561 String jobId = jobDescription.getJobID();
00562 Date submitDate = jobDescription.getSubmitDate();
00563 int ressourceNb = jobDescription.getRessourceNb();
00564 int estimatedTime = jobDescription.getEstimatedTime();
00565 String jobStatus = jobDescription.getJobStatus();
00566
00567 result += (this.center(jobId, 74) +
00568 this.center(String.valueOf(submitDate), 30) +
00569 this.center(String.valueOf(estimatedTime), 18) +
00570 this.center(String.valueOf(ressourceNb), 20) +
00571 this.center(jobStatus, 10) + "\n");
00572 }
00573
00574 String addition = "\n\n";
00575 result = addition + result;
00576
00577 System.out.println(result);
00578 }
00579 }