/*******************************************************************************
* 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 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 {
table.addCell("No data", status.getStyle());
}
}
}
if (isLayoutApplicationsVertically()) {
SimpleWebTable newTable = new SimpleWebTable();
newTable.setErrors(table.getErrors());
newTable.setTitle(table.getTitle());
newTable.addColumn("Application");
for (List<Cell> row : table.getRows()) {
// The location is in the second row
newTable.addColumn(row.get(1).getContent(), row.get(1).getStyleClass());
}
for (Cell columnHeader : table.getColumnHeaders().subList(2, table.getColumnHeaders().size())) {
// This is the index into collumn list of the old table to get the data for the current application
int rowColumnIndex = newTable.getRows().size() + 2;
newTable.newRow();
newTable.addCell(columnHeader.getContent(), columnHeader.getStyleClass());
for (List<Cell> row : table.getRows()) {
newTable.addCell(row.get(rowColumnIndex).getContent(), row.get(rowColumnIndex).getStyleClass(), row.get(rowColumnIndex).getLink());
}
}
return newTable;
}
return table;
}
private ThreadCategory log() {
return ThreadCategory.getInstance(getClass());
}
/**
* Filter a collection of OnmsLocationSpecificStatus based on a
* collection of monitors and a collection of monitored services.
* A specific OnmsLocationSpecificStatus instance will only be
* returned if its OnmsLocationMonitor is in the collection of
* monitors and its OnmsMonitoredService is in the collection of
* services.
*
* @param statuses
* @param monitors
* @param services
* @return filtered list
*/
private Set<OnmsLocationSpecificStatus> filterStatus(Collection<OnmsLocationSpecificStatus> statuses,
Collection<OnmsLocationMonitor> monitors,
Collection<OnmsMonitoredService> services) {
Set<OnmsLocationSpecificStatus> filteredStatuses = new HashSet<OnmsLocationSpecificStatus>();
for (OnmsLocationSpecificStatus status : statuses) {
if (!monitors.contains(status.getLocationMonitor())) {
continue;
}
if (!services.contains(status.getMonitoredService())) {
continue;
}
filteredStatuses.add(status);
}
return filteredStatuses;
}
/**
* <p>calculateCurrentStatus</p>
*
* @param monitors a {@link java.util.Collection} object.
* @param applicationServices a {@link java.util.Collection} object.
* @param statuses a {@link java.util.Collection} object.
* @return a {@link org.opennms.web.svclayer.support.DefaultDistributedStatusService.Severity} object.
*/
public Severity calculateCurrentStatus(
Collection<OnmsLocationMonitor> monitors,
Collection<OnmsMonitoredService> applicationServices,
Collection<OnmsLocationSpecificStatus> statuses) {
int goodMonitors = 0;
int badMonitors = 0;
for (OnmsLocationMonitor monitor : monitors) {
if (monitor == null || monitor.getStatus() != MonitorStatus.STARTED) {
continue;
}
Severity status = calculateCurrentStatus(monitor, applicationServices, statuses);
if (status == Severity.NORMAL) {
goodMonitors++;
} else if (status != Severity.INDETERMINATE) {
badMonitors++;
}
}
if (goodMonitors == 0 && badMonitors == 0) {
return Severity.INDETERMINATE; // No current responses
} else if (goodMonitors != 0 && badMonitors == 0) {
return Severity.NORMAL; // No bad responses
} else if (goodMonitors == 0 && badMonitors != 0) {
return Severity.CRITICAL; // All bad responses
} else if (goodMonitors != 0 && badMonitors != 0){
return Severity.WARNING; // Some bad responses
} else {
throw new IllegalStateException("Shouldn't have gotten here. "
+ "good monitors = "
+ goodMonitors
+ ", bad monitors = "
+ badMonitors);
}
}
/**
* <p>calculateCurrentStatus</p>
*
* @param monitor a {@link org.opennms.netmgt.model.OnmsLocationMonitor} object.
* @param applicationServices a {@link java.util.Collection} object.
* @param statuses a {@link java.util.Collection} object.
* @return a {@link org.opennms.web.svclayer.support.DefaultDistributedStatusService.Severity} object.
*/
public Severity calculateCurrentStatus(OnmsLocationMonitor monitor,
Collection<OnmsMonitoredService> applicationServices,
Collection<OnmsLocationSpecificStatus> statuses) {
Set<PollStatus> pollStatuses = new HashSet<PollStatus>();
for (OnmsMonitoredService service : applicationServices) {
boolean foundIt = false;
for (OnmsLocationSpecificStatus status : statuses) {
if (status.getMonitoredService().equals(service) && status.getLocationMonitor().equals(monitor)) {
pollStatuses.add(status.getPollResult());
foundIt = true;
break;
}
}
if (!foundIt) {
pollStatuses.add(PollStatus.unknown("No status found for this service"));
if (log().isDebugEnabled()) {
log().debug("Did not find status for service " + service + " in application. Setting status for it to unknown.");
}
}
}
return calculateStatus(pollStatuses);
}
/**
* <p>calculateStatus</p>
*
* @param pollStatuses a {@link java.util.Collection} object.
* @return a {@link org.opennms.web.svclayer.support.DefaultDistributedStatusService.Severity} object.
*/
public Severity calculateStatus(Collection<PollStatus> pollStatuses) {
int goodStatuses = 0;
int badStatuses = 0;
for (PollStatus pollStatus : pollStatuses) {
if (pollStatus.isAvailable()) {
goodStatuses++;
} else if (!pollStatus.isUnknown()) {
badStatuses++;
}
}
if (goodStatuses == 0 && badStatuses == 0) {
return Severity.INDETERMINATE;
} else if (goodStatuses > 0 && badStatuses == 0) {
return Severity.NORMAL;
} else {
return Severity.CRITICAL;
}
}
/**
* Calculate the percentage of time that all services are up for this
* application on this remote monitor.
*
* @param applicationServices services to report on
* @param statuses status entries to use for report
* @param startDate start date. The report starts on this date.
* @param endDate end date. The report ends the last millisecond prior
* this date.
* @return representation of the percentage uptime out to three decimal
* places. Null is returned if there is no data.
*/
public String calculatePercentageUptime(
Collection<OnmsMonitoredService> applicationServices,
Collection<OnmsLocationSpecificStatus> statuses,
Date startDate, Date endDate) {
/*
* The methodology is as such:
* 1) Sort the status entries by their timestamp;
* 2) Create a Map of each monitored service with a default
* PollStatus of unknown.
* 3) Iterate through the sorted list of status entries until
* we hit a timestamp that is not within our time range or
* run out of entries.
* a) Along the way, update the status Map with the current
* entry's status, and calculate the current status.
* b) If the current timestamp is before the start time, store
* the current status so we can use it once we cross over
* into our time range and then continue.
* c) If the previous status is normal, then count up the number
* of milliseconds since the previous state change entry in
* the time range (or the beginning of the range if this is
* the first entry in within the time range), and add that
* a counter of "normal" millseconds.
* d) Finally, save the current date and status for later use.
* 4) Perform the same computation in 3c, except count the number
* of milliseconds since the last state change entry (or the
* start time if there were no entries) and the end time, and add
* that to the counter of "normal" milliseconds.
* 5) Divide the "normal" milliseconds counter by the total number
* of milliseconds in our time range and compute and return a
* percentage.
*/
List<OnmsLocationSpecificStatus> sortedStatuses =
new LinkedList<OnmsLocationSpecificStatus>(statuses);
Collections.sort(sortedStatuses, new Comparator<OnmsLocationSpecificStatus>(){
public int compare(OnmsLocationSpecificStatus o1, OnmsLocationSpecificStatus o2) {
return o1.getPollResult().getTimestamp().compareTo(o2.getPollResult().getTimestamp());
}
});
HashMap<OnmsMonitoredService,PollStatus> serviceStatus =
new HashMap<OnmsMonitoredService,PollStatus>();
for (OnmsMonitoredService service : applicationServices) {
serviceStatus.put(service, PollStatus.unknown("No history for this service from this location"));
}
float normalMilliseconds = 0f;
Date lastDate = startDate;
Severity lastStatus = Severity.CRITICAL;
for (OnmsLocationSpecificStatus status : sortedStatuses) {
Date currentDate = status.getPollResult().getTimestamp();
if (!currentDate.before(endDate)) {
// We're at or past the end date, so we're done processing
break;
}
serviceStatus.put(status.getMonitoredService(), status.getPollResult());
Severity currentStatus = calculateStatus(serviceStatus.values());
if (currentDate.before(startDate)) {
/*
* We're not yet to a date that is inside our time period, so
* we don't need to check the status and adjust the
* normalMilliseconds variable, but we do need to save the
* status so we have an up-to-date status when we cross the
* start date.
*/
lastStatus = currentStatus;
continue;
}
/*
* Because we *just* had a state change, we want to look at the
* value of the *last* status.
*/
if (lastStatus == Severity.NORMAL) {
long milliseconds = currentDate.getTime() - lastDate.getTime();
normalMilliseconds += milliseconds;
}
lastDate = currentDate;
lastStatus = currentStatus;
}
if (lastStatus == Severity.NORMAL) {
long milliseconds = endDate.getTime() - lastDate.getTime();
normalMilliseconds += milliseconds;
}
float percentage = normalMilliseconds /
(endDate.getTime() - startDate.getTime()) * 100;
return new DecimalFormat("0.000").format((double) percentage) + "%";
}
private String createHistoryPageUrl(
OnmsMonitoringLocationDefinition locationDefinition,
OnmsApplication application) {
List<String> params = new ArrayList<String>(2);
params.add("location=" + Util.encode(locationDefinition.getName()));
params.add("application=" + Util.encode(application.getName()));
return "distributedStatusHistory.htm"
+ "?"
+ StringUtils.collectionToDelimitedString(params, "&");
}
/** {@inheritDoc} */
public DistributedStatusHistoryModel createHistoryModel(
String locationName, String monitorId, String applicationName,
String timeSpan, String previousLocationName) {
List<String> errors = new LinkedList<String>();
List<OnmsMonitoringLocationDefinition> locationDefinitions = m_locationMonitorDao.findAllMonitoringLocationDefinitions();
List<RelativeTimePeriod> periods = Arrays.asList(RelativeTimePeriod.getDefaultPeriods());
Collection<OnmsApplication> applications = m_applicationDao.findAll();
List<OnmsApplication> sortedApplications = new ArrayList<OnmsApplication>(applications);
Collections.sort(sortedApplications);
OnmsMonitoringLocationDefinition location = new OnmsMonitoringLocationDefinition();
if (locationName == null) {
if (!locationDefinitions.isEmpty()) {
location = locationDefinitions.get(0);
}
} else {
location = m_locationMonitorDao.findMonitoringLocationDefinition(locationName);
if (location == null) {
errors.add("Could not find location definition '" + locationName + "'");
if (!locationDefinitions.isEmpty()) {
location = locationDefinitions.get(0);
}
}
}
int monitorIdInt = -1;
if (monitorId != null && monitorId.length() > 0) {
try {
monitorIdInt = WebSecurityUtils.safeParseInt(monitorId);
} catch (NumberFormatException e) {
errors.add("Monitor ID '" + monitorId + "' is not an integer");
}
}
OnmsApplication application = new OnmsApplication();
if (applicationName == null) {
if (!sortedApplications.isEmpty()) {
application = sortedApplications.get(0);
}
} else {
application = m_applicationDao.findByName(applicationName);
if (application == null) {
errors.add("Could not find application '" + applicationName + "'");
if (!sortedApplications.isEmpty()) {
application = sortedApplications.get(0);
}
}
}
Collection<OnmsLocationMonitor> monitors = m_locationMonitorDao.findByLocationDefinition(location);
List<OnmsLocationMonitor> sortedMonitors = new LinkedList<OnmsLocationMonitor>(monitors);
Collections.sort(sortedMonitors);
OnmsLocationMonitor monitor = null;
if (monitorIdInt != -1 && location.getName().equals(previousLocationName)) {
for (OnmsLocationMonitor m : sortedMonitors) {
if (m.getId().equals(monitorIdInt)) {
monitor = m;
break;
}
}
}
if (monitor == null && !sortedMonitors.isEmpty()) {
monitor = sortedMonitors.get(0);
}
RelativeTimePeriod period = RelativeTimePeriod.getPeriodByIdOrDefault(timeSpan);
/*
* Initialize the heirarchy under the service so that we don't get
* a LazyInitializationException later when the JSP page is pulling
* data out of the model object.
*/
Collection<OnmsMonitoredService> memberServices = m_monitoredServiceDao.findByApplication(application);
for (OnmsMonitoredService service : memberServices) {
m_locationMonitorDao.initialize(service.getIpInterface());
m_locationMonitorDao.initialize(service.getIpInterface().getNode());
}
Collection<OnmsMonitoredService> applicationMemberServices = m_monitoredServiceDao.findByApplication(application);
if (applicationMemberServices.isEmpty()) {
errors.add("There are no services in the application '" + applicationName + "'");
}
DistributedStatusHistoryModel model = new DistributedStatusHistoryModel(locationDefinitions,
sortedApplications,
sortedMonitors,
periods,
location,
application,
applicationMemberServices,
monitor,
period,
errors);
initializeGraphUrls(model);
return model;
}
private void initializeGraphUrls(DistributedStatusHistoryModel model) {
if (model.getChosenMonitor() != null) {
Collection<OnmsMonitoredService> services = model.getChosenApplicationMemberServices();
long[] times = model.getChosenPeriod().getStartAndEndTimes();
SortedSet<ServiceGraph> serviceGraphs = new TreeSet<ServiceGraph>(SERVICE_GRAPH_COMPARATOR);
for (OnmsMonitoredService service : services) {
serviceGraphs.add(getServiceGraphForService(model.getChosenMonitor(), service, times));
}
model.setServiceGraphs(serviceGraphs);
}
}
private ServiceGraph getServiceGraphForService(OnmsLocationMonitor locMon, OnmsMonitoredService service, long[] times) {
OnmsResource resource = m_resourceDao.getResourceForIpInterface(service.getIpInterface(), locMon);
if (resource == null) {
return new ServiceGraph(service, new String[] { "Resource could not be found. Has any response time data been collected for this service from this location monitor?" });
}
String graphName = service.getServiceName().toLowerCase();
try {
m_graphDao.getPrefabGraph(graphName);
} catch (ObjectRetrievalFailureException e) {
return new ServiceGraph(service, new String[] { "Graph definition could not be found for '" + graphName + "'. A graph definition needs to be created for this service." });
}
PrefabGraph[] prefabGraphs = m_graphDao.getPrefabGraphsForResource(resource);
for (PrefabGraph graph : prefabGraphs) {
if (graph.getName().equals(graphName)) {
String url = "graph/graph.png"
+ "?report=" + Util.encode(graph.getName())
+ "&resourceId=" + Util.encode(resource.getId())
+ "&start=" + times[0] + "&end=" + times[1];
return new ServiceGraph(service, url);
}
}
return new ServiceGraph(service, new String[] { "Graph could not be found for '" + graphName + "' on this resource. Has any response time data been collected for this service from this location monitor and is the graph definition correct?" });
}
/**
* <p>afterPropertiesSet</p>
*
* @throws java.lang.Exception if any.
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.state(m_monitoredServiceDao != null, "property monitoredServiceDao cannot be null");
Assert.state(m_locationMonitorDao != null, "property locationMonitorDao cannot be null");
Assert.state(m_applicationDao != null, "property applicationDao cannot be null");
Assert.state(m_resourceDao != null, "property resourceDao cannot be null");
Assert.state(m_graphDao != null, "property graphDao cannot be null");
}
/**
* <p>setMonitoredServiceDao</p>
*
* @param monitoredServiceDao a {@link org.opennms.netmgt.dao.MonitoredServiceDao} object.
*/
public void setMonitoredServiceDao(MonitoredServiceDao monitoredServiceDao) {
m_monitoredServiceDao = monitoredServiceDao;
}
/**
* <p>setLocationMonitorDao</p>
*
* @param locationMonitorDao a {@link org.opennms.netmgt.dao.LocationMonitorDao} object.
*/
public void setLocationMonitorDao(LocationMonitorDao locationMonitorDao) {
m_locationMonitorDao = locationMonitorDao;
}
/**
* <p>setApplicationDao</p>
*
* @param applicationDao a {@link org.opennms.netmgt.dao.ApplicationDao} object.
*/
public void setApplicationDao(ApplicationDao applicationDao) {
m_applicationDao = applicationDao;
}
/**
* <p>getResourceDao</p>
*
* @return a {@link org.opennms.netmgt.dao.ResourceDao} object.
*/
public ResourceDao getResourceDao() {
return m_resourceDao;
}
/**
* <p>setResourceDao</p>
*
* @param resourceDao a {@link org.opennms.netmgt.dao.ResourceDao} object.
*/
public void setResourceDao(ResourceDao resourceDao) {
m_resourceDao = resourceDao;
}
/**
* <p>getGraphDao</p>
*
* @return a {@link org.opennms.netmgt.dao.GraphDao} object.
*/
public GraphDao getGraphDao() {
return m_graphDao;
}
/**
* <p>setGraphDao</p>
*
* @param graphDao a {@link org.opennms.netmgt.dao.GraphDao} object.
*/
public void setGraphDao(GraphDao graphDao) {
m_graphDao = graphDao;
}
/**
* <p>setLayoutApplicationsVertically</p>
*
* @param layoutApplicationsVertically a boolean.
*/
public void setLayoutApplicationsVertically(boolean layoutApplicationsVertically) {
m_layoutApplicationsVertically = layoutApplicationsVertically;
}
/**
* <p>isLayoutApplicationsVertically</p>
*
* @return a boolean.
*/
public boolean isLayoutApplicationsVertically() {
return m_layoutApplicationsVertically;
}
}