/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2010-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.reporting.availability; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; import java.util.ListIterator; import java.util.TreeMap; import org.exolab.castor.xml.MarshalException; import org.exolab.castor.xml.ValidationException; import org.opennms.core.utils.ThreadCategory; import org.opennms.netmgt.config.CatFactory; import org.opennms.netmgt.config.CategoryFactory; import org.opennms.netmgt.config.categories.Categorygroup; import org.opennms.netmgt.config.categories.Catinfo; import org.opennms.reporting.availability.svclayer.AvailabilityDataService; import org.opennms.reporting.datablock.Node; /** * AvailabilityData collects all the outages for all node/ip/service * combination and stores it appropriately in the m_nodes structure. * * @author <A HREF="mailto:jacinta@oculan.com">Jacinta Remedios </A> */ public class AvailabilityData { /** * The log4j category used to log debug messsages and statements. */ private static final String LOG4J_CATEGORY = "OpenNMS.Report"; /** * List of Node objects that satisfy the filter rule for the category. */ private List<Node> m_nodes; /** * End Time of the report. */ private long m_endTime; /** * End Time of the report. */ private long m_startTime; /** * End Time of the last month. */ private long m_lastMonthEndTime; /** * Number of days in the last month */ private int m_daysInLastMonth; /** * Category Factory */ CatFactory m_catFactory; /** * Section Index */ private int m_sectionIndex = 0; /** * Availability Data Service */ private AvailabilityDataService m_availabilityDataService; // This version used when end date availalable as strings (from command line?) /** * <p>fillReport</p> * * @param categoryName a {@link java.lang.String} object. * @param report a {@link org.opennms.reporting.availability.Report} object. * @param format a {@link java.lang.String} object. * @param monthFormat a {@link java.lang.String} object. * @param startMonth a {@link java.lang.String} object. * @param startDate a {@link java.lang.String} object. * @param startYear a {@link java.lang.String} object. * @throws java.io.IOException if any. * @throws org.exolab.castor.xml.MarshalException if any. * @throws org.exolab.castor.xml.ValidationException if any. * @throws java.lang.Exception if any. */ public void fillReport(String categoryName, Report report, String format, String monthFormat, String startMonth, String startDate, String startYear) throws IOException, MarshalException, ValidationException, Exception { Calendar cal = new GregorianCalendar(); cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(startDate)); cal.set(Calendar.MONTH, Integer.parseInt(startMonth)); cal.set(Calendar.YEAR, Integer.parseInt(startYear)); cal.set(Calendar.HOUR_OF_DAY, 23); cal.set(Calendar.MINUTE, 59); cal.set(Calendar.SECOND, 59); generateData(categoryName, report, format, monthFormat, new Date(cal.getTimeInMillis())); } // This version used when end date availalable as a java Date /** * <p>fillReport</p> * * @param categoryName a {@link java.lang.String} object. * @param report a {@link org.opennms.reporting.availability.Report} object. * @param format a {@link java.lang.String} object. * @param monthFormat a {@link java.lang.String} object. * @param periodEndDate a {@link java.util.Date} object. * @throws java.io.IOException if any. * @throws org.exolab.castor.xml.MarshalException if any. * @throws org.exolab.castor.xml.ValidationException if any. * @throws java.lang.Exception if any. */ public void fillReport(String categoryName, Report report, String format, String monthFormat, Date periodEndDate) throws IOException, MarshalException, ValidationException, Exception { generateData(categoryName, report, format, monthFormat, periodEndDate); } private void generateData(String categoryName, Report report, String format, String monthFormat, Date periodEndDate) throws IOException, MarshalException, ValidationException, Exception { String oldPrefix = ThreadCategory.getPrefix(); ThreadCategory.setPrefix(LOG4J_CATEGORY); ThreadCategory log = ThreadCategory.getInstance(this.getClass()); log.debug("Inside AvailabilityData"); m_nodes = new ArrayList<Node>(); initializeInterval(periodEndDate); Catinfo config = null; try { CategoryFactory.init(); m_catFactory = CategoryFactory.getInstance(); config = m_catFactory.getConfig(); } catch (IOException e) { log.fatal("Initializing CategoryFactory", e); throw e; } catch (MarshalException e) { log.fatal("Initializing CategoryFactory", e); throw e; } catch (ValidationException e) { log.fatal("Initializing CategoryFactory", e); throw e; } // FIXME There's some magic in here regarding multiple categories in a report if (log.isDebugEnabled()) { log.debug("CATEGORY " + categoryName); } m_catFactory.getReadLock().lock(); try { if (categoryName.equals("") || categoryName.equals("all")) { int catCount = 0; if (log.isDebugEnabled()) { log.debug("catCount " + catCount); } for(final Categorygroup cg : config.getCategorygroupCollection()) { for(org.opennms.netmgt.config.categories.Category cat : cg.getCategories().getCategoryCollection()) { if (log.isDebugEnabled()) { log.debug("CATEGORY " + cat.getLabel()); } catCount++; populateDataStructures(cat, report, format, monthFormat, catCount); } } if (log.isDebugEnabled()) { log.debug("catCount " + catCount); } } else { org.opennms.netmgt.config.categories.Category cat = (org.opennms.netmgt.config.categories.Category) m_catFactory.getCategory(categoryName); if (log.isDebugEnabled()) { log.debug("CATEGORY - now populating data structures " + cat.getLabel()); } populateDataStructures(cat, report, format, monthFormat, 1); } final SimpleDateFormat simplePeriod = new SimpleDateFormat("MMMMMMMMMMM dd, yyyy"); final String reportPeriod = simplePeriod.format(new java.util.Date(m_startTime)) + " - " + simplePeriod.format(new java.util.Date(m_endTime)); Created created = report.getCreated(); if (created == null) { created = new Created(); } created.setPeriod(reportPeriod); report.setCreated(created); } finally { m_catFactory.getReadLock().unlock(); } if (log.isDebugEnabled()) { log.debug("After availCalculations"); } ThreadCategory.setPrefix(oldPrefix); } /** * Populates the data structure for this category. This method only * computes for monitored services in this category. * * @param cat * Category * @param report * Report Castor class * @param format * SVG-specific/all reports */ private void populateDataStructures( org.opennms.netmgt.config.categories.Category cat, Report report, String format, String monthFormat, int catIndex) throws Exception { ThreadCategory log = ThreadCategory.getInstance(this.getClass()); if (log.isDebugEnabled()) log.debug("Inside populate data Structures" + catIndex); report.setCatCount(catIndex); log.debug("Inside populate data Structures"); try { List<String> monitoredServices = new ArrayList<String>(cat.getServiceCollection()); if (m_availabilityDataService == null) log.debug("DATA SERVICE IS NULL"); m_nodes = m_availabilityDataService.getNodes(cat, m_startTime, m_endTime); if (log.isDebugEnabled()) { log.debug("Nodes " + m_nodes); } // remove all the nodes that do not have outages ListIterator<Node> cleanNodes = m_nodes.listIterator(); while (cleanNodes.hasNext()) { Node node = (Node) cleanNodes.next(); if (node != null && !node.hasOutages()) { if (log.isDebugEnabled()) { log.debug("Removing node: " + node); } cleanNodes.remove(); } } if (log.isDebugEnabled()) { log.debug("Cleaned Nodes " + m_nodes); } TreeMap<Double, List<String>> topOffenders = getPercentNode(); if (log.isDebugEnabled()) { log.debug("TOP OFFENDERS " + topOffenders); } if (m_nodes.size() <= 0) { m_nodes = null; } if (m_nodes != null) { AvailCalculations availCalculations = new AvailCalculations( m_nodes, m_endTime, m_lastMonthEndTime, monitoredServices, report, topOffenders, cat.getWarning(), cat.getNormal(), cat.getComment(), cat.getLabel(), format, monthFormat, catIndex, m_sectionIndex); m_sectionIndex = availCalculations.getSectionIndex(); report.setSectionCount(m_sectionIndex - 1); } else { org.opennms.reporting.availability.Category category = new org.opennms.reporting.availability.Category(); category.setCatComments(cat.getComment()); category.setCatName(cat.getLabel()); category.setCatIndex(catIndex); category.setNodeCount(0); category.setIpaddrCount(0); category.setServiceCount(0); Section section = new Section(); section.setSectionIndex(m_sectionIndex); org.opennms.reporting.availability.CatSections catSections = new org.opennms.reporting.availability.CatSections(); catSections.addSection(section); category.addCatSections(catSections); org.opennms.reporting.availability.Categories categories = report.getCategories(); categories.addCategory(category); report.setCategories(categories); report.setSectionCount(m_sectionIndex); m_sectionIndex++; } } catch (Throwable e) { log.fatal("Exception has occurred", e); throw new Exception(e); } } /** * Initialize the endTime, start Time, last Months end time and number of days in the * last month. */ private void initializeInterval(Date periodEndDate) { Calendar tempCal = new GregorianCalendar(); tempCal.setTime(periodEndDate); // This used to be the day prior to the report being run, which is confusing // tempCal.add(Calendar.DAY_OF_MONTH, -1); tempCal.set(Calendar.HOUR_OF_DAY, 23); tempCal.set(Calendar.MINUTE, 59); tempCal.set(Calendar.SECOND, 59); tempCal.set(Calendar.MILLISECOND, 999); m_endTime = tempCal.getTimeInMillis(); // Calculate first of the month, 12 months ago. tempCal.add(Calendar.YEAR, -1); tempCal.set(Calendar.DAY_OF_MONTH, 1); tempCal.set(Calendar.HOUR_OF_DAY, 0); tempCal.set(Calendar.MINUTE, 0); tempCal.set(Calendar.SECOND, 0); tempCal.set(Calendar.MILLISECOND, 0); m_startTime = tempCal.getTimeInMillis(); // Reset tempCal to m_end time and calculate last month calendar details tempCal.setTimeInMillis(m_endTime); tempCal.add(Calendar.MONTH, -1); m_daysInLastMonth = tempCal.getActualMaximum(Calendar.DAY_OF_MONTH); // Not entirely sure if this is needed tempCal.set(Calendar.DAY_OF_MONTH, m_daysInLastMonth); tempCal.set(Calendar.HOUR_OF_DAY, 23); tempCal.set(Calendar.MINUTE, 59); tempCal.set(Calendar.SECOND, 59); tempCal.set(Calendar.MILLISECOND, 999); m_lastMonthEndTime = tempCal.getTimeInMillis(); } /** * Returns the nodes. * * @return a {@link java.util.List} object. */ public List<Node> getNodes() { return m_nodes; } /** * Returns percent/node combinations for the last month. This is used to * get the last months top 20 offenders * * @return a {@link java.util.TreeMap} object. */ public TreeMap<Double, List<String>> getPercentNode() { ThreadCategory log = ThreadCategory.getInstance(this.getClass()); int days = m_daysInLastMonth; long endTime = m_lastMonthEndTime; Calendar cal = new GregorianCalendar(); cal.setTimeInMillis(endTime); cal.add(Calendar.DATE, -1 * days); long rollingWindow = endTime - cal.getTime().getTime(); long startTime = cal.getTime().getTime(); if (log.isDebugEnabled()) { log.debug("getPercentNode: Start time " + new java.util.Date(startTime)); log.debug("getPercentNode: End time " + new java.util.Date(endTime)); } TreeMap<Double, List<String>> percentNode = new TreeMap<Double, List<String>>(); for(Node node : m_nodes) { if (node != null) { double percent = node.getPercentAvail(endTime, rollingWindow); String nodeName = node.getName(); if (log.isDebugEnabled()) { log.debug("Node " + nodeName + " " + percent + "%"); } if (percent < 100.0) { List<String> nodeNames = percentNode.get(new Double(percent)); if (nodeNames == null) { nodeNames = new ArrayList<String>(); } nodeNames.add(nodeName); percentNode.put(new Double(percent), nodeNames); } } } if (log.isDebugEnabled()) { log.debug("Percent node " + percentNode); } return percentNode; } /** * <p>setAvailabilityDataService</p> * * @param availabilityDataService a {@link org.opennms.reporting.availability.svclayer.AvailabilityDataService} object. */ public void setAvailabilityDataService( AvailabilityDataService availabilityDataService) { ThreadCategory log = ThreadCategory.getInstance(this.getClass()); log.debug("setting m_availabilityDataService"); m_availabilityDataService = availabilityDataService; } }