/******************************************************************************* * 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.web.category; import java.io.IOException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspWriter; import org.exolab.castor.xml.MarshalException; import org.exolab.castor.xml.ValidationException; import org.opennms.core.utils.ThreadCategory; import org.opennms.netmgt.config.ViewsDisplayFactory; import org.opennms.netmgt.config.viewsdisplay.Section; import org.opennms.netmgt.config.viewsdisplay.View; /** * <p>CategoryList class.</p> * * @author ranger * @version $Id: $ */ public class CategoryList { protected CategoryModel m_model; /** * Display rules from viewsdisplay.xml. If null, then just show all known * categories under the header "Category". (See the getSections method.) */ protected Section[] m_sections; private int m_disconnectTimeout; /** * <p>Constructor for CategoryList.</p> * * @throws javax.servlet.ServletException if any. */ public CategoryList() throws ServletException { try { m_model = CategoryModel.getInstance(); } catch (Throwable e) { log().error("failed to instantiate the category model: " + e, e); throw new ServletException("failed to instantiate the category model: " + e, e); } try { ViewsDisplayFactory.init(); ViewsDisplayFactory viewsDisplayFactory = ViewsDisplayFactory.getInstance(); View view = viewsDisplayFactory.getDefaultView(); if (view != null) { m_sections = view.getSection(); m_disconnectTimeout = viewsDisplayFactory.getDisconnectTimeout(); log().debug("found display rules from viewsdisplay.xml"); } else { log().debug("did not find display rules from viewsdisplay.xml"); } } catch (Throwable e) { log().error("Couldn't open viewsdisplay factory on categories box: " + e, e); } } private ThreadCategory log() { return ThreadCategory.getInstance(getClass()); } /** * For the given map of category names to Category objects, organize the * categories into the currently active display rules. * * <p> * If there are no display rules, a single section named <em>Category</em> * will be returned. It will include all the categories in the category map, * in alphabetical order by category name. * </p> * * @param categoryMap a {@link java.util.Map} object. * @return a {@link java.util.List} object. * @throws java.io.IOException if any. */ public List<Section> getSections(Map<String, Category> categoryMap) throws IOException { if (m_sections != null) { // Just return the display rules as a list. return Arrays.asList(m_sections); } List<Section> sectionList = null; Section section = new Section(); section.setSectionName("Category"); // Put the categories in a TreeMap to sort them alphabetically. TreeMap<String, Category> orderedMap = new TreeMap<String, Category>(categoryMap); // Iterate over the categories, adding each to the name list. for (Iterator<Map.Entry<String,Category>> i = orderedMap.entrySet().iterator(); i.hasNext();) { Map.Entry<String,Category> entry = i.next(); Category category = (Category) entry.getValue(); section.addCategory(category.getName()); } // Add our one section to the sections list. sectionList = new ArrayList<Section>(); sectionList.add(section); return sectionList; } /** * <p>getCategoryData</p> * * @return a {@link java.util.Map} object. * @throws java.io.IOException if any. * @throws org.exolab.castor.xml.MarshalException if any. * @throws org.exolab.castor.xml.ValidationException if any. */ public Map<String, List<Category>> getCategoryData() throws IOException, MarshalException, ValidationException { Map<String, Category> categoryMap = m_model.getCategoryMap(); List<Section> sectionList = getSections(categoryMap); Map<String, List<Category>> categoryData = new LinkedHashMap<String, List<Category>>(); for (Section section : sectionList) { List<Category> categories = new LinkedList<Category>(); String[] categoryNames = section.getCategory(); for (int j = 0; j < categoryNames.length; j++) { String categoryName = categoryNames[j]; Category category = (Category) categoryMap.get(categoryName); if (category == null) { categories.add(new Category(categoryName)); } else { categories.add(category); } } categoryData.put(section.getSectionName(), categories); } return Collections.unmodifiableMap(categoryData); } /** * Returns the earliest update time for the categories in categoryData. * * @param categoryData * category data to evaluate. From getCategoryData(). * @returns the earliest update time. If one of the categories has no RTC * data, -1 is returned. If no categories exist in categoryData, 0 * is returned. * @return a long. */ public long getEarliestUpdate(Map<String,List<Category>> categoryData) { long earliestUpdate = 0; for (Iterator<String> i = categoryData.keySet().iterator(); i.hasNext();) { String sectionName = i.next(); List<Category> categories = categoryData.get(sectionName); for (Iterator<Category> j = categories.iterator(); j.hasNext();) { Category category = j.next(); if (category.getLastUpdated() == null) { return -1; } else if (earliestUpdate == 0 || earliestUpdate > category.getLastUpdated().getTime()) { earliestUpdate = category.getLastUpdated().getTime(); } } } return earliestUpdate; } /** * <p>isDisconnected</p> * * @return a boolean. * @throws java.io.IOException if any. * @throws org.exolab.castor.xml.MarshalException if any. * @throws org.exolab.castor.xml.ValidationException if any. */ public boolean isDisconnected() throws IOException, MarshalException, ValidationException { return isDisconnected(getEarliestUpdate(getCategoryData())); } /** * <p>isDisconnected</p> * * @param earliestUpdate a long. * @return a boolean. */ public boolean isDisconnected(long earliestUpdate) { if (earliestUpdate < 1 || (earliestUpdate + m_disconnectTimeout) < System.currentTimeMillis()) { return true; } else { return false; } } /* * FIXME: This isn't used. This functionality is in category-box.jsp. * It is marked private so that no one can use it unless they fix * its accessability and this comment. :-P */ @SuppressWarnings("unused") private void printBox(JspWriter out, HttpServletResponse response) throws IOException, MarshalException, ValidationException { Map<String,List<Category>> categoryData = getCategoryData(); out.println("<table width=\"100%\" border=\"1\" cellspacing=\"0\" " + "cellpadding=\"2\" bordercolor=\"black\" " + "bgcolor=\"#cccccc\">"); long earliestUpdate = getEarliestUpdate(categoryData); boolean opennmsDisconnect = isDisconnected(earliestUpdate); for (Iterator<String> i = categoryData.keySet().iterator(); i.hasNext();) { String sectionName = i.next(); out.println("<tr bgcolor=\"#999999\">"); out.println("<td width=\"50%\"><b>" + sectionName + "</b></td>"); out.println("<td width=\"20%\" align=\"right\">" + "<b>Outages</b></td>"); out.println("<td width=\"30%\" align=\"right\">" + "<b>24hr Avail</b></td>"); out.println("</tr>"); List<Category> categories = categoryData.get(sectionName); String title; String lastUpdated; long lastUpdatedTime; String outageText; String outageColor; String availText; String availColor; for (Iterator<Category> j = categories.iterator(); j.hasNext();) { Category category = j.next(); String categoryName = category.getName(); title = category.getTitle(); outageColor = (opennmsDisconnect ? "lightblue" : category.getOutageColor()); availColor = (opennmsDisconnect ? "lightblue" : category.getAvailColor()); lastUpdated = (category.getLastUpdated() == null ? "Never" : category.getLastUpdated().toString()); lastUpdatedTime = (category.getLastUpdated() == null ? -1 : category.getLastUpdated().getTime()); outageText = category.getOutageText(); availText = "<b>" + category.getAvailText() + "</b>"; out.println("<tr>"); out.println("<td><a href=\"rtc/category.jsp?category=" + URLEncoder.encode(response.encodeURL(categoryName), "UTF-8") + "\" title=\"" + title + "\">" + categoryName + "</a></td>"); out.println("<td bgcolor=\"" + outageColor + "\" align=\"right\" title=\"Updated: " + lastUpdated + "\">" + outageText + "</td>"); out.println("<td bgcolor=\"" + availColor + "\" align=\"right\" title=\"Updated: " + lastUpdated + "\">" + availText + "</td>"); out.println("<!-- Last updated " + lastUpdated + " -->"); out.println("<!-- Epoch time: " + lastUpdatedTime + " -->"); out.println("</tr>"); } } out.println("<tr bgcolor=\"#999999\">"); if (opennmsDisconnect) { out.println("<td colspan=\"3\"><font color=\"#bb1111\">" + "OpenNMS Disconnect -- is the OpenNMS daemon " + "running?<br/>Last update: " + (earliestUpdate > 0 ? new Date(earliestUpdate).toString() : "one or more categories have never been updated.") + "</font></td>"); } else { out.println("<td colspan=\"3\">Percentage over last " + "24 hours</td>"); } out.println("</tr>"); out.println("</table>"); } }