/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2006-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.svclayer.support; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.opennms.core.utils.LogUtils; import org.opennms.netmgt.config.surveillanceViews.Category; import org.opennms.netmgt.config.surveillanceViews.ColumnDef; import org.opennms.netmgt.config.surveillanceViews.RowDef; import org.opennms.netmgt.config.surveillanceViews.View; import org.opennms.netmgt.dao.CategoryDao; import org.opennms.netmgt.dao.NodeDao; import org.opennms.netmgt.dao.SurveillanceViewConfigDao; import org.opennms.netmgt.model.OnmsCategory; import org.opennms.netmgt.model.OnmsNode; import org.opennms.web.api.Util; import org.opennms.netmgt.model.SurveillanceStatus; import org.opennms.web.svclayer.AggregateStatus; import org.opennms.web.svclayer.ProgressMonitor; import org.opennms.web.svclayer.SimpleWebTable; import org.opennms.web.svclayer.SurveillanceService; import org.springframework.orm.ObjectRetrievalFailureException; import org.springframework.util.StringUtils; /** * <p>DefaultSurveillanceService class.</p> * * @author <a href="mailto:david@opennms.org">David Hustace</a> * @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a> * @author <a href="mailto:jeffg@opennms.org">Jeff Gehlbach</a> * @since 1.8.1 */ public class DefaultSurveillanceService implements SurveillanceService { private NodeDao m_nodeDao; private CategoryDao m_categoryDao; private SurveillanceViewConfigDao m_surveillanceConfigDao; interface CellStatusStrategy { public SurveillanceStatus[][] calculateCellStatus(SurveillanceView sView, ProgressMonitor progressMonitor); public int getPhaseCount(SurveillanceView sView); } class DefaultCellStatusStrategy implements CellStatusStrategy { private Collection<OnmsNode> getNodesInCategories(final Set<OnmsCategory> categories) { return m_nodeDao.findAllByCategoryList(categories); } public SurveillanceStatus[][] calculateCellStatus(final SurveillanceView sView, final ProgressMonitor progressMonitor) { final List<Collection<OnmsNode>> nodesByRowIndex = new ArrayList<Collection<OnmsNode>>(); final List<Collection<OnmsNode>> nodesByColIndex = new ArrayList<Collection<OnmsNode>>(); /* * Iterate of the requested view's configuration (row's and columns) and set an aggreated status into each table * cell. */ for(int rowIndex = 0; rowIndex < sView.getRowCount(); rowIndex++) { progressMonitor.beginNextPhase("Loading nodes for row '"+sView.getRowLabel(rowIndex) + "'"); final Collection<OnmsNode> nodesForRow = getNodesInCategories(sView.getCategoriesForRow(rowIndex)); nodesByRowIndex.add(rowIndex, nodesForRow); } for(int colIndex = 0; colIndex < sView.getColumnCount(); colIndex++) { progressMonitor.beginNextPhase("Loading nodes for column '"+sView.getColumnLabel(colIndex) + "'"); final Collection<OnmsNode> nodesForCol = getNodesInCategories(sView.getCategoriesForColumn(colIndex)); nodesByColIndex.add(colIndex, nodesForCol); } final SurveillanceStatus[][] cellStatus = new SurveillanceStatus[sView.getRowCount()][sView.getColumnCount()]; progressMonitor.beginNextPhase("Intersecting rows and columns"); for(int rowIndex = 0; rowIndex < sView.getRowCount(); rowIndex++) { final Collection<OnmsNode> nodesForRow = nodesByRowIndex.get(rowIndex); for(int colIndex = 0; colIndex < sView.getColumnCount(); colIndex++) { final Collection<OnmsNode> nodesForCol = nodesByColIndex.get(colIndex); final Set<OnmsNode> cellNodes = new HashSet<OnmsNode>(nodesForRow); cellNodes.retainAll(nodesForCol); cellStatus[rowIndex][colIndex] = new AggregateStatus(cellNodes); } } return cellStatus; } public int getPhaseCount(final SurveillanceView sView) { return sView.getRowCount()+sView.getColumnCount()+1; } } class LowMemCellStatusStrategy implements CellStatusStrategy { private String toString(final Collection<OnmsCategory> categories) { final StringBuilder buf = new StringBuilder(); buf.append("{"); for(final OnmsCategory cat : categories) { if (buf.length() != 0) { buf.append(", "); } buf.append(cat.getName()); } buf.append("}"); return buf.toString(); } public SurveillanceStatus[][] calculateCellStatus(final SurveillanceView sView, final ProgressMonitor progressMonitor) { final SurveillanceStatus[][] cellStatus = new SurveillanceStatus[sView.getRowCount()][sView.getColumnCount()]; for(int rowIndex = 0; rowIndex < sView.getRowCount(); rowIndex++) { for(int colIndex = 0; colIndex < sView.getColumnCount(); colIndex++) { final Collection<OnmsCategory> rowCategories = sView.getCategoriesForRow(rowIndex); final Collection<OnmsCategory> columnCategories = sView.getCategoriesForColumn(colIndex); progressMonitor.beginNextPhase(String.format("Finding nodes in %s intersect %s", toString(rowCategories), toString(columnCategories))); final Collection<OnmsNode> cellNodes = m_nodeDao.findAllByCategoryLists(rowCategories, columnCategories); cellStatus[rowIndex][colIndex] = new AggregateStatus(cellNodes); } } return cellStatus; } public int getPhaseCount(final SurveillanceView sView) { return sView.getRowCount()*sView.getColumnCount(); } } class VeryLowMemCellStatusStrategy implements CellStatusStrategy { private String toString(final Collection<OnmsCategory> categories) { final StringBuilder buf = new StringBuilder(); buf.append("{"); for(final OnmsCategory cat : categories) { if (buf.length() != 0) { buf.append(", "); } buf.append(cat.getName()); } buf.append("}"); return buf.toString(); } public SurveillanceStatus[][] calculateCellStatus(final SurveillanceView sView, final ProgressMonitor progressMonitor) { final SurveillanceStatus[][] cellStatus = new SurveillanceStatus[sView.getRowCount()][sView.getColumnCount()]; for(int rowIndex = 0; rowIndex < sView.getRowCount(); rowIndex++) { for(int colIndex = 0; colIndex < sView.getColumnCount(); colIndex++) { final Collection<OnmsCategory> rowCategories = sView.getCategoriesForRow(rowIndex); final Collection<OnmsCategory> columnCategories = sView.getCategoriesForColumn(colIndex); progressMonitor.beginNextPhase(String.format("Finding status for nodes in %s intersect %s", toString(rowCategories), toString(columnCategories))); final SurveillanceStatus status = m_nodeDao.findSurveillanceStatusByCategoryLists(rowCategories, columnCategories); cellStatus[rowIndex][colIndex] = status; } } return cellStatus; } public int getPhaseCount(final SurveillanceView sView) { return sView.getRowCount()*sView.getColumnCount(); } } /** * <p>createSurveillanceTable</p> * * @return a {@link org.opennms.web.svclayer.SimpleWebTable} object. */ public SimpleWebTable createSurveillanceTable() { return createSurveillanceTable("default", new ProgressMonitor()); } public class SurveillanceView { private final SurveillanceViewConfigDao m_surveillanceConfigDao; private final CategoryDao m_categoryDao; private final View m_view; public SurveillanceView(final String viewName, final SurveillanceViewConfigDao surveillanceConfigDao, final CategoryDao categoryDao) { m_surveillanceConfigDao = surveillanceConfigDao; m_categoryDao = categoryDao; m_view = m_surveillanceConfigDao.getView(viewName); } public int getRowCount() { return m_view.getRows().getRowDefCount(); } public int getColumnCount() { return m_view.getColumns().getColumnDefCount(); } public Set<OnmsCategory> getCategoriesForRow(final int rowIndex) { return getOnmsCategoriesFromViewCategories(getRowDef(rowIndex).getCategoryCollection()); } private RowDef getRowDef(final int rowIndex) { return m_view.getRows().getRowDef(rowIndex); } public Set<OnmsCategory> getCategoriesForColumn(final int colIndex) { return getOnmsCategoriesFromViewCategories(getColumnDef(colIndex).getCategoryCollection()); } private ColumnDef getColumnDef(final int colIndex) { return m_view.getColumns().getColumnDef(colIndex); } private Set<OnmsCategory> getOnmsCategoriesFromViewCategories(final Collection<Category> viewCats) { final Set<OnmsCategory> categories = new HashSet<OnmsCategory>(); for (final Category viewCat : viewCats) { final OnmsCategory category = m_categoryDao.findByName(viewCat.getName()); if (category == null) throw new ObjectRetrievalFailureException(OnmsCategory.class, viewCat.getName(), "Unable to locate OnmsCategory named: "+viewCat.getName()+" as specified in the surveillance view configuration file", null); categories.add(category); } return categories; } public String getRowLabel(final int rowIndex) { return getRowDef(rowIndex).getLabel(); } public String getColumnLabel(final int colIndex) { return getColumnDef(colIndex).getLabel(); } public String getColumnReportCategory(final int colIndex) { return getColumnDef(colIndex).getReportCategory(); } public String getRowReportCategory(final int rowIndex) { return getRowDef(rowIndex).getReportCategory(); } } /** * {@inheritDoc} * * Creates a custom table object containing intersected rows and * columns and categories. */ public SimpleWebTable createSurveillanceTable(final String surveillanceViewName, final ProgressMonitor progressMonitor) { CellStatusStrategy strategy = getCellStatusStrategy(); final String name = (surveillanceViewName == null ? m_surveillanceConfigDao.getDefaultView().getName() : surveillanceViewName); final View view = m_surveillanceConfigDao.getView(name); final SurveillanceView sView = new SurveillanceView(name, m_surveillanceConfigDao, m_categoryDao); progressMonitor.setPhaseCount(strategy.getPhaseCount(sView) + 1); /* * Initialize a status table */ final SimpleWebTable webTable = new SimpleWebTable(); webTable.setTitle(view.getName()); webTable.addColumn("Nodes Down", "simpleWebTableHeader"); // set up the column headings for(int colIndex = 0; colIndex < sView.getColumnCount(); colIndex++) { webTable.addColumn(sView.getColumnLabel(colIndex), "simpleWebTableHeader") .setLink(computeReportCategoryLink(sView.getColumnReportCategory(colIndex))); } // build the set of nodes for each cell final SurveillanceStatus[][] cellStatus = strategy.calculateCellStatus(sView, progressMonitor); progressMonitor.beginNextPhase("Calculating Status Values"); for(int rowIndex = 0; rowIndex < sView.getRowCount(); rowIndex++) { webTable.newRow(); webTable.addCell(sView.getRowLabel(rowIndex), "simpleWebTableRowLabel") .setLink(computeReportCategoryLink(sView.getRowReportCategory(rowIndex))); for(int colIndex = 0; colIndex < sView.getColumnCount(); colIndex++) { final SurveillanceStatus survStatus = cellStatus[rowIndex][colIndex]; final String text = survStatus.getDownEntityCount()+" of "+survStatus.getTotalEntityCount(); LogUtils.debugf(this, "Text: %s, Style %s", text, survStatus.getStatus()); final SimpleWebTable.Cell cell = webTable.addCell(text, survStatus.getStatus()); if (survStatus.getDownEntityCount() > 0) { cell.setLink(createNodePageUrl(sView, colIndex, rowIndex)); } } } progressMonitor.finished(webTable); return webTable; } private CellStatusStrategy getCellStatusStrategy() { return new VeryLowMemCellStatusStrategy(); } private String computeReportCategoryLink(final String reportCategory) { String link = null; if (reportCategory != null) { link = "rtc/category.jsp?category=" + Util.encode(reportCategory); } return link; } /* * This creates a relative url to the node list page and sets the category * parameters to show the categories for this cell. * FIXME: this code should move to the jsp after the status table is * enhanced to support this requirement. */ private String createNodePageUrl(final SurveillanceView view, final int colIndex, final int rowIndex) { Set<OnmsCategory> columns = Collections.emptySet(); Set<OnmsCategory> rows = Collections.emptySet(); try { columns = view.getCategoriesForColumn(colIndex); } catch (final ObjectRetrievalFailureException e) { LogUtils.warnf(this, "An error occurred while getting categories for view %s, column %d", view, colIndex); } try { rows = view.getCategoriesForRow(rowIndex); } catch (final ObjectRetrievalFailureException e) { LogUtils.warnf(this, "An error occurred while getting categories for view %s, row %d", view, rowIndex); } final List<String> params = new ArrayList<String>(columns.size() + rows.size()); for (final OnmsCategory category : columns) { params.add("category1=" + Util.encode(category.getName())); } for (final OnmsCategory category : rows) { params.add("category2=" + Util.encode(category.getName())); } params.add("nodesWithDownAggregateStatus=true"); return "element/nodeList.htm?" + StringUtils.collectionToDelimitedString(params, "&"); } /** * <p>getNodeDao</p> * * @return a {@link org.opennms.netmgt.dao.NodeDao} object. */ public NodeDao getNodeDao() { return m_nodeDao; } /** * <p>setNodeDao</p> * * @param nodeDao a {@link org.opennms.netmgt.dao.NodeDao} object. */ public void setNodeDao(final NodeDao nodeDao) { m_nodeDao = nodeDao; } /** * <p>getCategoryDao</p> * * @return a {@link org.opennms.netmgt.dao.CategoryDao} object. */ public CategoryDao getCategoryDao() { return m_categoryDao; } /** * <p>setCategoryDao</p> * * @param categoryDao a {@link org.opennms.netmgt.dao.CategoryDao} object. */ public void setCategoryDao(final CategoryDao categoryDao) { m_categoryDao = categoryDao; } /** * <p>getSurveillanceConfigDao</p> * * @return a {@link org.opennms.netmgt.dao.SurveillanceViewConfigDao} object. */ public SurveillanceViewConfigDao getSurveillanceConfigDao() { return m_surveillanceConfigDao; } /** * <p>setSurveillanceConfigDao</p> * * @param surveillanceConfigDao a {@link org.opennms.netmgt.dao.SurveillanceViewConfigDao} object. */ public void setSurveillanceConfigDao(final SurveillanceViewConfigDao surveillanceConfigDao) { m_surveillanceConfigDao = surveillanceConfigDao; } /** {@inheritDoc} */ public String getHeaderRefreshSeconds(final String viewName) { return m_surveillanceConfigDao.getView(viewName == null ? m_surveillanceConfigDao.getDefaultView().getName() : viewName).getRefreshSeconds(); } /** {@inheritDoc} */ public boolean isViewName(final String viewName) { View view = ( viewName == null ? m_surveillanceConfigDao.getDefaultView() : m_surveillanceConfigDao.getView(viewName) ); return (view == null) ? false : true; } /** * <p>getViewNames</p> * * @return a {@link java.util.List} object. */ public List<String> getViewNames() { final List<String> viewNames = new ArrayList<String>(m_surveillanceConfigDao.getViews().getViewCount()); for (final View view : getViewCollection()) { viewNames.add(view.getName()); } Collections.sort(viewNames); return viewNames; } private Collection<View> getViewCollection() { return m_surveillanceConfigDao.getViews().getViewCollection(); } }