gt:                     table.addCell("No data", status.getStyle());
context: /*******************************************************************************
   * This file is part of OpenNMS(R).
   *
   * Copyright (C) 2006-2012 The OpenNMS Group, Inc.
   * OpenNMS(R) is Copyright (C) 1999-2012 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 static org.opennms.core.utils.InetAddressUtils.toInteger;
  
  import java.io.Serializable;
  import java.text.DecimalFormat;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Set;
  import java.util.SortedSet;
  import java.util.TreeSet;
  
  import org.opennms.core.utils.ThreadCategory;
  import org.opennms.core.utils.WebSecurityUtils;
  import org.opennms.netmgt.dao.ApplicationDao;
  import org.opennms.netmgt.dao.GraphDao;
  import org.opennms.netmgt.dao.LocationMonitorDao;
  import org.opennms.netmgt.dao.MonitoredServiceDao;
  import org.opennms.netmgt.dao.ResourceDao;
  import org.opennms.netmgt.model.OnmsApplication;
  import org.opennms.netmgt.model.OnmsLocationMonitor;
  import org.opennms.netmgt.model.OnmsLocationSpecificStatus;
  import org.opennms.netmgt.model.OnmsMonitoredService;
  import org.opennms.netmgt.model.OnmsMonitoringLocationDefinition;
  import org.opennms.netmgt.model.OnmsResource;
  import org.opennms.netmgt.model.PollStatus;
  import org.opennms.netmgt.model.PrefabGraph;
  import org.opennms.netmgt.model.OnmsLocationMonitor.MonitorStatus;
  import org.opennms.web.api.Util;
  import org.opennms.web.command.DistributedStatusDetailsCommand;
  import org.opennms.web.graph.RelativeTimePeriod;
  import org.opennms.web.svclayer.DistributedStatusService;
  import org.opennms.web.svclayer.SimpleWebTable;
  import org.opennms.web.svclayer.SimpleWebTable.Cell;
  import org.opennms.web.svclayer.support.DistributedStatusHistoryModel.ServiceGraph;
  import org.springframework.beans.factory.InitializingBean;
  import org.springframework.orm.ObjectRetrievalFailureException;
  import org.springframework.util.Assert;
  import org.springframework.util.StringUtils;
  import org.springframework.validation.Errors;
  
  /**
   * <p>DefaultDistributedStatusService class.</p>
   *
   * @author <a href="mailto:dj@opennms.org">DJ Gregor</a>
   * @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a>
   * @author <a href="mailto:jeffg@opennms.org">Jeff Gehlbach</a>
   */
  public class DefaultDistributedStatusService implements DistributedStatusService, InitializingBean {
      private MonitoredServiceDao m_monitoredServiceDao;
      private LocationMonitorDao m_locationMonitorDao;
      private ApplicationDao m_applicationDao;
      private ResourceDao m_resourceDao;
      private GraphDao m_graphDao;
      private boolean m_layoutApplicationsVertically = false;
      
      private static final MonitoredServiceComparator MONITORED_SERVICE_COMPARATOR = new MonitoredServiceComparator();
      private static final ServiceGraphComparator SERVICE_GRAPH_COMPARATOR = new ServiceGraphComparator();
      private static final LocationStatusComparator LOCATION_STATUS_COMPARATOR = new LocationStatusComparator();
      private static final PollStatus NO_RECORDED_STATUS;
      
      static {
          NO_RECORDED_STATUS = PollStatus.unknown("No status recorded for this service from this location");
          NO_RECORDED_STATUS.setTimestamp(null);
      }
  
      public enum Severity {
          INDETERMINATE("Indeterminate"),
          NORMAL("Normal"),
          WARNING("Warning"),
          CRITICAL("Critical");
          
          private final String m_style;
  
          private Severity(String style) {
              m_style = style;
          }
          
          public String getStyle() {
              return m_style;
          }
      }
      
      public static class MonitoredServiceComparator implements Comparator<OnmsMonitoredService>, Serializable {
          /**
           * 
           */
          private static final long serialVersionUID = 3000643751074224389L;
  
          public int compare(OnmsMonitoredService o1, OnmsMonitoredService o2) {
              int diff;
              diff = o1.getIpInterface().getNode().getLabel().compareToIgnoreCase(o2.getIpInterface().getNode().getLabel());
              if (diff != 0) {
                  return diff;
              }
  
              diff = toInteger(o1.getIpAddress()).compareTo(toInteger(o2.getIpAddress()));
              if (diff != 0) {
                  return diff;
              }
  
              return o1.getServiceName().compareToIgnoreCase(o2.getServiceName());
          }
      }
  
      /**
       * Comparator for ServiceGraph objects. 
       * Orders objects with no errors and then those with errors and orders within
       * each of these groups by the service ordering (see MonitoredServiceComparator).
       * 
       * @author <a href="mailto:dj@opennms.org">DJ Gregor</a>
       */
      public static class ServiceGraphComparator implements Comparator<ServiceGraph>, Serializable {
          /**
           * 
           */
          private static final long serialVersionUID = -1365958323886041945L;
  
          public int compare(ServiceGraph o1, ServiceGraph o2) {
              if ((o1.getErrors().length == 0 && o2.getErrors().length == 0)
                      || (o1.getErrors().length > 0 && o2.getErrors().length > 0)) {
                  return MONITORED_SERVICE_COMPARATOR.compare(o1.getService(), o2.getService());
              } else if (o1.getErrors().length > 0) {
                  return 1;
              } else {
                  return -1;
              }
          }
      }
      
      public static class LocationStatusComparator implements Comparator<OnmsLocationSpecificStatus>, Serializable {
          /**
           * 
           */
          private static final long serialVersionUID = -5854706886193427256L;
  
          public int compare(OnmsLocationSpecificStatus o1, OnmsLocationSpecificStatus o2) {
              if ((o1.getPollResult().isUnknown() && o2.getPollResult().isUnknown())
                      || (!o1.getPollResult().isUnknown() && !o2.getPollResult().isUnknown())) {
                  return o1.getMonitoredService().compareTo(o2.getMonitoredService());
              } else if (o1.getPollResult().isUnknown()) {
                  return 1;
              } else {
                  return -1;
              }
          }
      }
      
      
      
      /**
       * <p>getApplicationCount</p>
       *
       * @return a int.
       */
      public int getApplicationCount() {
          return m_applicationDao.countAll();
      }
  
      /** {@inheritDoc} */
      public SimpleWebTable createStatusTable(DistributedStatusDetailsCommand command, Errors errors) {
          SimpleWebTable table = new SimpleWebTable(); 
          table.setErrors(errors);
          
          // Already had some validation errors, so don't bother doing anything 
          if (table.getErrors().hasErrors()) {
              return table;
          }
          
          table.setTitle("Distributed poller view for " + command.getApplication() + " from " + command.getLocation() + " location");
  
          List<OnmsLocationSpecificStatus> status = findLocationSpecificStatus(command, table.getErrors());
          
          // No data was found, and an error was probably added, so just return
          if (status == null) {
              return table;
          }
          
          table.addColumn("Node", "");
          table.addColumn("Monitor", "");
          table.addColumn("Service", "");
          table.addColumn("Status", "");
          table.addColumn("Response", "");
          table.addColumn("Last Status Change", "");
          table.addColumn("Last Update", "");
          
          SortedSet<OnmsLocationSpecificStatus> sortedStatus = new TreeSet<OnmsLocationSpecificStatus>(LOCATION_STATUS_COMPARATOR);
          sortedStatus.addAll(status);        
          for (OnmsLocationSpecificStatus s : sortedStatus) {
              table.newRow();
              table.addCell(s.getMonitoredService().getIpInterface().getNode().getLabel(), 
                            getStyleForPollResult(s.getPollResult()),
                            "element/node.jsp?node=" + s.getMonitoredService().getIpInterface().getNode().getId());
              table.addCell(s.getLocationMonitor().getDefinitionName() + "-"
                            + s.getLocationMonitor().getId(),
                            "",
                            "distributed/locationMonitorDetails.htm?monitorId=" + s.getLocationMonitor().getId()); 
              table.addCell(s.getMonitoredService().getServiceName(), "",
                            "element/service.jsp?ifserviceid="
                            + s.getMonitoredService().getId());
              table.addCell(s.getPollResult().getStatusName(),
                            "bright");
              table.addCell(getResponseText(s.getPollResult()), "");
              table.addCell(reDateify(s.getPollResult().getTimestamp()), "");
              table.addCell(reDateify(s.getLocationMonitor().getLastCheckInTime()), "");
          }
          
          return table;
      }
  
      /**
       * TODO: Use the enum for these string values
       */
      private String getStyleForPollResult(PollStatus status) {
          if (status.isAvailable()) {
              return "Normal";
          } else if (status.isUnresponsive()) {
              return "Warning";
          } else if (status.isUnknown()) {
              return "Indeterminate";
          } else {
              return "Critical";
          }
      }
  
      private String getResponseText(PollStatus status) {
          if (status.isAvailable()) {
              Double responseTime = status.getResponseTime();
              if (responseTime != null && responseTime >= 0) {
              	return responseTime + "ms";
              } else {
                  return "";
              }
          } else {
              return status.getReason(); 
          }
      }
      
      /**
       * Convert any Date into a fresh, brand-new java.util.Date.
       * We use this so that we get reliable results from Date.toString(),
       * since things like java.sql.Date have a different toString() format.
       * 
       * @param date input date
       * @return brand spankin' new java.util.Date
       */
      private Date reDateify(Date date) {
          if (date == null) {
              return null;
          } else {
              return new Date(date.getTime());
          }
      }
  
  
      /**
       * <p>findLocationSpecificStatus</p>
       *
       * @param command a {@link org.opennms.web.command.DistributedStatusDetailsCommand} object.
       * @param errors a {@link org.springframework.validation.Errors} object.
       * @return a {@link java.util.List} object or null if no location monitors are registered for the specified location and application tuple
       */
      protected List<OnmsLocationSpecificStatus> findLocationSpecificStatus(DistributedStatusDetailsCommand command, Errors errors) throws IllegalArgumentException {
          String locationName = command.getLocation();
          String applicationName = command.getApplication();
  
          Assert.notNull(locationName, "location cannot be null");
          Assert.notNull(applicationName, "application cannot be null");
          
          OnmsMonitoringLocationDefinition location = m_locationMonitorDao.findMonitoringLocationDefinition(locationName);
          if (location == null) {
              throw new IllegalArgumentException("Could not find location for "
                                                 + "location name \""
                                                 + locationName + "\"");
          }
          
          OnmsApplication application = m_applicationDao.findByName(applicationName);
          if (application == null) {
              throw new IllegalArgumentException("Could not find application "
                                                 + "for application name \""
                                                 + applicationName + "\"");
          }
  
          Collection<OnmsLocationMonitor> locationMonitors = m_locationMonitorDao.findByLocationDefinition(location);
          
          if (locationMonitors.size() == 0) {
              errors.reject("location.no-monitors",
                            new Object[] { applicationName, locationName },
                            "No location monitors have registered for this "
                            + "application and location");
              return null;
          }
          
          List<OnmsLocationMonitor> sortedLocationMonitors = new ArrayList<OnmsLocationMonitor>(locationMonitors);
          Collections.sort(sortedLocationMonitors);
          
          Collection<OnmsMonitoredService> services = m_monitoredServiceDao.findByApplication(application);
          
          List<OnmsMonitoredService> sortedServices = new ArrayList<OnmsMonitoredService>(services);
          Collections.sort(sortedServices);
                                                                       
          List<OnmsLocationSpecificStatus> status = new LinkedList<OnmsLocationSpecificStatus>();
          for (OnmsMonitoredService service : sortedServices) {
              for (OnmsLocationMonitor locationMonitor : sortedLocationMonitors) {
                  OnmsLocationSpecificStatus currentStatus = m_locationMonitorDao.getMostRecentStatusChange(locationMonitor, service);
                  if (currentStatus == null) {
                      status.add(new OnmsLocationSpecificStatus(locationMonitor, service, NO_RECORDED_STATUS));
                  } else {
                      status.add(currentStatus);
                  }
              }
          }
  
          return status;
      }
  
      /** {@inheritDoc} */
      public SimpleWebTable createFacilityStatusTable(Date start, Date end) {
          Assert.notNull(start, "argument start cannot be null");
          Assert.notNull(end, "argument end cannot be null");
          if (!start.before(end)) {
              throw new IllegalArgumentException("start date (" + start + ") must be older than end date (" + end + ")");
          }
          
          SimpleWebTable table = new SimpleWebTable();
          
          List<OnmsMonitoringLocationDefinition> locationDefinitions = m_locationMonitorDao.findAllMonitoringLocationDefinitions();
  
          Collection<OnmsApplication> applications = m_applicationDao.findAll();
          if (applications.size() == 0) {
              throw new IllegalArgumentException("there are no applications");
          }
          
          List<OnmsApplication> sortedApplications = new ArrayList<OnmsApplication>(applications);
          Collections.sort(sortedApplications);
          
          Collection<OnmsLocationSpecificStatus> mostRecentStatuses = m_locationMonitorDao.getAllMostRecentStatusChanges();
  
          Collection<OnmsLocationSpecificStatus> statusesPeriod = new HashSet<OnmsLocationSpecificStatus>();
          statusesPeriod.addAll(m_locationMonitorDao.getAllStatusChangesAt(start));
          statusesPeriod.addAll(m_locationMonitorDao.getStatusChangesBetween(start, end));
  
          table.setTitle("Distributed Poller Status Summary");
          
          table.addColumn("Area", "");
          table.addColumn("Location", "");
          for (OnmsApplication application : sortedApplications) {
              table.addColumn(application.getName(), "");
          }
          
          for (OnmsMonitoringLocationDefinition locationDefinition : locationDefinitions) {
              Collection<OnmsLocationMonitor> monitors = m_locationMonitorDao.findByLocationDefinition(locationDefinition);
              
              table.newRow();
              table.addCell(locationDefinition.getArea(), "");
              table.addCell(locationDefinition.getName(), "");
              
              for (OnmsApplication application : sortedApplications) {
                  Collection<OnmsMonitoredService> memberServices = m_monitoredServiceDao.findByApplication(application);
                  Severity status = calculateCurrentStatus(monitors, memberServices, mostRecentStatuses);
              
                  Set<OnmsLocationSpecificStatus> selectedStatuses = filterStatus(statusesPeriod, monitors, memberServices);
                  
                  if (selectedStatuses.size() > 0) {
                      String percentage = calculatePercentageUptime(memberServices, selectedStatuses, start, end);
                      table.addCell(percentage, status.getStyle(), createHistoryPageUrl(locationDefinition, application));
                  } else {
  