package sos.stacks.hobbit;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import sos.spooler.Job_impl;
import sos.spooler.Order;
import sos.spooler.Variable_set;
import sos.util.SOSDate;
import sos.xml.SOSXMLXPath;
/**
* @author andreas.pueschel@sos-berlin.com
*
*
* see job documentation in the package jobdoc for details
*/
public class JobSchedulerHobbitMessageJob extends Job_impl {
/** optional name for this job, defaults to scheduler job name */
protected String hobbitJob = "JobSchedulerHobbitMessageJob";
/** required URL of the hobbit server to which this job is reporting */
protected String hobbitUrl = "";
/** optional name or IP address of the host for which this job is reporting, default: job scheduler host */
protected String hobbitHost = "";
/** optional name of the test in the hobbit server console, default: scheduler */
protected String hobbitTest = "";
/** optional message type: currently "reset", "status" and "notify" are supported, default: status */
protected String messageType = "";
/** required message color: green, yellow, red */
protected String messageColor = "";
/** optional lifetime of a message */
protected String messageLifetime = "";
/** required message content */
protected String messageContent = "";
/** persistent messages are repeatedly processed */
protected boolean isMessagePersistent = true;
protected Vector messageVector = new Vector();
protected Iterator messageIterator = null;
protected Vector messageVariables = new Vector();
/**
* initialize message items
*/
protected void initMessageItems() {
this.setHobbitUrl("http://" + spooler.hostname() + "/hobbit-cgi/bbmessage.sh");
this.setHobbitHost(spooler.hostname());
this.setHobbitTest("scheduler");
this.setMessageType("status");
this.setMessageLifetime("");
this.setMessageColor("green");
this.setMessageContent("");
}
/**
* move message items to hashmap
*/
protected HashMap putMessageItem(String url, String host, String test, String type, String lifetime, String color, String content) {
HashMap message = new HashMap();
message.put("url", url);
message.put("host", host);
message.put("test", test);
message.put("type", type);
message.put("lifetime", lifetime);
message.put("color", color);
message.put("content", content);
return message;
}
/**
* move message items from hashmap to classs variables
*/
protected void getMessageItem(HashMap message) {
if (message.containsKey("url") && message.get("url") != null) this.setHobbitUrl(message.get("url").toString());
if (message.containsKey("host") && message.get("host") != null) this.setHobbitHost(message.get("host").toString());
if (message.containsKey("test") && message.get("test") != null) this.setHobbitTest(message.get("test").toString());
if (message.containsKey("type")&& message.get("type") != null) this.setMessageType(message.get("type").toString());
if (message.containsKey("lifetime")&& message.get("lifetime") != null) this.setMessageLifetime(message.get("lifetime").toString());
if (message.containsKey("color")&& message.get("color") != null) this.setMessageColor(message.get("color").toString());
if (message.containsKey("content")&& message.get("content") != null) this.setMessageContent(message.get("content").toString());
}
/**
* serialize message items to String
*/
protected String serializeMessageItem(String id, String url, String host, String test, String type, String lifetime, String color, String content) {
StringBuffer message = new StringBuffer();
message.append("<message id=\"" + id + "\">");
message.append("<url>" + this.normalizeItem(url) + "</url>");
message.append("<host>" + this.normalizeItem(host) + "</host>");
message.append("<test>" + this.normalizeItem(test) + "</test>");
message.append("<type>" + this.normalizeItem(type) + "</type>");
message.append("<lifetime>" + this.normalizeItem(lifetime) + "</lifetime>");
message.append("<color>" + this.normalizeItem(color) + "</color>");
message.append("<content>" + this.normalizeItem(content) + "</content>");
message.append("</message>");
return message.toString();
}
/**
* normalize message item
*/
protected String normalizeItem(String item) {
item = item.replaceAll("&", "&");
item = item.replaceAll("<", "<");
item = item.replaceAll(">", ">");
return item;
}
/**
* get job parameters from job configuration (scheduler.xml)
*/
protected void getJobParameters() throws Exception {
try { // to fetch default job parameters
if (spooler_task.params().var("job") != null && spooler_task.params().var("job").length() > 0) {
this.setHobbitJob(spooler_task.params().var("job"));
spooler_log.debug1(".. job parameter [job]: " + this.getHobbitJob());
} else if (this.getHobbitJob() == null || this.getHobbitJob().length() == 0){
this.setHobbitJob(spooler_job.name());
}
if (spooler_task.params().var("url") != null && spooler_task.params().var("url").length() > 0) {
this.setHobbitUrl(spooler_task.params().var("url"));
spooler_log.debug1(".. job parameter [url]: " + this.getHobbitUrl());
}
if (spooler_task.params().var("host") != null && spooler_task.params().var("host").length() > 0) {
this.setHobbitHost(spooler_task.params().var("host"));
spooler_log.debug1(".. job parameter [host]: " + this.getHobbitHost());
}
if (spooler_task.params().var("test") != null && spooler_task.params().var("test").length() > 0) {
this.setHobbitTest(spooler_task.params().var("test"));
spooler_log.debug1(".. job parameter [test]: " + this.getHobbitTest());
}
if (spooler_task.params().var("type") != null && spooler_task.params().var("type").length() > 0) {
this.setMessageType(spooler_task.params().var("type"));
spooler_log.debug1(".. job parameter [type]: " + this.getMessageType());
}
if (spooler_task.params().var("lifetime") != null && spooler_task.params().var("lifetime").length() > 0) {
this.setMessageLifetime(spooler_task.params().var("lifeteime"));
spooler_log.debug1(".. job parameter [lifetime]: " + this.getMessageLifetime());
}
if (spooler_task.params().var("persistent") != null && spooler_task.params().var("persistent").length() > 0) {
if (spooler_task.params().var("persistent").equals("0")
|| spooler_task.params().var("persistent").equalsIgnoreCase("false")
|| spooler_task.params().var("persistent").equalsIgnoreCase("no")) {
this.setMessagePersistent(false);
spooler_log.debug1(".. job parameter [persistent]: " + this.isMessagePersistent());
} else {
this.setMessagePersistent(true);
}
}
} catch (Exception e) {
throw new Exception("error occurred processing job parameters: " + e.getMessage());
}
}
/**
* check scheduler log file for warnings and errors
*/
public boolean spooler_open() {
long logFilepointer = 0;
String logFilename = "";
String logLine = "";
File logFile = null;
File prevLogFile = null;
RandomAccessFile checkFile = null;
RandomAccessFile checkPrevFile = null;
try {
this.messageVector = new Vector();
this.initMessageItems();
this.getJobParameters();
if (this.getMessageType().equalsIgnoreCase("reset")) {
spooler.set_var(this.getHobbitJob() + ".messages", "");
spooler_log.info("message stack has been reset");
this.messageVector.add(this.putMessageItem(this.getHobbitUrl(), this.getHobbitHost(), this.getHobbitTest(),
"status", this.getMessageLifetime(), "green", SOSDate.getCurrentTimeAsString() + ": warnings and errors were reset"));
}
try { // to retrieve persistent messages from scheduler variables
if (this.isMessagePersistent() ) {
String messageSet = spooler.var(this.getHobbitJob() + ".messages");
if (messageSet != null && messageSet.length() > 0) {
messageSet = messageSet.replaceAll(String.valueOf((char)254), "<").replaceAll(String.valueOf((char)255), ">");
SOSXMLXPath xpath = new SOSXMLXPath(new StringBuffer(messageSet));
NodeList nodelist = xpath.selectNodeList("//messages/*");
for (int i=0; i < nodelist.getLength(); i++) {
Node node = nodelist.item(i);
if (node == null) continue;
NodeList itemlist = xpath.selectNodeList(node, "*");
String curUrl = this.getHobbitUrl();
String curHost = this.getHobbitHost();
String curTest = this.getHobbitTest();
String curType = this.getMessageType();
String curLifetime = this.getMessageLifetime();
String curColor = this.getMessageColor();
String curContent = "";
for (int j=0; j<itemlist.getLength(); j++) {
Node item = itemlist.item(j);
if (item == null) continue;
if (item.getNodeName().equals("url") && item.getFirstChild() != null) {
curUrl = item.getFirstChild().getNodeValue();
} else if (item.getNodeName().equals("host") && item.getFirstChild() != null) {
curHost = item.getFirstChild().getNodeValue();
} else if (item.getNodeName().equals("test") && item.getFirstChild() != null) {
curTest = item.getFirstChild().getNodeValue();
} else if (item.getNodeName().equals("type") && item.getFirstChild() != null) {
curType = item.getFirstChild().getNodeValue();
} else if (item.getNodeName().equals("lifetime") && item.getFirstChild() != null) {
curLifetime = item.getFirstChild().getNodeValue();
} else if (item.getNodeName().equals("color") && item.getFirstChild() != null) {
curColor = item.getFirstChild().getNodeValue();
} else if (item.getNodeName().equals("content") && item.getFirstChild() != null) {
curContent = item.getFirstChild().getNodeValue();
}
}
this.messageVector.add(this.putMessageItem(curUrl, curHost, curTest,
curType, curLifetime, curColor, curContent));
}
}
}
} catch (Exception e) { // ignore all errors when processing persistent messages
spooler_log.info("persistent messages processed with errors: " + e.getMessage());
}
try { // to process possibly partially checked previous log files
String logFilepointerVariable = spooler.var(this.getHobbitJob() + ".filepointer");
String logFilenameVariable = spooler.var(this.getHobbitJob() + ".filename");
if (logFilepointerVariable != null && logFilepointerVariable.length() > 0) logFilepointer = Long.parseLong(logFilepointerVariable);
if (logFilenameVariable != null && logFilenameVariable.length() > 0) logFilename = logFilenameVariable;
// on previous execution of this job a different log file may have been partially checked
if (logFilename != null && logFilename.length() > 0 && !logFilename.equals(new File(spooler.log().filename()).getCanonicalPath() )) {
prevLogFile = new File(logFilename);
if (!prevLogFile.exists()) {
spooler_log.info("log file from previous job execution not found: " + prevLogFile.getCanonicalPath() );
}
checkPrevFile = new RandomAccessFile(prevLogFile, "r");
if (logFilepointer > 0) {
checkPrevFile.seek(logFilepointer);
spooler_log.debug3("starting to check previous log file [" + prevLogFile.getCanonicalPath() + "] from position: " + logFilepointer);
}
while((logLine = checkPrevFile.readLine()) != null) {
if (logLine.indexOf("[WARN]") != -1) {
this.messageVector.add(this.putMessageItem(this.getHobbitUrl(), this.getHobbitHost(), this.getHobbitTest(),
this.getMessageType(), this.getMessageLifetime(), "yellow", logLine));
} else if (logLine.indexOf("[ERROR]") != -1) {
this.messageVector.add(this.putMessageItem(this.getHobbitUrl(), this.getHobbitHost(), this.getHobbitTest(),
this.getMessageType(), this.getMessageLifetime(), "red", logLine));
}
}
spooler_log.debug3("previous log file [" + prevLogFile.getCanonicalPath() + "] processed");
logFilepointer = 0;
logFilename = "";
}
} catch (Exception e) { // ignore all errors when processing previous log files (log files may have been gzipped or removed)
spooler_log.info("previous log file [" + ((prevLogFile != null) ? prevLogFile.getCanonicalPath() : "") + "] processed with errors: " + e.getMessage());
logFilepointer = 0;
logFilename = "";
} finally {
if (checkPrevFile != null ) try { checkPrevFile.close(); } catch (Exception ex) {} // gracefully ignore this error
}
try {
logFile = new File(spooler.log().filename());
if (!logFile.exists()) {
throw new Exception("log file not found: " + logFile.getCanonicalPath() );
}
checkFile = new RandomAccessFile(logFile, "r");
if (logFilepointer > 0) {
checkFile.seek(logFilepointer);
spooler_log.debug3("starting to check current log file [" + logFile.getCanonicalPath() + "] from position: " + logFilepointer);
}
while((logLine = checkFile.readLine()) != null) {
if (logLine.matches( "^\\d{4}-\\d{1,2}-\\d{1,2} +\\d{1,2}:\\d{1,2}:\\d{1,2}(\\.\\d{1,3})? +\\[WARN\\] +.*" )) {
this.messageVector.add(this.putMessageItem(this.getHobbitUrl(), this.getHobbitHost(), this.getHobbitTest(),
this.getMessageType(), this.getMessageLifetime(), "yellow", logLine));
} else if (logLine.matches( "^\\d{4}-\\d{1,2}-\\d{1,2} +\\d{1,2}:\\d{1,2}:\\d{1,2}(\\.\\d{1,3})? +\\[ERROR\\] +.*" )) {
this.messageVector.add(this.putMessageItem(this.getHobbitUrl(), this.getHobbitHost(), this.getHobbitTest(),
this.getMessageType(), this.getMessageLifetime(), "red", logLine));
}
}
spooler.set_var(this.getHobbitJob() + ".filename", logFile.getCanonicalPath());
spooler.set_var(this.getHobbitJob() + ".filepointer", Long.toString(checkFile.getFilePointer()));
spooler_log.debug3("current log file [" + logFile.getCanonicalPath() + "] processed to position: " + Long.toString(checkFile.getFilePointer()));
// send a green message if no errors and warnings are to be reported
if (this.messageVector.isEmpty()) {
this.messageVector.add(this.putMessageItem(this.getHobbitUrl(), this.getHobbitHost(), this.getHobbitTest(),
"status", this.getMessageLifetime(), "green", SOSDate.getCurrentTimeAsString() + ": job scheduler is up and running"));
}
this.messageIterator = this.messageVector.iterator();
return this.messageIterator.hasNext();
} catch (Exception e) {
throw new Exception(e);
} finally {
if (checkFile != null ) try { checkFile.close(); } catch (Exception ex) {} // gracefully ignore this error
}
} catch (Exception e){
spooler_log.warn("failed to check messages in log file [" + spooler.log().filename() + "]: " + e.getMessage());
return false;
}
}
/**
* process message from scheduler log file
*/
public boolean spooler_process() {
Order order = null;
Variable_set orderData = null;
int messageCounter = 0;
boolean rc = true;
try {
this.initMessageItems();
this.getJobParameters();
try { // to fetch parameters from orders that have precedence to job parameters
if (spooler_task.job().order_queue() != null) {
order = spooler_task.order();
if (spooler_task.order().payload() == null)
throw new Exception("no payload was given for this order: " + order.id());
orderData = (Variable_set) spooler_task.order().payload();
if ( orderData.var("url") != null && orderData.var("url").toString().length() > 0) {
this.setHobbitUrl(orderData.var("url").toString());
spooler_log.debug1(".. order parameter [url]: " + this.getHobbitUrl());
}
if ( orderData.var("host") != null && orderData.var("host").toString().length() > 0) {
this.setHobbitHost(orderData.var("host").toString());
spooler_log.debug1(".. order parameter [host]: " + this.getHobbitHost());
}
if ( orderData.var("test") != null && orderData.var("test").toString().length() > 0) {
this.setHobbitTest(orderData.var("test").toString());
spooler_log.debug1(".. order parameter [test]: " + this.getHobbitTest());
}
if ( orderData.var("type") != null && orderData.var("type").toString().length() > 0) {
this.setMessageType(orderData.var("type").toString());
spooler_log.debug1(".. order parameter [type]: " + this.getMessageType());
}
if ( orderData.var("lifetime& |