/* Copyright 2009-2012 Comcast Interactive Media, LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fishwife.jrugged;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* A {@link RolledUpMonitoredService} provides for grouping {@link MonitoredService}
* instances together into a single system for status reporting purposes. Subsystems are
* divided into <em>critical</em> and <em>noncritical</em> groups. The system as a whole
* will only report UP status (GREEN) if all subsystems, critical and noncritical alike,
* are likewise UP. Critical systems are necessary for providing functionality within the
* system, so the system as a whole reports the lowest (least functional) status of any
* critical systems which are not UP. If all critical systems are UP, but one or more
* noncritical systems are not UP, then the system as a whole will be in the DEGRADED
* (YELLOW) state.
*/
public class RolledUpMonitoredService implements MonitoredService {
private final String name;
private final Collection<? extends MonitoredService> criticals;
private final Collection<? extends MonitoredService> noncriticals;
/**
* Initializes the {@link RolledUpMonitoredService} with its component subsystems.
*
* @param name
* the name for this rolled up service.
* @param criticals
* the set of {@link MonitoredService} subsystems that are necessary for
* the system as a whole to be functional
* @param noncriticals
* the set of <code>MonitoredService</code> subsystems that are part of the
* system as a whole but which are not strictly necessary for
* functionality.
*/
public RolledUpMonitoredService(final String name,
final Collection<? extends MonitoredService> criticals,
final Collection<? extends MonitoredService> noncriticals) {
this.name = name;
this.criticals = criticals;
this.noncriticals = noncriticals;
}
/**
* Get the {@link ServiceStatus} for the rolled up service. The name for the
* ServiceStatus is the name of this rolled up service. The {@link Status} is computed
* based on the status of the critical and non-critical subsystems. The {@link List}
* of reasons contains the reasons reported for each system. Each service returns the
* service name in addition to the reason that it has that status (which is reported
* by the service itself)
*
* @return the {@link ServiceStatus}.
*/
@Override
public ServiceStatus getServiceStatus() {
final List<String> reasons = new ArrayList<>();
Status criticalStatus = Status.UP;
for (final MonitoredService m : criticals) {
final ServiceStatus serviceStatus = m.getServiceStatus();
final Status status = serviceStatus.getStatus();
if (statusIsNotUp(status)) {
for (final String reason : serviceStatus.getReasons()) {
reasons.add(serviceStatus.getName() + ":" + reason);
}
}
if (status.getValue() < criticalStatus.getValue()) {
criticalStatus = status;
}
}
Status result = Status.UP;
for (final MonitoredService m : noncriticals) {
final ServiceStatus serviceStatus = m.getServiceStatus();
final Status status = serviceStatus.getStatus();
if (statusIsNotUp(status)) {
for (final String reason : serviceStatus.getReasons()) {
reasons.add(serviceStatus.getName() + ":" + reason);
}
result = Status.DEGRADED;
}
}
if (criticalStatus.getValue() < result.getValue()) {
result = criticalStatus;
}
return new ServiceStatus(name, result, reasons);
}
/**
* Get the {@link List} of {@link ServiceStatus} instances for all subsystems.
*
* @return the {@link List} of {@link ServiceStatus} instances.
*/
public List<ServiceStatus> getAllStatuses() {
final List<ServiceStatus> list = getCriticalStatuses();
list.addAll(getNonCriticalStatuses());
return list;
}
/**
* Get the {@link List} of {@link ServiceStatus} instances for all critical
* subsystems.
*
* @return the {@link List} of {@link ServiceStatus} instances.
*/
public List<ServiceStatus> getCriticalStatuses() {
final List<ServiceStatus> list = new ArrayList<>();
for (final MonitoredService m : criticals) {
final ServiceStatus serviceStatus = m.getServiceStatus();
list.add(serviceStatus);
}
return list;
}
/**
* Get the {@link List} of {@link ServiceStatus} instances for all non-critical
* subsystems.
*
* @return the {@link List} of {@link ServiceStatus} instances.
*/
public List<ServiceStatus> getNonCriticalStatuses() {
final List<ServiceStatus> list = new ArrayList<>();
for (final MonitoredService m : noncriticals) {
final ServiceStatus serviceStatus = m.getServiceStatus();
list.add(serviceStatus);
}
return list;
}
private boolean statusIsNotUp(final Status status) {
return Status.UP != status;
}
}