/* Copyright 1999-2011 (c) My-Channels Copyright (c) 2012-2015 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors. Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG. */ package com.pcbsys.nirvana.nAdminAPI.apps; import com.pcbsys.nirvana.client.nSessionAttributes; import com.pcbsys.nirvana.nAdminAPI.*; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.*; /** * This application will start multiple threads to monitor each specified Nirvana realm. Triggers can be set in the * configuration file. If these triggers are hit, information regarding this issue will be output to a CSV file. */ public class RealmMonitor { String sampleConfig = "" + "# SAMPLE CONFIG FILE \n" + "\n" + "\n" + "#If no workingdir set then will default to current dir\n" + "\n" + "#workingdir=/Users/XXX/Desktop/\n" + "runRealmMonitor=true \n" + "runConnectionMonitor=true \n" + "runThreadMonitor= true \n" + "runLogMonitor= true \n" + "runChannelMonitor= true\n" + "\n" + "#--------------------\n" + "monitor=connectionmonitor \n" + "headings=Date,Time,Name,Last received,Queue Size,Events Received,Events Transmitted\n" + "methods=getDate,getTime,getRealmName,getTimeOfLastReceive,getQueueSize,getEventsReceived,getEventsTransmitted\n" + "#outputfile=/Users/XXX/Desktop/ConnectionMonitor.txt \n" + "refreshrate=5000\n" + "#maxTimeOfLastTransmitt=5000 #default = keepAliveTime * 1.5\n" + "maxQueuedEvents=0\n" + "\n" + "#-------------------- \n" + "monitor = threadmonitor \n" + "headings = Time,Realm Name,Name,Queued,Idle,Allocated,Tasks Executed \n" + "methods = getTime, getRealmName,getName,getQueue,getIdle,getSize,getTotal\n" + "maxQueueSize=0;\n" + "minIdle=0\n" + "\n" + "#---------------------\n" + "monitor = logmonitor\n" + "keywords = exception,stalled,attack,Exceeded\n" + "\n" + "#---------------------\n" + "monitor = realmmonitor \n" + "refreshrate=5000\n" + "headings=Time,Name,Channels,Queues,Current Connections,Total Connections,Free Memory,Total Memory,Used Memory,Threads \n" + "methods=getTime, getRealmName,getNoOfChannels,getNoOfQueues,getCurrentConnections,getTotalConnections,getFreeMemory,getTotalMemory,getUsedMemory,getNoOfThreads \n" + "methodsError=getTime, getRealmName,print0, print0, print0, print0, print0, print0, print0, print0\n" + "#methodsError lists the methods to call if there is an error. print0 will simply output 0 so there are clear errors in any graphs\n" + "\n" + "\n" + "#---------------------\n" + "monitor = channelmonitor \n" + "#debug=true\n" + "refreshrate=10000\n" + "headings=Time,Name,Type, Published, Consumed, Connections, Used Space, pub rate\n" + "methods = getTime,getName,getType, getTotalPublished,getTotalConsumed, getTotalNoOfConnections, getUsedSpace, getPublishRate\n" + "\n" + "#int\n" + "minPercentFreeInStore = 0;\n" + "minFanoutTime = 0;\n" + "minUsedSpace = 0;\n" + "#long\n" + "minCurrentEvents = 0;\n" + "#float\n" + "minConsumedRate = 0.0;\n" + "minPubRate = .0; \n" + "minCacheHitRatio = 0;\n" + "minConnectionRate = 0;\n" + "minCurrentCons = 0;\n" + "\n" + "#maxFanoutTime = #Integer.MAX_VALUE; realm_m = new ArrayList(); private List chan_m = new ArrayList(); private List con_m = new ArrayList(); private List thread_m = new ArrayList(); private List log_m = new ArrayList(); //---------------------------- String TIME_FORMAT_NOW = "HH:mm:ss"; String DATE_FORMAT_NOW = "dd.MM.yyyy"; SimpleDateFormat timeformat = new SimpleDateFormat(TIME_FORMAT_NOW); SimpleDateFormat dateformat = new SimpleDateFormat(DATE_FORMAT_NOW); String workingdir = ""; public static void main(String[] args){ new RealmMonitor(args); } /** * First process the arguments (Rname and config file location) * * All other properties are then read in from the config file. Config file can set properties for the individual * monitor threads but also specify which methods to invoke and output to the csv files. * * Each monitor thread is passed a list of methods to invoke. The connection monitor for example will try to invoke * these methods on the nConnectionDetails object where as the Realm monitor will invoke the methods on the rNode. * * It is also possible to override these methods or define custom methods. This is handled by the order in which the application * tries to invoke the methods. First we try to invoke on the monitor thread, then the actual object (e.g. nConnectionDetails) * and finally this class. By doing this we can override certain methods in order to return a value in a different format (e.g. a time) * Also we will want to timestamp everything that is written to the csv file so there is a getTime method written for this class * so we can add getTime to our methods list. * */ public RealmMonitor(String[] args){ workingdir = System.getProperty("user.dir")+"/RealmMonitorOut/"; processArgs(args); setupMonitorThreads(); checkConfig(); try{ getConfigDetails(); } catch(Exception e){ e.printStackTrace(); } new ExitHandler(); startMonitorThreads(); } /** * We store everything based on rname so when we get a nRealmNode for a cluster node we need to find that nodes rname. * @param n a realm node * @return the rname for n */ public String getRname(nRealmNode n){ nInterfaceStatus is = (nInterfaceStatus)n.getInterfaceManager().getInterfaces().get(0); nInterface i = is.getInterface(); return i.getURL(); } /** * Creates one rnode for every rname passed in, also gets any other realm nodes which are part of a cluster. * A new thread is then created (but not started) for every rname and every different monitor. */ private void setupMonitorThreads(){ if(runRealmMonitor) { for (String rname : rnames) { nRealmNode rNode = getRealmNode(rname); rNode.waitForEntireNameSpace(); if (rNode.isClustered()) { nClusterNode cNode = rNode.getCluster(); Enumeration nodes = cNode.getNodes(); while (nodes.hasMoreElements()) { nRealmNode n; try { n = (nRealmNode) nodes.nextElement(); realm_m.add(new RealmMonitor_t(getRname(n)).withRnode(n)); } catch (Exception e) { System.out.println("Error trying to get all nodes in cluster: attempting to continue"); } } } else realm_m.add(new RealmMonitor_t(rname).withRnode(rNode)); } } if(runChannelMonitor) { for (String rname : rnames) { nRealmNode rNode = getRealmNode(rname); rNode.waitForEntireNameSpace(); if (rNode.isClustered()) { nClusterNode cNode = rNode.getCluster(); Enumeration nodes = cNode.getNodes(); while (nodes.hasMoreElements()) { nRealmNode n; try { n = (nRealmNode) nodes.nextElement(); chan_m.add(new ChannelMonitor_t(getRname(n)).withRnode(n)); } catch (Exception e) { System.out.println("Error trying to get all nodes in cluster: attempting to continue"); } } } else chan_m.add(new ChannelMonitor_t(rname).withRnode(rNode)); } } if(runLogMonitor) { for (String rname : rnames) { nRealmNode rNode = getRealmNode(rname); rNode.waitForEntireNameSpace(); if (rNode.isClustered()) { nClusterNode cNode = rNode.getCluster(); Enumeration nodes = cNode.getNodes(); while (nodes.hasMoreElements()) { nRealmNode n; try { n = (nRealmNode) nodes.nextElement(); log_m.add(new LogMonitor_t(getRname(n)).withRnode(n)); } catch (Exception e) { System.out.println("Error trying to get all nodes in cluster: attempting to continue"); } } } else log_m.add(new LogMonitor_t(rname).withRnode(rNode)); } } if(runConnectionMonitor) { for (String rname : rnames) { nRealmNode rNode = getRealmNode(rname); rNode.waitForEntireNameSpace(); if (rNode.isClustered()) { nClusterNode cNode = rNode.getCluster(); Enumeration nodes = cNode.getNodes(); while (nodes.hasMoreElements()) { nRealmNode n; try { n = (nRealmNode) nodes.nextElement(); con_m.add(new ConnectionMonitor_t(getRname(n)).withRnode(n)); } catch (Exception e) { System.out.println("Error trying to get all nodes in cluster: attempting to continue"); } } } else con_m.add(new ConnectionMonitor_t(rname).withRnode(rNode)); } } if(runThreadMonitor) { for (String rname : rnames) { nRealmNode rNode = getRealmNode(rname); rNode.waitForEntireNameSpace(); if (rNode.isClustered()) { nClusterNode cNode = rNode.getCluster(); Enumeration nodes = cNode.getNodes(); while (nodes.hasMoreElements()) { nRealmNode n; try { n = (nRealmNode) nodes.nextElement(); thread_m.add(new ThreadMonitor_t(getRname(n)).withRnode(n)); } catch (Exception e) { System.out.println("Error trying to get all nodes in cluster: attempting to continue"); } } } else thread_m.add(new ThreadMonitor_t(rname).withRnode(rNode)); } } } /** * Once we have dealt with the configuration file the threads are all initialised. */ private void startMonitorThreads(){ if(runRealmMonitor) { for (RealmMonitor_t aRealm_m : realm_m) { aRealm_m.init(); } } if(runChannelMonitor) { for (ChannelMonitor_t aChan_m : chan_m) { aChan_m.init(); } } if(runLogMonitor) { for (LogMonitor_t aLog_m : log_m) { aLog_m.init(); } } if(runConnectionMonitor) { for (ConnectionMonitor_t aCon_m : con_m) { aCon_m.init(); } } if(runThreadMonitor) { for (ThreadMonitor_t aThread_m : thread_m) { aThread_m.init(); } } } /** * This class monitors the threads of a realm */ public class ThreadMonitor_t extends MonitorThread{ nRealmNode rNode; long maxQueueSize = 0; long minIdle = 0; private ThreadMonitor_t(String rname){ this.rname=rname; headings = new String[]{"getTime","getQueue","getIdle","getName","getTotal"}; } void init(){ if(rNode==null)rNode = getRealmNode(rname); name=rNode.getName(); if(outputFile.equals(""))outputFile = workingdir+"ThreadMonitor_"+name+".txt"; if(refreshRate==0)refreshRate=5000; try{ FileWriter fstream = new FileWriter(outputFile,true); out = new BufferedWriter(fstream); printHeadings(); } catch(Exception e){ e.printStackTrace(); } this.start(); } public ThreadMonitor_t withRnode(nRealmNode n){ rNode = n; return this; } public void run(){ while(true){ for(Object tp : rNode.getThreadPoolDetails()){ if(checkThreadPool((nThreadPool)tp)){ write(printDetails(tp,this)); } } try { Thread.sleep(refreshRate); } catch (InterruptedException ignore) { } } } private boolean checkThreadPool(nThreadPool tp){ return debug || tp.getQueue() > maxQueueSize || tp.getIdle() <= minIdle; } public void setMaxQueueSize(Object o){ maxQueueSize = Long.parseLong((String)o); if(debug)System.out.println("setting maxQueueSize = "+maxQueueSize); } public void setMinIdle(Object o){ minIdle = Long.parseLong((String)o); if(debug)System.out.println("setting minIdle = "+minIdle); } } /** * Monitors the log and writes to a csv file if a keyword is found */ public class LogMonitor_t extends MonitorThread implements nLogListener{ nRealmNode rNode; String[]keywords; private LogMonitor_t(String rname){ this.rname = rname; headings = new String[]{"Log Listener"}; } void init(){ if(rNode==null)rNode = getRealmNode(rname); name = rNode.getName(); if(outputFile.equals(""))outputFile = workingdir+"LogMonitor_"+name+".txt"; try{ FileWriter fstream = new FileWriter(outputFile,true); out = new BufferedWriter(fstream); printHeadings(); rNode.addLogListener(this); } catch(Exception e){ e.printStackTrace(); } } public LogMonitor_t withRnode(nRealmNode n){ rNode = n; return this; } public void setKeywords(Object o){ keywords = RealmMonitor.getStringArray((String)o); if(debug) System.out.println("Setting keywords = "+o); } private boolean checkForProblems(String line){ if(keywords == null)return true; for(String keyword : keywords){ if(line.contains(keyword))return true; } return false; } public void report(String message) { if(checkForProblems(message)){ write(message+"\n"); } } } /** * Monitors changes to realm connections */ public class ConnectionMonitor_t extends MonitorThread implements nConnectionListener{ nRealmNode rNode; final Hashtable cons = new Hashtable(); int maxQueuedEvents = 0; long keepAliveTime = 60000; Double maxTimeOfLastTransmitt = -1.0; private ConnectionMonitor_t(String rname){ this.name = rname; headings = new String[]{"getTime","getTimeOfLastReceive","getQueueSize","getEventsReceived","getEventsTransmitted"}; } void init(){ if(rNode==null)rNode = getRealmNode(rname); name = rNode.getName(); if(maxTimeOfLastTransmitt==-1.0){ try { keepAliveTime = Long.parseLong(rNode.getConfigGroup("Connection Config").find("KeepAlive").getValue()); //6.0 } catch (Exception e) { try{ keepAliveTime = Long.parseLong(rNode.getConfigGroup("FanoutValues").find("KeepAlive").getValue()); //5.5 } catch(Exception e2){ System.out.println("could not get keep alive value"); } keepAliveTime=60000; } maxTimeOfLastTransmitt = keepAliveTime*1.5; } if(refreshRate==0)refreshRate=5000; if(outputFile.equals(""))outputFile = workingdir+"ConnectionMonitor_"+name+".txt"; try{ rNode.addConnectionListener(this); FileWriter fstream = new FileWriter(outputFile,true); out = new BufferedWriter(fstream); printHeadings(); } catch(Exception e){ e.printStackTrace(); } this.start(); } public ConnectionMonitor_t withRnode(nRealmNode n){ rNode = n; return this; } public void run(){ while(true){ synchronized(cons){ for(nConnectionDetails details : cons.values()){ if(checkForProblems(details)){ write(printDetails(details,this)); } } } try { Thread.sleep(refreshRate); } catch (InterruptedException ignore) { } } } public void add(nConnectionDetails details) { synchronized(cons){ cons.put(details.getId(), details); } } public void del(nConnectionDetails details) { synchronized(cons){ cons.remove(details.getId()); } } private boolean checkForProblems(nConnectionDetails details){ return details.getQueueSize() > maxQueuedEvents || details.getTimeOfLastTransmitt() > maxTimeOfLastTransmitt || debug; } public void setMaxQueuedEvents(Object o){ maxQueuedEvents = Integer.parseInt((String)o); if(debug)System.out.println("setting maxQueuedEvents = "+maxQueuedEvents); } public void setMaxTimeOfLastTransmitt(Object o){ maxTimeOfLastTransmitt = Double.valueOf((String)o); if(debug)System.out.println("setting maxTimeOfLastTransmitt = "+maxTimeOfLastTransmitt); } } /** * Monitors channels for issues. Will write to the csv if any triggers are hit e.g. the used space reaches a * certain level. */ public class ChannelMonitor_t extends MonitorThread{ nRealmNode rNode; int maxFanoutTime = Integer.MAX_VALUE; int maxUsedSpace = 0; float maxConsumedRate = 0; long maxCurrentEvents = Long.MAX_VALUE; float maxPubRate = Float.MAX_VALUE; float maxCacheHitRatio = Float.MAX_VALUE; float maxConnectionRate = Float.MAX_VALUE; float maxCurrentCons = Float.MAX_VALUE; int maxPercentFreeInStore = Integer.MAX_VALUE; int minPercentFreeInStore=0; int minFanoutTime =0; int minUsedSpace = 0; float minConsumedRate = 0; long minCurrentEvents = 0; float minPubRate = 0; float minCacheHitRatio = 0; float minConnectionRate = 0; float minCurrentCons = 0; private ChannelMonitor_t(String rname){ this.rname = rname; } public void init(){ if(rNode==null)rNode = getRealmNode(rname); name = rNode.getName(); if(outputFile.equals(""))outputFile = workingdir+"ChannelMonitor_"+name+".txt"; try{ FileWriter fstream = new FileWriter(outputFile,true); out = new BufferedWriter(fstream); printHeadings(); this.start(); } catch(Exception e){ e.printStackTrace(); } } public ChannelMonitor_t withRnode(nRealmNode n){ rNode = n; return this; } public void run(){ while(true){ try { checkForProblems(rNode); Thread.sleep(refreshRate); } catch (InterruptedException ignore) { } } } public void checkForProblems(nRealmNode rNode){ checkForProblems(rNode.getNodes()); } public void checkForProblems(Enumeration nodes){ while ( nodes.hasMoreElements() ) { Object obj = nodes.nextElement(); if ( obj instanceof nLeafNode ) { checkForProblems( (nLeafNode)obj ); } else if ( obj instanceof nRealmNode ) { checkForProblems( (nRealmNode)obj ); } else if ( obj instanceof nContainer ) { checkForProblems((nContainer)obj); } } } public void checkForProblems(nLeafNode node){ if(node.getUsedSpace()=maxUsedSpace){ write(printDetails(node, this)); return; } if(node.getConsumedRate()<=minConsumedRate||node.getConsumedRate()>=maxConsumedRate){ write(printDetails(node, this)); return; } if(node.getPublishRate()<=minPubRate||node.getPublishRate()>=maxPubRate){ write(printDetails(node, this)); return; } if(node.getCacheHitRatio()<=minCacheHitRatio||node.getCacheHitRatio()>=maxCacheHitRatio){ write(printDetails(node, this)); return; } if(node.getConnectionRate()<=minConnectionRate||node.getConnectionRate()>=maxConnectionRate){ write(printDetails(node, this)); return; } if(node.getCurrentNoOfConnections()<=minCurrentCons||node.getCurrentNoOfConnections()>=maxCurrentCons){ write(printDetails(node, this)); return; } if(node.getCurrentNumberOfEvents()<=minCurrentEvents||node.getCurrentNumberOfEvents()>=maxCurrentEvents){ write(printDetails(node, this)); return; } if(node.getFanoutTime()<=minFanoutTime||node.getFanoutTime()>=maxFanoutTime){ write(printDetails(node, this)); return; } if(node.getPercentageFreeInStore()<=minPercentFreeInStore||node.getPercentageFreeInStore()>=maxPercentFreeInStore){ write(printDetails(node, this)); return; } if(debug)write(printDetails(node, this)); } public void checkForProblems(nContainer container){ checkForProblems(container.getNodes()); } public String getType(Object o){ nLeafNode leaf = (nLeafNode)o; if(leaf.isChannel()){ return "Channel"; } if(leaf.isQueue()){ return "Queue"; } return "unknown"; } public String getUsedSpace(Object o){ long used = ((nLeafNode)o).getUsedSpace(); used = used/1024; return used+""; } /** * All these set methods are invoked if the property is set in the config file i.e if maxUsedSpace is set in the properties * file then setMaxUsedSpace is invoked with the value * @param o the value set in the config file. We know this is a string so we can immediately cast it. */ public void setMaxUsedSpace(Object o){ maxUsedSpace = Integer.parseInt((String) o); if(debug)System.out.println("setting maxUsedSpace = "+maxUsedSpace); } public void setMaxConsumedRate(Object o){ maxConsumedRate = Float.parseFloat((String) o); if(debug)System.out.println("setting maxConsumedRate = "+maxConsumedRate); } public void setMaxPubRate(Object o){ maxPubRate = Float.parseFloat((String) o); if(debug)System.out.println("setting maxPubRate = "+maxPubRate); } public void setMaxConnectionRate(Object o){ maxConnectionRate = Float.parseFloat((String) o); if(debug)System.out.println("setting maxConnectionRate = "+maxConnectionRate); } public void setMaxCacheHitRatio(Object o){ maxCacheHitRatio = Float.parseFloat((String) o); if(debug)System.out.println("setting maxCacheHitRatio = "+maxCacheHitRatio); } public void setMaxCurrentCons(Object o){ maxCurrentCons = Float.parseFloat((String) o); if(debug)System.out.println("setting maxCurrentCons = "+maxCurrentCons); } public void setMaxFanoutTime(Object o){ maxFanoutTime = Integer.parseInt((String) o); if(debug)System.out.println("setting maxFanoutTime = "+maxFanoutTime); } public void setMaxPercentFreeInStore(Object o){ maxPercentFreeInStore = Integer.parseInt((String) o); if(debug)System.out.println("setting maxPercentFreeInStore = "+maxPercentFreeInStore); } public void setMaxCurrentEvents(Object o){ maxCurrentEvents = Long.parseLong((String) o); if(debug)System.out.println("setting maxCurrentEvents = "+maxCurrentEvents); } public void setMinPercentFreeInStore(Object o){ minPercentFreeInStore = Integer.parseInt((String) o); if(debug)System.out.println("setting minPercentFreeInStore = "+minPercentFreeInStore); } public void setMinUsedSpace(Object o){ minUsedSpace = Integer.parseInt((String) o); if(debug)System.out.println("setting minUsedSpace = "+minUsedSpace); } public void setMinConsumedRate(Object o){ minConsumedRate = Float.parseFloat((String) o); if(debug)System.out.println("setting minConsumedRate = "+minConsumedRate); } public void setMinPubRate(Object o){ minPubRate = Float.parseFloat((String) o); if(debug)System.out.println("setting minPubRate = "+minPubRate); } public void setMinConnectionRate(Object o){ minConnectionRate = Float.parseFloat((String) o); if(debug)System.out.println("setting minConnectionRate = "+minConnectionRate); } public void setMinCacheHitRatio(Object o){ minCacheHitRatio = Float.parseFloat((String) o); if(debug)System.out.println("setting minCacheHitRatio = "+minCacheHitRatio); } public void setMinCurrentCons(Object o){ minCurrentCons = Float.parseFloat((String)o); if(debug)System.out.println("setting minCurrentCons = "+minCurrentCons); } public void setMinFanoutTime(Object o){ minFanoutTime = Integer.parseInt((String)o); if(debug)System.out.println("setting minFanoutTime = "+minFanoutTime); } public void setMinCurrentEvents(Object o){ minCurrentEvents = Long.parseLong((String)o); if(debug)System.out.println("setting minCurrentEvents = "+minCurrentEvents); } } /** * Monitors the realm. Will continuously write to the csv file. If we do not receive an update from the realm * in more than 2*updateInterval then we write 0s to the csv. This way any problems will be clear if the csv is * used to create a graph. */ public class RealmMonitor_t extends MonitorThread implements Observer { nRealmNode rNode; long lastUpdate; String[] methodsError; private RealmMonitor_t(String rname){ this.rname = rname; headings = new String[]{"getTime","getNoOfChannels","getNoOfQueues","getCurrentConnections","getTotalConnections","getFreeMemory","getTotalMemory","getNoOfThreads"};//need get used! } public void init(){ if(rNode==null)rNode = getRealmNode(rname); name = rNode.getName(); if(outputFile.equals(""))outputFile = workingdir+"RealmMonitor_"+name+".txt"; try{ FileWriter fstream = new FileWriter(outputFile,true); out = new BufferedWriter(fstream); printHeadings(); if(refreshRate==0)refreshRate = Long.parseLong(rNode.getConfigGroup("Connection Config").find("KeepAlive").getValue()); } catch(Exception e){ refreshRate=60000; } rNode.addObserver(this); lastUpdate = System.currentTimeMillis(); this.start(); } public RealmMonitor_t withRnode(nRealmNode rNode){ this.rNode=rNode; return this; } public void run(){ while(true){ try { if(!checkForProblems(rNode)){ write(printDetails(rNode, this)); } else{ print0s(); } Thread.sleep(refreshRate); } catch (InterruptedException ignore) { } } } public void print0s(){ StringBuilder sb = new StringBuilder(); if(methodsError==null){ for(String s : headings){ sb.append("0,"); } write(sb.substring(0,sb.length()-1)+"\n"); } else{ String[]temp = methods; methods = methodsError; write(printDetails(rNode, this)); methods = temp; } } public String getTotalMemory(Object o){ nRealmNode rn = (nRealmNode)o; long tot = rn.getTotalMemory(); tot=tot/(1024*1024); return tot+""; } public String getFreeMemory(Object o){ nRealmNode rn = (nRealmNode)o; long free = rn.getFreeMemory(); free=free/(1024*1024); return free+""; } public String getUsedMemory(Object o){ nRealmNode rn = (nRealmNode)o; long totalmem = rn.getTotalMemory(); long freemem = rn.getFreeMemory(); long diff = totalmem-freemem; diff = diff/(1024*1024); return diff+""; } public void setMethodsError(Object o){ methodsError=getStringArray((String) o); if(debug)System.out.println("setting methodsError = "+o); } public boolean checkForProblems(nRealmNode rNode){ long now = System.currentTimeMillis(); long diff = now - lastUpdate; return diff > rNode.getUpdateInterval() * 2; } public void update(Observable o, Object arg) { lastUpdate = System.currentTimeMillis(); } } Hashtable rNodes = new Hashtable(); /** * This method is used to ensure we do not start multiple rnodes for one rname * @param rname rname for the rnode to construct * @return either a cached rnode or a newly constructed rnode for rname */ private nRealmNode getRealmNode(String rname){ try { if(rNodes.containsKey(rname)){ return rNodes.get(rname); } System.out.print("Establishing realm node..."); nSessionAttributes nsa = new nSessionAttributes(rname); nRealmNode rNode = new nRealmNode(nsa); if (!rNode.isAuthorised()) { System.out.println("User not authorised on this node " + nsa); System.exit(1); } System.out.println("done\n"); rNodes.put(rname,rNode); return rNode; } catch (Exception e) { e.printStackTrace(); System.exit(1); } return null; } /** * Reads the configuration details from the config file. * @throws Exception */ private void getConfigDetails() throws Exception { BufferedReader reader=null; try{ File f = new File(configloc); reader = new BufferedReader(new FileReader(f)); String line; String monitor = ""; int linenum=-1; while ((line = reader.readLine()) != null) { linenum++; line = line.trim(); if(line.length()==0 || line.charAt(0)=='#'){ continue; } if(line.contains("#")){ line = line.substring(0,line.indexOf('#')); } if(line.endsWith(";")){ line = line.substring(0,line.length()-1); } String[] args = line.split("="); if(args.length!=2)throw new Exception("Syntax error in config file at line: "+linenum+" (too many '=')"); String field = args[0].trim(); String value = args[1].trim(); if(field.equalsIgnoreCase("monitor")){ monitor = value; continue; } setValue(monitor,field,value); } }finally { if (reader != null) { reader.close(); } } } /** * For the given monitor object, sets the field for that monitor to the value read from the config file. * @param monitor the name of the monitor class e.g. connectionmonitor * @param field the field (variable) of the monitor to be set * @param value the value to set the field to */ private void setValue(String monitor, String field, String value){ try{ String firstLetter = field.substring(0,1); field = "set"+firstLetter.toUpperCase()+field.substring(1); if(monitor.equalsIgnoreCase("")){ this.getClass().getMethod(field,Object.class).invoke(this,value); return; } if(monitor.equalsIgnoreCase("realmmonitor")){ if(runRealmMonitor) { for(RealmMonitor_t m : realm_m){ m.getClass().getMethod(field,Object.class).invoke(m,value); } } return; } if(monitor.equalsIgnoreCase("channelmonitor")){ if(runChannelMonitor) { for(ChannelMonitor_t m : chan_m){ m.getClass().getMethod(field,Object.class).invoke(m,value); } } return; } if(monitor.equalsIgnoreCase("logmonitor")){ if(runLogMonitor) { for(LogMonitor_t m : log_m){ m.getClass().getMethod(field,Object.class).invoke(m,value); } } return; } if(monitor.equalsIgnoreCase("connectionmonitor")){ if(runConnectionMonitor) { for(ConnectionMonitor_t m : con_m){ m.getClass().getMethod(field,Object.class).invoke(m,value); } } return; } if(monitor.equalsIgnoreCase("threadmonitor")){ if(runThreadMonitor) { for(ThreadMonitor_t m : thread_m){ m.getClass().getMethod(field,Object.class).invoke(m,value); } } return; } throw new Exception("unknown monitor"); } catch(Exception ignore){ } } /** * If the user has not input a config file location then we can create a config file in the working directory */ private void checkConfig(){ if(configloc.equals("")){ configloc = System.getProperty("user.dir")+"/RealmMonitorOut/"; File f = new File(configloc); f.mkdirs(); configloc+="config.txt"; f = new File(configloc); if(!f.exists()){ System.out.println("No config file found so generating one > "+configloc); try{ FileWriter fstream = new FileWriter(configloc); BufferedWriter out = new BufferedWriter(fstream); out.write(sampleConfig); out.close(); } catch(Exception e){ System.out.println("Error generating sample config file. Please specify one."); Usage(); System.exit(0); } } } System.out.println("Using config file : "+configloc); } /** * Each monitor class has a list of methods which should be invoked and the return value printed to the csv. * This method takes a monitor thread and an object. It then tries to invoke each method in the monitor's methods * array. First it tries to invoke the method on the monitor object (e.g. ConnectionMonitor_t), * then the object passed in (e.g. nConnectionDetails) and then the enclosing class (RealmMonitor). * Once a the method is found it is invoked and the returned object is added to a comma separated list. * By trying to invoke the methods in this order we can override certain return types. Some methods return an array of * String so would cause us to write something like String[] to the csv which is no good. So instead we can add a * method in the monitor thread class which takes the String[] and returns a String representation. * * @param o an object such as nConnectionDetails or nRealmNode * @param mon the calling monitor thread * @return comma separated list of values to be written to the csv */ private synchronized String printDetails(Object o, Object mon){ StringBuilder sb = new StringBuilder(); for(String methodname : ((MonitorThread)mon).getMethods()){ //getName is a method in the Thread class so need to rename to make sure we invoke this on the correct object if(methodname.equals("getName"))methodname="_getName"; try { sb.append(tryInvoke(methodname, mon, o)); } catch (NoSuchMethodException e) { try { sb.append(tryInvoke(methodname, o, o)); } catch (NoSuchMethodException e1) { try { sb.append(tryInvoke(methodname, this, o)); } catch (Exception e11) { e11.printStackTrace(); } } catch(Exception e2){ e2.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } } return sb.substring(0,sb.length()-1)+"\n"; } /** * * @param method the name of the method to invoke * @param o the object to try to invoke on. For example if this if the connection monitor, we will first try to invoke * on the connection monitor thread (to allow us to override methods), then the nConnectionDetails object, then * the this RealmMonitor class (e.g. getTime) * @param baseobject In the case of the connection monitor this will be the nConnectionDetails object. This is passed * so that we can handle a method like getSubject differently. getSubject returns an array of Strings so we would * need to override this in the monitor thread so we can output a comma separated list. This still requires us to * pass the nConnectionDetails object to the monitor thread method. * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalAccessException */ public String tryInvoke(String method,Object o, Object baseobject) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Object ret = null; Method m; try{ m = o.getClass().getMethod(method); ret = m.invoke(o); } catch(Exception e){ try{ m =o.getClass().getMethod(method,Object.class); ret = m.invoke(o, baseobject); } catch(IllegalArgumentException e2){ e2.printStackTrace(); } } //Need to make sure we can handle all return types. //if the method name contains the word time we will format it as a time if(ret!=null){ if(ret instanceof Long){ if(method.toLowerCase().contains("time")){ Calendar cal = Calendar.getInstance(); cal.setTimeInMillis((Long)ret); ret = timeformat.format(cal.getTime()); } else{ ret = Long.toString((Long)ret); } } return ret.toString()+","; } return ","; } /** * Super class for each of the monitor threads. Contains methods applicable to all monitor threads. */ public class MonitorThread extends Thread{ String rname; String name; String[] headings; String[] methods; BufferedWriter out; boolean debug = false; long refreshRate=0; String outputFile=""; void write(String message){ try { out.write(message); out.flush(); if(debug)System.out.print(message); } catch (IOException ignored) { } } String[] getHeadings(){ return headings; } String[] getMethods(){ return methods; } public void setHeadings(Object o){ headings = RealmMonitor.getStringArray((String)o); if(debug) System.out.println("setting headings = "+o); } public void setMethods(Object o){ methods = RealmMonitor.getStringArray((String)o); if(debug) System.out.println("setting methods = "+o); } public void setDebug(Object o){ debug = Boolean.valueOf((String)o); System.out.println("Setting debug mode = "+debug); } //log monitor is async so no refresh rate public void setRefreshrate(Object o){ refreshRate = Long.parseLong((String)o); if(debug) System.out.println("setting refreshRate = "+o); } public void setOutputfile(Object o){ outputFile = (String)o; if(debug) System.out.println("outputFile = "+o); } public String getRname(){ return rname; } public String getRealmName(){ return name; } public String _getName(Object o){ Method m = null; try { m = o.getClass().getMethod("getName"); Object ret = m.invoke(o); return ret.toString(); } catch (Exception ignored) {} return "error"; } public String getID(){ return name; } void printHeadings(){ for(int i = 0; i < headings.length; i++){ write(headings[i]); if(i [config file]\n"); System.out.println("\n"); System.out.println(" : comma separated list of rnames to monitor.\n"); System.out.println("[Optional Parameters]\n"); System.out.println("[config file] : configuration file location e.g. c:\\config.txt\n"); System.out.println("All other parameters can be specified in the config file."); System.out.println("If realm is clustered then other realms in cluster will"); System.out.println("be found automatically."); } /** * Enables the user to stop the monitoring by removing a lock file. * The lock file is created in the working directory. */ private class ExitHandler extends Thread { File lckFile = null; public ExitHandler() { try { setName("LoadRunner : exit thread"); setDaemon(true); lckFile = new File(workingdir + File.separator +"RealmMonitor.lck"); start(); } catch (Exception e) { e.printStackTrace(); } } public void run() { try { if (lckFile.exists()) { lckFile.delete(); try { Thread.sleep(2000); } catch (InterruptedException ignored) { } } else{ try { lckFile.getParentFile().mkdirs(); } catch (Exception ignored) { } } lckFile.createNewFile(); while (lckFile.exists()) { try { Thread.sleep(1000); } catch (Exception ignored) { } } System.out.println("JVM exiting after lck file removal..."); System.exit(1); } catch (Exception e) { e.printStackTrace(); } } } }