package edu.umn.pssa.ibmonitorservice; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Calendar; import java.util.List; import java.util.Properties; import java.util.Vector; import javax.mail.Authenticator; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import org.apache.log4j.Logger; public class Monitor extends Thread { // Logger private static final Logger logger = Logger.getLogger(IBMonitorSvc.class.getName()); // Application Constants private static final String PUBLICATION_CONTRACT = "PubContract"; private static final String SUBSCRIPTION_CONTRACT = "SubContract"; private static final String MESSAGE_INSTANCE = "MessageInstance"; private static final String DOMAIN_STATUS = "DomainStatus"; private static final String NODE_DOWNTIME = "NodeDowntime"; private static final String DEFAULT_PUBLICATION_MONITOR = "Default Publication Contracts"; private static final String DEFAULT_SUBSCRIPTION_MONITOR = "Default Subscription Contracts"; private static final String DEFAULT_MESSAGE_INSTANCE_MONITOR = "Default Message Instances"; private static final String MESSAGE_INSTANCE_THRESHOLD = "MsgInstanceThreshold"; private static final String PUBLICATION_CONTRACT_THRESHOLD = "PubContractThreshold"; private static final String SUBSCRIPTION_CONTRACT_THRESHOLD = "SubContractThreshold"; private static final String MESSAGE_INSTANCE_AGING = "MsgInstanceAging"; private static final String PUBLICATION_CONTRACT_AGING = "PubContractAging"; private static final String SUBSCRIPTION_CONTRACT_AGING = "SubContractAging"; private static final String MESSAGE_INSTANCE_RECORD = ".PSAPMSGPUBHDR"; private static final String PUBLICATION_CONTRACT_RECORD = ".PSAPMSGPUBCON"; private static final String SUBSCRIPTION_CONTRACT_RECORD = ".PSAPMSGSUBCON"; private static final String MESSAGE_INSTANCE_STATUS_COLUMN = "PUBSTATUS"; private static final String PUBLICATION_CONTRACT_STATUS_COLUMN = "PUBCONSTATUS"; private static final String SUBSCRIPTION_CONTRACT_STATUS_COLUMN = "SUBCONSTATUS"; private static final String SELECT_COUNT = "Select Count(*) From "; private static final String SELECT_MESSAGE_INSTANCES = "Select /*+ Index(PSAPMSGPUBHDR PSCPSAPMSGPUBHDR) */ IBTRANSACTIONID From "; private static final String SELECT_PUBLICATION_CONTRACTS = "Select /*+ Index(PSAPMSGPUBCON PSCPSAPMSGPUBCON) */ IBTRANSACTIONID From "; private static final String SELECT_SUBSCRIPTION_CONTRACTS = "Select /*+ Index(PSAPMSGSUBCON PSCPSAPMSGSUBCON) */ IBTRANSACTIONID From "; private static final String SELECT_DOMAIN_STATUS = "Select count(*) From <SCHEMA>.PSAPMSGDOMSTAT Where DOMAIN_STATUS = 'A'"; private static final String SELECT_EACH = "Select 'X' From UM_IB_MONITOR Where DATABASE_NAME = ':1' and EVENT_NAME = ':2' and EVENT_TYPE = ':3' and ESCALATION = :4 and IBTRANSACTIONID = ':5'"; private static final String INSERT_TRANSACTION = "Insert Into UM_IB_MONITOR Values(':1', ':2', ':3', :4, ':5')"; private static final String DELETE_TRANSACTIONS = "Delete From UM_IB_MONITOR Where DATABASE_NAME = ':1' and EVENT_NAME = ':2' and EVENT_TYPE = ':3' and IBTRANSACTIONID not in (:4)"; private static final String INSERT_NODE_DOWN = "Insert Into <SCHEMA>.PSNODESDOWN Select :1, :2, :3, :4, :5, :6 From Dual Where Not Exists (Select 'X' From <SCHEMA>.PSNODESDOWN Where MSGNODENAME = :1 and TRXTYPE = :2 and IB_OPERATIONNAME = :3 and VERSIONNAME = :4)"; private static final String REMOVE_NODE_DOWN = "Delete From <SCHEMA>.PSNODESDOWN Where MSGNODENAME = :1 and TRXTYPE = :2 and IB_OPERATIONNAME = :3 and VERSIONNAME = :4"; private static final String ACTION_NOTIFY = "Notify"; private static final String ACTION_CANCEL = "Cancel"; private static final String ACTION_RESUBMIT = "Resubmit"; private static final String ACTION_RETRY_REACT = "Retry/React"; private static final String ACTION_NOTIFY_EACH = "Notify Each"; private static final String ACTION_CUSTOM = "Custom"; private static final String STATUS_OK = ""; private static final String STATUS_ALERT = "ALERT"; private static final String TYPE_MESSAGE = "Message"; private static final String TYPE_THRESHOLD = "Threshold"; private static final String TYPE_AGING = "Aging"; private static final String TYPE_NODE_DOWN = "Node Downtime"; private static final String WINDOW_ACTIVE = "Active"; private static final String WINDOW_OFF_HOURS = "Off Hours"; private static final String WINDOW_DOWN_TIME = "Down Time"; private static final String DOMAIN_STATUS_NOTIFICATION_SUBJECT = "No Active IB Domains found in "; private static final String DOMAIN_STATUS_NOTIFICATION_BODY = "Monitoring did not find any active IB domains in <DATABASE>. Please verify at least one domain is active."; private static final String CRLF = System.getProperty("line.separator"); private static final String ON_CALL = "On Call"; private MonitorConnection connection; private Vector<MonitorConfig> vMonitors; private Connection connMonitor; private Session emailSession; private int monitorId; private int downTimeFrequency = 0; private int defaultNotifyInterval = 0; private int defaultNotifyIntervalOffHours = 0; private Boolean domainStatusCheck = false; private Boolean hasNotifyEach = false; private long sleepTime = 0; private String databaseName = ""; private String databaseHost = ""; private String databasePassword = ""; private String databaseUser = ""; private String databaseSchema = ""; private String defaultNotifyTo = ""; private String defaultNotifyCC = ""; private boolean monitoring = false; private Calendar downTimeStart = null; private Calendar downTimeEnd = null; private String defaultOffHoursTimeStart = ""; private String defaultOffHoursTimeEnd = ""; public Monitor() { } public Monitor(DatabaseType dbNode, int monitorID, boolean debugMode, String databaseType) { emailSession = createSession(); monitorId = monitorID; vMonitors = new Vector<MonitorConfig>(); // Get "Core" configurations databaseName = dbNode.getDatabaseName(); databaseHost = dbNode.getHost(); databaseUser = dbNode.getUser(); databasePassword = dbNode.getPassword(); databaseSchema = dbNode.getDbSchema(); defaultNotifyTo = dbNode.getDefaultNotifyTo(); defaultNotifyCC = dbNode.getDefaultNotifyCC(); defaultNotifyInterval = dbNode.getDefaultNotifyInterval(); if (defaultNotifyInterval == 0) { defaultNotifyInterval = 60; } domainStatusCheck = "ON".equalsIgnoreCase(dbNode.getDomainStatus()); // Set Off Hours monitoring, if configured defaultOffHoursTimeStart = dbNode.getStartTimeOffHours(); defaultOffHoursTimeEnd = dbNode.getEndTimeOffHours(); defaultNotifyIntervalOffHours = dbNode.getDefaultNotifyIntervalOffHours(); if (defaultNotifyIntervalOffHours == 0) { defaultNotifyIntervalOffHours = defaultNotifyInterval; } int tmpTime = dbNode.getSleepTime(); if (tmpTime == 0) { sleepTime = 5 * 60 * 1000; } else { sleepTime = tmpTime * 60 * 1000; } vMonitors = populateConfigs(dbNode); // Check if we're in debug mode for this specific Database if (!debugMode) { if ("ON".equalsIgnoreCase(dbNode.getDebugMode())) { logger.info("Debug Mode turned on for database " + this.databaseName); debugMode = true; } } // Write SQL to a log file if in Debug Mode if (debugMode) { Logger debugLog = Logger.getLogger("ibmonitordebug"); // Output SQL Statements for (int i = 0; i < vMonitors.size(); i++) { logger.info("logging Debug SQL"); debugLog.debug("-- " + vMonitors.get(i).monitorName); debugLog.debug(vMonitors.get(i).sqlStatement); debugLog.debug(CRLF); } } else { // Check for connectivity connection = new MonitorConnection(getNodeValue(dbNode.dbType, databaseType)); if (!connection.testConnectivity()){ logger.info("Unable to find driver for database connectivity. Exiting program."); } else { // Create the connection to verify connectivity connMonitor = connection.openDBConnection(databaseHost, databaseUser, databasePassword); if (connMonitor == null) { logger.info("Did not create connection for " + databaseName + " on host " + databaseHost); IBMonitorSvc.terminateMonitor(monitorId); monitoring = false; } else { logger.info("Created connection for " + databaseName + " on host " + databaseHost); if (hasNotifyEach) { connection.createIBMonitorTable(connMonitor, databaseName); } } } } } public void run() { startMonitor(); } private void startMonitor() { Thread waitThread = new Thread(); monitoring = true; while (monitoring) { try { synchronized (waitThread) { Thread.sleep(sleepTime); if (isDownTime()) { logger.info("Database " + databaseName + " will not be monitored during scheduled downtime. "); } else { if (connMonitor == null) { connMonitor = connection.openDBConnection(databaseHost, databaseUser, databasePassword); } // Write to ibAlerts.log file logger.info("Monitoring Database " + this.databaseName); if (connMonitor == null) { logger.info("Unable to create monitoring connection for " + databaseName); } else { // Execute Monitors if (vMonitors.size() > 0) { executeMonitors(); } } connMonitor.close(); connMonitor = null; } } } catch (Exception e) { logger.info("Monitoring in " + databaseName + " caught Exception: " + e.getMessage()); } } } // Method to populate the MonitorConfigs private Vector<MonitorConfig> populateConfigs(DatabaseType dbNode) { Vector<MonitorConfig> vConfigs; List<MonitorEventType> configNodes; MonitorEventType configNode; int index; int numConfigs = 0; int defaultTimeFrame; String defaultStatus; int defaultRetryCount ; String strStartTime = ""; String strEndTime = ""; String downTimeStartDay = ""; String downTimeEndDay = ""; vConfigs = new Vector<MonitorConfig>(); configNodes = dbNode.getMonitorEvent(); defaultStatus = getNodeValue(dbNode.getDefaultStatusToCheck(), ""); defaultTimeFrame = getNodeValue(dbNode.getDefaultMonitorTime(), 0); defaultRetryCount = getNodeValue(dbNode.getDefaultRetryCount(), 0); downTimeStartDay = getNodeValue(dbNode.getDownTimeStartDay(), ""); strStartTime = getNodeValue(dbNode.getDownTimeStart(), ""); downTimeEndDay = getNodeValue(dbNode.getDownTimeEndDay(), ""); strEndTime = getNodeValue(dbNode.getDownTimeEnd(), ""); downTimeFrequency = getNodeValue(dbNode.getDownTimeFrequency(), 0); if (!strStartTime.equalsIgnoreCase("") && !strEndTime.equalsIgnoreCase("") && !downTimeStartDay.equalsIgnoreCase("") && !downTimeEndDay.equalsIgnoreCase("") && downTimeFrequency > 0 ) { setMonitorDownTime(downTimeStartDay, strStartTime, downTimeEndDay, strEndTime); } // Get each specific monitor to execute for (index = 0; index < configNodes.size(); index ++ ) { configNode = configNodes.get(index); // Populate Configurations MonitorConfig tmpMonitor = new MonitorConfig(configNode); // Store in the Vector vConfigs.add(index, tmpMonitor); numConfigs = index; } if (numConfigs != 0) { numConfigs = numConfigs + 1; } // Populate 3 more entries in vConfigs for default monitors (Pubs/Subs/Instances) vConfigs.add(numConfigs, populateDefaultConfig(MESSAGE_INSTANCE, generateDefaultMonitorSQL(MESSAGE_INSTANCE_STATUS_COLUMN, defaultStatus, defaultTimeFrame, defaultRetryCount, vConfigs))); vConfigs.add(numConfigs + 1, populateDefaultConfig(PUBLICATION_CONTRACT, generateDefaultMonitorSQL(PUBLICATION_CONTRACT_STATUS_COLUMN, defaultStatus, defaultTimeFrame, defaultRetryCount, vConfigs))); vConfigs.add(numConfigs + 2, populateDefaultConfig(SUBSCRIPTION_CONTRACT, generateDefaultMonitorSQL(SUBSCRIPTION_CONTRACT_STATUS_COLUMN, defaultStatus, defaultTimeFrame, defaultRetryCount, vConfigs))); if (domainStatusCheck) { vConfigs.add(numConfigs + 3, populateDomainStatusConfig()); } return vConfigs; } private String generateMonitorSQL(MonitorConfig monitorConfigs) { String sqlString = ""; String statusColumn = ""; if (monitorConfigs.operationType.equalsIgnoreCase(SUBSCRIPTION_CONTRACT)) { sqlString = SELECT_SUBSCRIPTION_CONTRACTS + databaseSchema + SUBSCRIPTION_CONTRACT_RECORD; statusColumn = SUBSCRIPTION_CONTRACT_STATUS_COLUMN; } else if (monitorConfigs.operationType.equalsIgnoreCase(PUBLICATION_CONTRACT)) { sqlString = SELECT_PUBLICATION_CONTRACTS + databaseSchema + PUBLICATION_CONTRACT_RECORD; statusColumn = PUBLICATION_CONTRACT_STATUS_COLUMN; } else if (monitorConfigs.operationType.equalsIgnoreCase(MESSAGE_INSTANCE)) { sqlString = SELECT_MESSAGE_INSTANCES + databaseSchema + MESSAGE_INSTANCE_RECORD; statusColumn = MESSAGE_INSTANCE_STATUS_COLUMN; } else if (monitorConfigs.operationType.equalsIgnoreCase(MESSAGE_INSTANCE_THRESHOLD)) { sqlString = SELECT_COUNT + databaseSchema + MESSAGE_INSTANCE_RECORD; statusColumn = MESSAGE_INSTANCE_STATUS_COLUMN; } else if (monitorConfigs.operationType.equalsIgnoreCase(PUBLICATION_CONTRACT_THRESHOLD)) { sqlString = SELECT_COUNT + databaseSchema + PUBLICATION_CONTRACT_RECORD; statusColumn = PUBLICATION_CONTRACT_STATUS_COLUMN; } else if (monitorConfigs.operationType.equalsIgnoreCase(SUBSCRIPTION_CONTRACT_THRESHOLD)) { sqlString = SELECT_COUNT + databaseSchema + SUBSCRIPTION_CONTRACT_RECORD; statusColumn = SUBSCRIPTION_CONTRACT_STATUS_COLUMN; } else if (monitorConfigs.operationType.equalsIgnoreCase(MESSAGE_INSTANCE_AGING)) { sqlString = SELECT_COUNT + databaseSchema + MESSAGE_INSTANCE_RECORD; statusColumn = MESSAGE_INSTANCE_STATUS_COLUMN; } else if (monitorConfigs.operationType.equalsIgnoreCase(PUBLICATION_CONTRACT_AGING)) { sqlString = SELECT_COUNT + databaseSchema + PUBLICATION_CONTRACT_RECORD; statusColumn = PUBLICATION_CONTRACT_STATUS_COLUMN; } else if (monitorConfigs.operationType.equalsIgnoreCase(SUBSCRIPTION_CONTRACT_AGING)) { sqlString = SELECT_COUNT + databaseSchema + SUBSCRIPTION_CONTRACT_RECORD; statusColumn = SUBSCRIPTION_CONTRACT_STATUS_COLUMN; } else if (monitorConfigs.operationType.equalsIgnoreCase(NODE_DOWNTIME)) { return generateNodeDownSQL(monitorConfigs); } else { return ""; } // Build Where Clause sqlString = sqlString + " Where " + statusColumn + " in (" + monitorConfigs.status + ")"; // Add any Service Operation Conditions sqlString = sqlString + createCondition("and", "IB_OPERATIONNAME", monitorConfigs.serviceOperation, "in"); // Add any Service Operation EXCLUDE Conditions sqlString = sqlString + createCondition("and", "IB_OPERATIONNAME", monitorConfigs.serviceOperationExclude, "not in"); // Add any Publication Node Conditions sqlString = sqlString + createCondition("and", "PUBNODE", monitorConfigs.pubNode, "in"); // Add condition for Subscribing Node: Only for Publication Contracts if (monitorConfigs.operationType.equalsIgnoreCase(PUBLICATION_CONTRACT)) { sqlString = sqlString + createCondition("and", "SUBNODE", monitorConfigs.subNode, "in"); } // Add condition for time period to check if (monitorConfigs.timeToCheck > 0) { sqlString = sqlString + " and LASTUPDDTTM > (Sysdate - (" + monitorConfigs.timeToCheck + "/1440))"; } // If this is an Aging Monitor, add the necessary check on time if (monitorConfigs.monitorType.equals(TYPE_AGING)) { sqlString = sqlString + " and LASTUPDDTTM < (Sysdate - (" + monitorConfigs.age + "/1440))"; } return sqlString; } private String createCondition(String prefix, String columnName, String nodeValue, String condition) { if (nodeValue.equalsIgnoreCase("")) { return ""; } else { String values = ""; String strPrefix = ""; // Parse the list of values String[] array = nodeValue.split(","); for (int index = 0; index < array.length ; index ++ ) { values = values + strPrefix + "'" + array[index].trim() + "'"; strPrefix = ","; } return " " + prefix + " " + columnName + " " + condition + " (" + values + ")"; } } private String generateDefaultMonitorSQL(String statusColumn, String status, int timeFrame, int retryCount, Vector<MonitorConfig> vMonitorConfigs) { String sqlInClause = ""; String unionString = ""; String whereClause = ""; //Create the UNION ALL of all other checks: unionString = ""; for (int i=0; i < vMonitorConfigs.size(); i++) { if (vMonitorConfigs.get(i).monitorType.equalsIgnoreCase(TYPE_MESSAGE)) { sqlInClause = sqlInClause + unionString + vMonitorConfigs.get(i).sqlStatement; unionString = " Union All "; } } // Build Where Clause whereClause = " Where " + statusColumn + " in (" + status + ") and IBTRANSACTIONID not in (" + sqlInClause + ")"; if (retryCount > 0) { // Add time check condition to the Where clause to check X minutes whereClause = whereClause + " and RETRYCOUNT > " + retryCount; } if (timeFrame > 0) { // Add time check condition to the Where clause to check X minutes whereClause = whereClause + " and LASTUPDDTTM > (Sysdate - (" + timeFrame + "/1440))"; } return whereClause; } private String generateNodeDownSQL(MonitorConfig monitorConfigs) { String sqlString = INSERT_NODE_DOWN.replaceAll("<SCHEMA>", databaseSchema); // MSGNODENAME sqlString = sqlString.replaceAll(":1", generateReplacementString(monitorConfigs.subNode)); // TRXTYPE: Always Outbound Asynchronous (OA) sqlString = sqlString.replaceAll(":2", "'OA'"); // IB_OPERATIONNAME sqlString = sqlString.replaceAll(":3", generateReplacementString(monitorConfigs.serviceOperation)); // VERSIONNAME sqlString = sqlString.replaceAll(":4", "' '"); // EXTOPERATIONNAME sqlString = sqlString.replaceAll(":5", "' '"); // ROUTINGDEFNNAME sqlString = sqlString.replaceAll(":6", "' '"); return sqlString; } private String generateNodeDownRemovalSQL(MonitorConfig monitorConfigs) { String sqlString = REMOVE_NODE_DOWN.replaceAll("<SCHEMA>", databaseSchema); // MSGNODENAME sqlString = sqlString.replaceAll(":1", generateReplacementString(monitorConfigs.subNode)); // TRXTYPE: Always Outbound Asynchronous (OA) sqlString = sqlString.replaceAll(":2", "'OA'"); // IB_OPERATIONNAME sqlString = sqlString.replaceAll(":3", generateReplacementString(monitorConfigs.serviceOperation)); // VERSIONNAME sqlString = sqlString.replaceAll(":4", "' '"); return sqlString; } private String generateReplacementString(String value) { if (value.equals("") || value == null) { value = " "; } return "'" + value + "'"; } private MonitorConfig populateDefaultConfig(String opType, String whereClause) { MonitorConfig configs = new MonitorConfig(); String sqlString = ""; if (opType.equalsIgnoreCase(SUBSCRIPTION_CONTRACT)) { sqlString = SELECT_SUBSCRIPTION_CONTRACTS + databaseSchema + SUBSCRIPTION_CONTRACT_RECORD; configs.monitorName = DEFAULT_SUBSCRIPTION_MONITOR; } else if (opType.equalsIgnoreCase(PUBLICATION_CONTRACT)) { sqlString = SELECT_PUBLICATION_CONTRACTS + databaseSchema + PUBLICATION_CONTRACT_RECORD; configs.monitorName = DEFAULT_PUBLICATION_MONITOR; } else if (opType.equalsIgnoreCase(MESSAGE_INSTANCE)) { sqlString = SELECT_MESSAGE_INSTANCES + databaseSchema + MESSAGE_INSTANCE_RECORD; configs.monitorName = DEFAULT_MESSAGE_INSTANCE_MONITOR; } sqlString = sqlString + whereClause; configs.operationType = opType; configs.monitorType = TYPE_MESSAGE; configs.serviceOperation = ""; configs.pubNode = ""; configs.subNode = ""; configs.status = ""; configs.sqlStatement = sqlString; //SQL to execute configs.action = ""; //Action to be performed configs.reaction = ""; if (defaultNotifyTo.equals("") && defaultNotifyCC.equals("")) { configs.notificationFlag = false; //Notification Flag } else { configs.notificationFlag = true; //Notification Flag } configs.retryCount = 0; //# of retry attempts configs.alertStatus = STATUS_OK; //NOT currently in Alert State configs.alertSubject = configs.monitorName + " issues found in " + databaseName + "."; configs.alertText = configs.monitorName + " issues found in " + databaseName + "."; configs.notifyTo = defaultNotifyTo; configs.notifyCC = defaultNotifyCC; configs.notificationInterval = defaultNotifyInterval; // Every hour configs.lastNotification = null; // Set the Off Hours monitoring, if configured if (!defaultOffHoursTimeStart.equalsIgnoreCase("") && !defaultOffHoursTimeEnd.equalsIgnoreCase("")) { setMonitorHours(configs, defaultOffHoursTimeStart, defaultOffHoursTimeEnd, WINDOW_OFF_HOURS); } configs.notificationIntervalOffHours = defaultNotifyIntervalOffHours; // 0 unless configured return configs; } private MonitorConfig populateDomainStatusConfig() { MonitorConfig configs = new MonitorConfig(); String sqlString = SELECT_DOMAIN_STATUS.replace("<SCHEMA>", databaseSchema); configs.monitorType = DOMAIN_STATUS; configs.sqlStatement = sqlString; //SQL to execute configs.action = ""; //Action to be performed configs.reaction = ""; if (defaultNotifyTo.equals("") && defaultNotifyCC.equals("")) { configs.notificationFlag = false; //Notification Flag } else { configs.notificationFlag = true; //Notification Flag } configs.retryCount = 0; //# of retry attempts configs.alertStatus = STATUS_OK; //NOT currently in Alert State configs.alertSubject = DOMAIN_STATUS_NOTIFICATION_SUBJECT + databaseName + "."; configs.alertText = DOMAIN_STATUS_NOTIFICATION_BODY.replace("<DATABASE>", databaseName); configs.notifyTo = defaultNotifyTo; configs.notifyCC = defaultNotifyCC; configs.notificationInterval = defaultNotifyInterval; // Every hour configs.lastNotification = null; // Set the Off Hours monitoring, if configured if (!defaultOffHoursTimeStart.equalsIgnoreCase("") && !defaultOffHoursTimeEnd.equalsIgnoreCase("")) { setMonitorHours(configs, defaultOffHoursTimeStart, defaultOffHoursTimeEnd, WINDOW_OFF_HOURS); } configs.notificationIntervalOffHours = defaultNotifyIntervalOffHours; // 0 unless configured return configs; } // Method to execute each of the configured Monitor activities private void executeMonitors() { for (int monitorIndex = 0; monitorIndex < vMonitors.size(); monitorIndex++) { MonitorConfig monitorConfigs = vMonitors.get(monitorIndex); if (isInWindow(WINDOW_ACTIVE, monitorConfigs, monitorConfigs.startTime, monitorConfigs.endTime)) { processMonitorResults(monitorConfigs); } else { // Reset lastNotification if not already null if (!(monitorConfigs.lastNotification == null)) { monitorConfigs.lastNotification = null; } // Additional Node Down Logic: if (monitorConfigs.monitorType.equalsIgnoreCase(TYPE_NODE_DOWN) && monitorConfigs.alertStatus.equalsIgnoreCase(STATUS_ALERT)) { // Node should no longer be "Down" removeNodeDown(monitorConfigs); } } } } // Method to process the Monitor results private void processMonitorResults(MonitorConfig monitorConfigs) { String transactionID = ""; String notificationMessage = ""; int transCount = 0; int notifyInterval = 0; Boolean resultsFound = false; Boolean reaction = false; try { Statement stmt = connMonitor.createStatement(); if (monitorConfigs.monitorType.equalsIgnoreCase(TYPE_NODE_DOWN)) { stmt.executeUpdate(monitorConfigs.sqlStatement); monitorConfigs.alertStatus = STATUS_ALERT; } else { ResultSet rs = stmt.executeQuery(monitorConfigs.sqlStatement); while (rs.next()) { // For Transaction Monitors if (monitorConfigs.monitorType.equalsIgnoreCase(TYPE_MESSAGE)) { resultsFound = true; notificationMessage = monitorConfigs.alertText; // Get the Transaction ID transactionID = rs.getString(1); // Check if previously processed? // Take action if configured if (monitorConfigs.action.equalsIgnoreCase(ACTION_CUSTOM)) { // Fire the Custom Action monitorConfigs.customAction.fireAction(transactionID); } else if (monitorConfigs.action.equalsIgnoreCase(ACTION_RETRY_REACT)) { // First: Override resultsFound - we may or may not have to notify yet... resultsFound = false; // Second: Perform Retry/React logic. Set reaction to true accordingly. if (monitorConfigs.retryReact(transactionID)) { reaction = true; } } else if (monitorConfigs.action.equalsIgnoreCase(ACTION_NOTIFY_EACH)) { //TO DO: Need new logic. notifyEach(monitorConfigs, transactionID); } else if (!monitorConfigs.action.equalsIgnoreCase("") && !monitorConfigs.action.equalsIgnoreCase(ACTION_NOTIFY)) { executeUpdate(transactionID, monitorConfigs.operationType, monitorConfigs.action, databaseName, connMonitor); logger.info("executeUpdate fired on Transaction ID: " + transactionID + " in " + databaseName + ": Retry Count = " + monitorConfigs.retryCount); } else if (resultsFound){ break; //Since we are not taking an action other than notify, we don't need to keep looping } } else if (monitorConfigs.monitorType.equalsIgnoreCase(TYPE_THRESHOLD)) { // Get the Count transCount = Integer.valueOf(rs.getString(1)); if (transCount > monitorConfigs.threshold) { resultsFound = true; notificationMessage = monitorConfigs.alertText.replaceAll(":1", String.valueOf(transCount)); } } else if (monitorConfigs.monitorType.equalsIgnoreCase(TYPE_AGING)) { // Get the Count transCount = Integer.valueOf(rs.getString(1)); if (transCount > monitorConfigs.threshold) { resultsFound = true; notificationMessage = monitorConfigs.alertText.replaceAll(":1", String.valueOf(transCount)); } } else if (monitorConfigs.monitorType.equalsIgnoreCase(DOMAIN_STATUS)) { transCount = Integer.valueOf(rs.getString(1)); if (transCount == 0) { resultsFound = true; notificationMessage = monitorConfigs.alertText; } } } } if (monitorConfigs.action.equalsIgnoreCase(ACTION_NOTIFY_EACH) || monitorConfigs.reaction.equalsIgnoreCase(ACTION_NOTIFY_EACH)) { // Remove any Transaction IDs from UM_IB_MONITOR no longer found to be an issue stmt.execute(DELETE_TRANSACTIONS.replace(":1", databaseName) .replace(":2", monitorConfigs.monitorName) .replace(":3", monitorConfigs.monitorType) .replace(":4", monitorConfigs.sqlStatement)); } } catch (SQLException s) { logger.info("Processing caught SQLException in " + databaseName + ": " + s.getMessage() + CRLF + "SQL Statement is: " + monitorConfigs.sqlStatement); } catch (Exception e) { logger.info("Processing caught Exception in " + databaseName + ": " + e.toString() + CRLF + monitorConfigs.monitorName); } // Check if "reaction" is triggered: If so, set ResultsFound = true as well. if (reaction) { resultsFound = true; } if (resultsFound) { // Log in the current log file: logger.info(notificationMessage); // Determine if we're "Off Hours", and use the right interval if (isInWindow(WINDOW_OFF_HOURS, monitorConfigs, monitorConfigs.startTimeOffHours, monitorConfigs.endTimeOffHours)) { notifyInterval = monitorConfigs.notificationIntervalOffHours; } else { notifyInterval = monitorConfigs.notificationInterval; } // Notify if so configured if (monitorConfigs.notificationFlag == true) { //Send Notification if: // Last Notify Time is blank, or // Current Time is greater than Last Notify Time + Notification Interval if (monitorConfigs.lastNotification == null) { prepareNotification(monitorConfigs, notificationMessage); } else if (notifyInterval > 0){ Calendar rightNow = Calendar.getInstance(); Calendar nextNotify = null; nextNotify = (Calendar)monitorConfigs.lastNotification.clone(); nextNotify.add(Calendar.MINUTE, notifyInterval); if (rightNow.after(nextNotify)) { prepareNotification(monitorConfigs, notificationMessage); } else { // Nothing yet... } } } // Check for any necessary Escalations prepareEscalations(monitorConfigs, notificationMessage); } else if (!monitorConfigs.monitorType.equalsIgnoreCase(TYPE_NODE_DOWN)) { monitorConfigs.lastNotification = null; monitorConfigs.alertStatus = STATUS_OK; if (monitorConfigs.escalations == null) { //Do Nothing } else { // Clear out Escalations too for (int i=0; i < monitorConfigs.escalations.size(); i++) { monitorConfigs.escalations.elementAt(i).notificationSent = false; monitorConfigs.escalations.elementAt(i).issueDetected = null; monitorConfigs.escalations.elementAt(i).lastNotification = null; } } } } private void removeNodeDown(MonitorConfig monitorConfigs) { // Set the Alert Status to OK monitorConfigs.alertStatus = STATUS_OK; // Remove the row from PSNODESDOWN try { Statement stmt = connMonitor.createStatement(); stmt.executeUpdate(generateNodeDownRemovalSQL(monitorConfigs)); stmt.close(); } catch (SQLException s) { logger.info("Processing Node Down caught SQLException in " + databaseName + ": " + s.getMessage()); } catch (Exception e) { logger.info("Processing Node Down caught Exception in " + databaseName + ": " + e.getMessage()); } } private Session createSession() { Properties props = new Properties(); if (IBMonitorSvc.emailUser.isEmpty() || IBMonitorSvc.emailUser.equals("")) { props.setProperty("mail.smtp.host", IBMonitorSvc.emailHost); props.setProperty("mail.smtp.port", String.valueOf(IBMonitorSvc.emailPort)); props.setProperty("mail.smtp.auth", "false"); props.setProperty("mail.transport.protocol", "smtp"); if (IBMonitorSvc.emailPort == 25) { props.setProperty("mail.smtp.starttls.enable","false"); //Important: must start TLS } else { props.setProperty("mail.smtp.starttls.enable","true"); //Important: must start TLS } } else { props.setProperty("mail.smtp.host", IBMonitorSvc.emailHost); props.setProperty("mail.smtp.port", String.valueOf(IBMonitorSvc.emailPort)); props.setProperty("mail.smtp.auth", "true"); props.setProperty("mail.transport.protocol", "smtp"); props.setProperty("mail.smtp.starttls.enable","true"); //Important: must start TLS } Authenticator auth = new SMTPAuthenticator(); Session session = Session.getInstance(props, auth); session.setDebug(false); return session; } // Method to send a notification to configured parties. private void sendNotification(String sendTo, String sendCC, String subject, String message) { try { // create a message Message msg = new MimeMessage(emailSession); // set the from and to address InternetAddress addressFrom = new InternetAddress(IBMonitorSvc.emailReplyTo); msg.setFrom(addressFrom); if (!sendTo.equals("")){ InternetAddress[] addressTo = parseRecipients(sendTo); msg.setRecipients(Message.RecipientType.TO, addressTo); } if (!sendCC.equals("")){ InternetAddress[] addressCC = parseRecipients(sendCC); msg.setRecipients(Message.RecipientType.CC, addressCC); } // Setting the Subject and Content Type msg.setSubject(subject); message = message + CRLF + CRLF + "This is an automated email. Please do not reply to sender."; msg.setContent(message, "text/plain"); Transport.send(msg); } catch(MessagingException me) { logger.info("Error sending secure email message using password auth - " + me.getMessage()); } catch (Exception e) { logger.info("Exception caught when attempting to send email: " + e.getMessage()); } } private InternetAddress[] parseRecipients (String recipientList) { String[] tempArray; InternetAddress[] recipientArray; try { if (recipientList.contains(ON_CALL)) { //replace with list of email addresses/pagers to notify recipientList = updateRecipientsWithOnCall(recipientList); } tempArray = recipientList.split(";"); recipientArray = new InternetAddress[tempArray.length]; for (int index = 0; index < tempArray.length ; index ++ ) { recipientArray[index] = new InternetAddress(tempArray[index]); } return recipientArray; } catch(MessagingException me) { logger.info("Error setting recipientArray values - " + me.getMessage()); } return null; } public String updateRecipientsWithOnCall(String originalRecipients) { String newRecipients = ""; String onCallRecipients = ""; // Open the On Call File, read any items not commented out (with #) File onCallFile = new File(IBMonitorSvc.onCallFileName); try { BufferedReader input = new BufferedReader(new FileReader(onCallFile)); try { String line = null; // not declared within while loop String prefix = ""; while ((line = input.readLine()) != null) { // Check if valid line (does not start with # if (!line.startsWith("#")) { try { if (!line.split(":")[1].equals("") || !(line.split(":") == null)) { onCallRecipients = onCallRecipients + prefix + line.split(":")[1]; prefix = ";"; } } catch (Exception e) { // Nothing, just move to the next one } } } } finally { input.close(); } } catch (IOException ex) { logger.info("On Call File not found (or other file error.)"); return originalRecipients.replaceAll(ON_CALL, ""); } newRecipients = originalRecipients.replaceAll(ON_CALL, onCallRecipients); return newRecipients; } private class SMTPAuthenticator extends javax.mail.Authenticator { public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(IBMonitorSvc.emailUser, IBMonitorSvc.emailPassword); } } // Method to send notification private void prepareNotification(MonitorConfig monitorConfigs, String message) { sendNotification(monitorConfigs.notifyTo, monitorConfigs.notifyCC, monitorConfigs.alertSubject, message); String recipients = monitorConfigs.notifyTo + ";" + monitorConfigs.notifyCC; monitorConfigs.alertStatus = STATUS_ALERT; if (recipients.contains(ON_CALL)) { //replace with list of email/pagers to notify recipients = updateRecipientsWithOnCall(recipients); } logger.info(" " + monitorConfigs.alertStatus + " Sent for " + monitorConfigs.alertSubject + " to " + recipients); monitorConfigs.lastNotification = Calendar.getInstance(); } private void prepareEscalations(MonitorConfig monitorConfigs, String message) { Calendar now = Calendar.getInstance(); // Notify any Escalations if (monitorConfigs.escalations == null) { // Do nothing } else { for (int i=0; i < monitorConfigs.escalations.size(); i ++) { Calendar nextNotify = null; EscalationConfig escalation = monitorConfigs.escalations.elementAt(i); // Set the Date/Time the issue was detected if it is null. if (escalation.issueDetected == null) { escalation.issueDetected = now; } // Find time an Escalation should fire if (!escalation.notificationSent) { nextNotify = (Calendar)escalation.issueDetected.clone(); nextNotify.add(Calendar.MINUTE, escalation.escalationDelay); } else if (escalation.notificationInterval > 0){ nextNotify = (Calendar)escalation.lastNotification.clone(); nextNotify.add(Calendar.MINUTE, escalation.notificationInterval); } // Check if monitor should fire if (nextNotify != null && nextNotify.compareTo(now) <=0 ) { sendNotification(escalation.email, "", monitorConfigs.alertSubject, message + CRLF + escalation.emailText); escalation.notificationSent = true; escalation.lastNotification = now; String recipients = monitorConfigs.notifyTo + ";" + monitorConfigs.notifyCC; logger.info(" ESCALATION: " + monitorConfigs.alertStatus + " Sent for " + monitorConfigs.alertSubject + " to " + recipients); } } } } private void prepareEscalationsEach(MonitorConfig monitorConfigs, String message, String transactionID) { Calendar now = Calendar.getInstance(); // Notify any Escalations if (monitorConfigs.escalations == null) { // Do nothing } else { for (int i=0; i < monitorConfigs.escalations.size(); i ++) { EscalationConfig escalation = monitorConfigs.escalations.elementAt(i); if (checkPreviouslyNotified(monitorConfigs.monitorName, monitorConfigs.monitorType, transactionID, i + 1)) { Calendar nextNotify = null; // Set the Date/Time the issue was detected - even if not null for Notify Each escalation.issueDetected = now; nextNotify = (Calendar)escalation.issueDetected.clone(); nextNotify.add(Calendar.MINUTE, escalation.escalationDelay); // Check if monitor should fire if (nextNotify != null && nextNotify.compareTo(now) <=0 ) { String subject = monitorConfigs.alertSubject + " Transaction ID: " + transactionID; sendNotification(escalation.email, "", subject, message + CRLF + escalation.emailText.replaceAll("TRANSACTIONID", transactionID)); escalation.notificationSent = true; escalation.lastNotification = now; String recipients = monitorConfigs.notifyTo + ";" + monitorConfigs.notifyCC; logger.info(" ESCALATION (EACH): " + monitorConfigs.alertStatus + " Sent for " + subject + " to " + recipients); } } else { escalation.notificationSent = true; escalation.lastNotification = now; } } } } private void notifyEach(MonitorConfig configs, String transactionID) { int notifyInterval = 0; // Determine if we're "Off Hours", and use the right interval if (isInWindow(WINDOW_OFF_HOURS, configs, configs.startTimeOffHours, configs.endTimeOffHours)) { notifyInterval = configs.notificationIntervalOffHours; } else { notifyInterval = configs.notificationInterval; } String msg = configs.alertText + " Transaction ID: " + transactionID; if (checkPreviouslyNotified(configs.monitorName, configs.monitorType, transactionID, 0)) { prepareNotification(configs, msg); } else if (notifyInterval > 0){ if (configs.lastNotification == null) { configs.lastNotification = Calendar.getInstance(); } Calendar rightNow = Calendar.getInstance(); Calendar nextNotify = null; nextNotify = (Calendar)configs.lastNotification.clone(); nextNotify.add(Calendar.MINUTE, notifyInterval); if (rightNow.after(nextNotify)) { prepareNotification(configs, configs.alertText); } } prepareEscalationsEach(configs, msg, transactionID); } private boolean checkPreviouslyNotified(String eventName, String eventType, String transactionID, int escalation) { Connection conn; conn = connection.openDBConnection(databaseHost, databaseUser, databasePassword); try { Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(SELECT_EACH.replace(":1", databaseName) .replace(":2", eventName) .replace(":3", eventType) .replace(":4", String.valueOf(escalation)) .replace(":5", transactionID)); if (rs.next()) { if (rs.getString(1).equalsIgnoreCase("X")) { stmt.close(); return false; } } // If the data has not been added, insert the row, but return false. insertTransaction(conn, eventName, eventType, transactionID, escalation); stmt.close(); } catch (SQLException s) { logger.info("SQLException encountered in " + databaseName + ": " + s.getMessage()); } return true; } private void insertTransaction(Connection conn, String eventName, String eventType, String transactionID, int escalation) { try { // If the data has not been added, insert the row, but return false. Statement stmt = conn.createStatement(); stmt.execute(INSERT_TRANSACTION.replace(":1", databaseName) .replace(":2", eventName) .replace(":3", eventType) .replace(":4", String.valueOf(escalation)) .replace(":5", transactionID)); stmt.close(); } catch (SQLException s) { logger.info("SQLException encountered in " + databaseName + ": " + s.getMessage()); } } /* How to update Messages: * Status Status String * 0 ERROR * 1 NEW * 2 START * 3 WRKNG * 4 DONE * 5 RETRY * 6 TIME * 7 EDIT (?) * 8 CNCLD * 9 HOLD (?) * * Publication Contract Record/Field: PSAPMSGPUBCON/PUBCONSTATUS * Subscription Contract Record/Field: PSAPMSGSUBCON/SUBCONSTATUS * Message Instance Record/Field: PSAPMSGPUBHDR/PUBSTATUS */ private void executeUpdate(String transactionID, String transactionType, String updAction, String databaseName, Connection connMonitor) { String sqlUpdate = ""; String statusString = ""; String statusField = ""; String sqlRecord = ""; int statusVal = 0; //Determine the Record/Field to update if (transactionType.equalsIgnoreCase(PUBLICATION_CONTRACT)) { sqlRecord = "PSAPMSGPUBCON"; statusField = "PUBCONSTATUS"; } else if (transactionType.equalsIgnoreCase(SUBSCRIPTION_CONTRACT)) { sqlRecord = "PSAPMSGSUBCON"; statusField = "SUBCONSTATUS"; } else if (transactionType.equalsIgnoreCase(MESSAGE_INSTANCE)) { sqlRecord = "PSAPMSGPUBHDR"; statusField = "PUBSTATUS"; } // Set the Status Field and Status String if (updAction.equalsIgnoreCase(ACTION_CANCEL)) { statusVal = 8; statusString = "CNCLD"; } else if (updAction.equalsIgnoreCase(ACTION_RESUBMIT)) { statusVal = 1; statusString = "NEW"; } else { return; } // Build the SQL Update if (!sqlRecord.equalsIgnoreCase("") && !statusString.equalsIgnoreCase("")) { sqlUpdate = "Update " + databaseSchema + "." + sqlRecord; sqlUpdate = sqlUpdate + " Set " + statusField + " = " + statusVal + ", STATUSSTRING = '" + statusString + "'"; sqlUpdate = sqlUpdate + " Where IBTRANSACTIONID = '" + transactionID + "'"; try { Statement stmt = connMonitor.createStatement(); stmt.executeUpdate(sqlUpdate); stmt.close(); } catch (SQLException s) { logger.info("SQLException encountered in " + databaseName + ": " + s.getMessage()); } } else { logger.info("Unable to update Transaction ID: " + transactionID + " in " + databaseName + "."); } } private void setMonitorDownTime(String tmpStartDay, String tmpStartTime, String tmpEndDay, String tmpEndTime) { String [] startTimes; String [] endTimes; Calendar today = Calendar.getInstance(); int currentDayofWeek = today.get(Calendar.DAY_OF_WEEK); int currentDay = today.get(Calendar.DAY_OF_MONTH); int currentMonth = today.get(Calendar.MONTH); int currentYear = today.get(Calendar.YEAR); startTimes = tmpStartTime.split(":"); endTimes = tmpEndTime.split(":"); downTimeStart = Calendar.getInstance(); downTimeEnd = Calendar.getInstance(); downTimeStart.set(currentYear, currentMonth, currentDay, Integer.parseInt(startTimes[0]), Integer.parseInt(startTimes[1])); downTimeEnd.set(currentYear, currentMonth, currentDay, Integer.parseInt(endTimes[0]), Integer.parseInt(endTimes[1])); // Shift the date accordingly downTimeStart.add(Calendar.DATE, (Integer.parseInt(tmpStartDay) - currentDayofWeek)); downTimeEnd.add(Calendar.DATE, (Integer.parseInt(tmpEndDay) - currentDayofWeek)); if (downTimeStart.after(downTimeEnd)) { downTimeEnd.add(Calendar.DATE, downTimeFrequency); } boolean adjust = true; while (adjust) { if (downTimeEnd.before(today)) { downTimeStart.add(Calendar.DATE, downTimeFrequency); downTimeEnd.add(Calendar.DATE, downTimeFrequency); } else { adjust = false; } } } private void setMonitorHours(MonitorConfig monitor, String tmpStartTime, String tmpEndTime, String strWindowType) { String [] startTimes; String [] endTimes; Calendar today = Calendar.getInstance(); int currentDay = today.get(Calendar.DAY_OF_MONTH); int currentMonth = today.get(Calendar.MONTH); int currentYear = today.get(Calendar.YEAR); startTimes = tmpStartTime.split(":"); endTimes = tmpEndTime.split(":"); // Create the startTime and endTime values Calendar startTime = Calendar.getInstance(); Calendar endTime = Calendar.getInstance(); startTime.set(currentYear, currentMonth, currentDay, Integer.parseInt(startTimes[0]), Integer.parseInt(startTimes[1])); endTime.set(currentYear, currentMonth, currentDay, Integer.parseInt(endTimes[0]), Integer.parseInt(endTimes[1])); if (strWindowType.equals(WINDOW_ACTIVE)) { monitor.startTime = startTime; monitor.endTime = endTime; // If Start Time is after End Time, increase End Time if (monitor.startTime.after(monitor.endTime)) { monitor.endTime.add(Calendar.DATE, 1); } } else if (strWindowType.equals(WINDOW_OFF_HOURS)) { monitor.startTimeOffHours = startTime; monitor.endTimeOffHours = endTime; // If Start Time Off Hours is after End Time Off Hours, increase End Time Off Hours if (monitor.startTimeOffHours.after(monitor.endTimeOffHours)) { monitor.endTimeOffHours.add(Calendar.DATE, 1); } } } private boolean isDownTime() { Calendar rightNow = Calendar.getInstance(); if (downTimeStart == null) { return false; } else { if (downTimeStart.before(rightNow) && downTimeEnd.after(rightNow)) { // Valid monitor for right now return true; } else if (downTimeEnd.before(rightNow)) { // Need to increment the date on the monitor downTimeStart.add(Calendar.DATE, downTimeFrequency); downTimeEnd.add(Calendar.DATE, downTimeFrequency); return false; } } return false; } private boolean isInWindow(String strWindowType, MonitorConfig monitor, Calendar startTime, Calendar endTime ) { Calendar rightNow = Calendar.getInstance(); if (startTime == null) { if (strWindowType.equals(WINDOW_OFF_HOURS)) { // Monitor is not configured with specific off hours times - so we are NEVER in "Off Hours" return false; } else { // Monitor is not configured with specific times - so we are always in that period return true; } } else { // Monitor has time conditions if (startTime.before(rightNow) && endTime.after(rightNow)) { // Valid monitor for right now return true; } else if (endTime.before(rightNow)) { if (strWindowType.equals(WINDOW_ACTIVE)) { int daysToAdd = 1; if (monitor.monitorType.equalsIgnoreCase(TYPE_NODE_DOWN)) { daysToAdd = monitor.frequency; } // Need to increment the date on the monitor monitor.startTime.add(Calendar.DATE, daysToAdd); monitor.endTime.add(Calendar.DATE, daysToAdd); return false; } else if (strWindowType.equals(WINDOW_OFF_HOURS)) { // Need to increment the date on the monitor Off Hours settings monitor.startTimeOffHours.add(Calendar.DATE, 1); monitor.endTimeOffHours.add(Calendar.DATE, 1); return false; } else if (strWindowType.equals(WINDOW_DOWN_TIME)) { // Need to increment the date on the monitor Down Times downTimeStart.add(Calendar.DATE, downTimeFrequency); downTimeEnd.add(Calendar.DATE, downTimeFrequency); return false; } } } return false; } private class MonitorConfig { public String monitorName; public String monitorType; public String operationType; public String serviceOperation; public String serviceOperationExclude; public String pubNode; public String subNode; public String status; public int age; public int threshold; public String action; public String reaction; public String alertStatus; public String sqlStatement; public String notifyTo; public String notifyCC; public String alertSubject; public String alertText; public int retryCount; public int timeToCheck; public int notificationInterval; //specified in minutes public Calendar lastNotification; public Calendar startTime; public Calendar endTime; public Calendar startTimeOffHours; public Calendar endTimeOffHours; public int notificationIntervalOffHours; //specified in minutes public boolean notificationFlag; public int frequency; // Specified in days public Vector<EscalationConfig> escalations; public CustomActionConfig customAction; private MonitorConfig() { } private MonitorConfig(MonitorEventType configNode) { List<EscalationType> escalationList; String strStartDay = ""; String strStartTime = ""; String strEndDay = ""; String strEndTime = ""; String offHoursTimeStart = ""; String offHoursTimeEnd = ""; monitorName = configNode.getMonitorName(); operationType = configNode.getOperationType(); if (operationType.equalsIgnoreCase(PUBLICATION_CONTRACT) || operationType.equalsIgnoreCase(SUBSCRIPTION_CONTRACT) || operationType.equalsIgnoreCase(MESSAGE_INSTANCE) ) { monitorType = TYPE_MESSAGE; } else if (operationType.equalsIgnoreCase(PUBLICATION_CONTRACT_THRESHOLD) || operationType.equalsIgnoreCase(SUBSCRIPTION_CONTRACT_THRESHOLD) || operationType.equalsIgnoreCase(MESSAGE_INSTANCE_THRESHOLD) ) { monitorType = TYPE_THRESHOLD; } else if (operationType.equalsIgnoreCase(PUBLICATION_CONTRACT_AGING) || operationType.equalsIgnoreCase(SUBSCRIPTION_CONTRACT_AGING) || operationType.equalsIgnoreCase(MESSAGE_INSTANCE_AGING) ) { monitorType = TYPE_AGING; } else if (operationType.equalsIgnoreCase(NODE_DOWNTIME)) { monitorType = TYPE_NODE_DOWN; } serviceOperation = getNodeValue(configNode.getServiceOperation(), ""); serviceOperationExclude = getNodeValue(configNode.getServiceOperationExclude(), ""); pubNode = getNodeValue(configNode.getPublishNode(), ""); subNode = getNodeValue(configNode.getSubscribeNode(), ""); status = getNodeValue(configNode.getStatus(), ""); age = getNodeValue(configNode.getAge(), 0); threshold = getNodeValue(configNode.getThreshold(), 0); timeToCheck = getNodeValue(configNode.getTimeToCheck(), 0); action = getNodeValue(configNode.getAction(), ""); reaction = getNodeValue(configNode.getReaction(), ""); // Check for hasNotifyEach if (action.equalsIgnoreCase(ACTION_NOTIFY_EACH) || reaction.equalsIgnoreCase(ACTION_NOTIFY_EACH)) { hasNotifyEach = true; } notifyTo = getNodeValue(configNode.getNotifyTo(), ""); notifyCC = getNodeValue(configNode.getNotifyCC(), ""); alertSubject = getNodeValue(configNode.getAlertSubject(), ""); alertText = getNodeValue(configNode.getAlertText(), ""); // Set notificationFlag based on Action if (action.equalsIgnoreCase(ACTION_NOTIFY)) { notificationFlag = true; } else if (action.equalsIgnoreCase(ACTION_CANCEL)) { notificationFlag = true; } else if (action.equalsIgnoreCase(ACTION_CUSTOM)) { notificationFlag = true; } else if (action.equalsIgnoreCase(ACTION_RETRY_REACT)) { notificationFlag = true; } else { notificationFlag = false; } retryCount = getNodeValue(configNode.getRetryCount(), 0); notificationInterval = getNodeValue(configNode.getNotifyInterval(), 0); alertStatus = STATUS_OK; lastNotification = null; if (monitorType.equalsIgnoreCase(TYPE_NODE_DOWN)) { strStartDay = getNodeValue(configNode.getDownTimeStartDay(), ""); strStartTime = getNodeValue(configNode.getDownTimeStart(), ""); strEndDay = getNodeValue(configNode.getDownTimeEndDay(), ""); strEndTime = getNodeValue(configNode.getDownTimeEnd(), ""); frequency = getNodeValue(configNode.getDownTimeFrequency(), 0); // Schedule first occurrence setNodeDownTime(strStartDay, strStartTime, strEndDay, strEndTime); } else { strStartTime = getNodeValue(configNode.getStartTime(), ""); strEndTime = getNodeValue(configNode.getEndTime(), ""); // Allow any Monitor to use Start/End times if (!strStartTime.equalsIgnoreCase("") && !strEndTime.equalsIgnoreCase("")) { setMonitorHours(this, strStartTime, strEndTime, WINDOW_ACTIVE); } } // Set Off Hours monitoring, if configured // If we have a specific notification interval - use Off Hours notificationIntervalOffHours = getNodeValue(configNode.getNotifyIntervalOffHours(), 0); if (notificationIntervalOffHours > 0) { offHoursTimeStart = getNodeValue(configNode.getStartTimeOffHours(), defaultOffHoursTimeStart); offHoursTimeEnd = getNodeValue(configNode.getEndTimeOffHours(), defaultOffHoursTimeEnd); if (!offHoursTimeStart.equalsIgnoreCase("") && !offHoursTimeEnd.equalsIgnoreCase("")) { setMonitorHours(this, offHoursTimeStart, offHoursTimeEnd, WINDOW_OFF_HOURS); } } // Get any custom actions if (action.equalsIgnoreCase(ACTION_CUSTOM)) { customAction = new CustomActionConfig(configNode.getCustomAction().get(0)); } // Configure any Escalations escalationList = configNode.getEscalation(); // Get each specific monitor to execute for (int index = 0; index < escalationList.size(); index ++ ) { if (escalations == null) { escalations = new Vector<EscalationConfig>(); } escalations.add(index, new EscalationConfig(escalationList.get(index))); } sqlStatement = generateMonitorSQL(this); } private void setNodeDownTime(String tmpStartDay, String tmpStartTime, String tmpEndDay, String tmpEndTime) { String [] startTimes; String [] endTimes; Calendar today = Calendar.getInstance(); int currentDayofWeek = today.get(Calendar.DAY_OF_WEEK); int currentDay = today.get(Calendar.DAY_OF_MONTH); int currentMonth = today.get(Calendar.MONTH); int currentYear = today.get(Calendar.YEAR); startTimes = tmpStartTime.split(":"); endTimes = tmpEndTime.split(":"); startTime = Calendar.getInstance(); endTime = Calendar.getInstance(); startTime.set(currentYear, currentMonth, currentDay, Integer.parseInt(startTimes[0]), Integer.parseInt(startTimes[1])); endTime.set(currentYear, currentMonth, currentDay, Integer.parseInt(endTimes[0]), Integer.parseInt(endTimes[1])); // Shift the date accordingly startTime.add(Calendar.DATE, (Integer.parseInt(tmpStartDay) - currentDayofWeek)); endTime.add(Calendar.DATE, (Integer.parseInt(tmpEndDay) - currentDayofWeek)); if (startTime.after(endTime)) { endTime.add(Calendar.DATE, frequency); } boolean adjust = true; while (adjust) { if (endTime.before(today)) { startTime.add(Calendar.DATE, frequency); endTime.add(Calendar.DATE, frequency); } else { adjust = false; } } } // Function to perform the Retry/React logic private boolean retryReact(String transactionID) { boolean react = false; String sqlRecord = ""; String statusField = ""; //Determine the Record/Field to update if (operationType.equalsIgnoreCase(PUBLICATION_CONTRACT)) { sqlRecord = "PSAPMSGPUBCON"; statusField = "PUBCONSTATUS"; } else if (operationType.equalsIgnoreCase(SUBSCRIPTION_CONTRACT)) { sqlRecord = "PSAPMSGSUBCON"; statusField = "SUBCONSTATUS"; } else if (operationType.equalsIgnoreCase(MESSAGE_INSTANCE)) { sqlRecord = "PSAPMSGPUBHDR"; statusField = "PUBSTATUS"; } try { Statement stmt = connMonitor.createStatement(); String sqlUpdate = "Update " + databaseSchema + "." + sqlRecord; sqlUpdate = sqlUpdate + " Set " + statusField + " = " + 1 + ", STATUSSTRING = 'NEW'"; sqlUpdate = sqlUpdate + " Where IBTRANSACTIONID = '" + transactionID + "' and RETRYCOUNT < " + retryCount; if (stmt.executeUpdate(sqlUpdate) == 0) { react = true; if (reaction.equalsIgnoreCase(ACTION_CANCEL)) { executeUpdate(transactionID, operationType, reaction, databaseName, connMonitor); logger.info("Retry/Resubmit executeUpdate fired on Transaction ID: " + transactionID + " in " + databaseName + ": Retry Count = " + retryCount); } else if (reaction.equalsIgnoreCase(ACTION_CUSTOM)) { // Fire the Custom Action customAction.fireAction(transactionID); } else if (reaction.equals(ACTION_NOTIFY_EACH)) { notifyEach(this, transactionID); } else if (!reaction.equals(ACTION_NOTIFY)) { logger.info("Invalid Reaction encountered on Transaction ID: " + transactionID + " in " + databaseName); } } stmt.close(); } catch (SQLException s) { logger.info("SQLException encountered in " + databaseName + ": " + s.getMessage()); } return react; } } private String getNodeValue(Object nodeValue, String defaultValue) { if (nodeValue == null) { return defaultValue; } else { return (String)nodeValue; } } private int getNodeValue(Object nodeValue, int defaultValue) { if (nodeValue == null) { return defaultValue; } else { return (Integer)nodeValue; } } private class EscalationConfig{ public String email; public String emailText; public boolean notificationSent; public int escalationDelay; public int notificationInterval; //specified in minutes public Calendar issueDetected; public Calendar lastNotification; private EscalationConfig(){ } private EscalationConfig(EscalationType escalationNode) { EmailAdditionsType emailAdditions; notificationSent = false; email = getNodeValue(escalationNode.getNotifyTo(), ""); escalationDelay = getNodeValue(escalationNode.getEscalationDelay(), 0); notificationInterval = getNodeValue(escalationNode.getNotificationInterval(), 0); issueDetected = null; lastNotification = null; emailText = ""; emailAdditions = escalationNode.getEmailAdditions(); emailText = emailText + CRLF + getEmailAdditions(emailAdditions); } private String getEmailAdditions(EmailAdditionsType emailAddition) { String tmpText = ""; List<String> emailLines; emailLines = emailAddition.getEmailLine(); // Get each specific email Tag for (int index = 0; index < emailLines.size(); index ++ ) { tmpText = tmpText + CRLF + emailLines.get(index); } return tmpText; } } private class CustomActionConfig{ private Vector<String> sqlCommands; private CustomActionConfig(){ } private CustomActionConfig(CustomActionType customActionNode) { sqlCommands = getSQLCommands(customActionNode.getSqlCommand()); } private Vector<String> getSQLCommands(List<String> sqlList) { Vector<String> sqlCommands = new Vector<String>(); // Get each specific SQLs to execute for (int index = 0; index < sqlList.size(); index ++ ) { sqlCommands.add(sqlList.get(index)); } return sqlCommands; } private void fireAction(String transactionID) { try { Statement stmt = connMonitor.createStatement(); for (int index = 0; index < sqlCommands.size(); index ++) { String sqlCommand = sqlCommands.get(index).replaceAll("<TRANSACTIONID>", transactionID); stmt.executeUpdate(sqlCommand); } stmt.close(); } catch (SQLException s) { logger.info("SQLException encountered in " + databaseName + ": " + s.getMessage()); } } } }