/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 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.rest;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import org.opennms.netmgt.dao.ApplicationDao;
import org.opennms.netmgt.dao.LocationMonitorDao;
import org.opennms.netmgt.dao.MonitoredServiceDao;
import org.opennms.netmgt.dao.NodeDao;
import org.opennms.netmgt.model.OnmsApplication;
import org.opennms.netmgt.model.OnmsLocationAvailDataPoint;
import org.opennms.netmgt.model.OnmsLocationAvailDefinition;
import org.opennms.netmgt.model.OnmsLocationAvailDefinitionList;
import org.opennms.netmgt.model.OnmsLocationMonitor;
import org.opennms.netmgt.model.OnmsLocationSpecificStatus;
import org.opennms.netmgt.model.OnmsMonitoringLocationDefinition;
import org.opennms.netmgt.model.OnmsMonitoringLocationDefinitionList;
import org.opennms.netmgt.model.OnmsNode;
import org.opennms.web.rest.support.TimeChunker;
import org.opennms.web.rest.support.TimeChunker.TimeChunk;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import com.sun.jersey.spi.resource.PerRequest;
@Component
@PerRequest
@Path("remotelocations")
@Transactional
public class RemotePollerAvailabilityService extends OnmsRestService {
@Autowired
LocationMonitorDao m_locationMonitorDao;
@Autowired
ApplicationDao m_applicationDao;
@Autowired
MonitoredServiceDao m_monitoredServiceDao;
@Autowired
NodeDao m_nodeDao;
@Autowired
TransactionTemplate m_transactionTemplate;
@Context
UriInfo m_uriInfo;
OnmsLocationAvailDefinitionList m_defList = null;
private Timer m_timer = null;
public RemotePollerAvailabilityService() {
super();
}
protected TimeChunker getTimeChunkerFromMidnight() {
Calendar calendar = Calendar.getInstance();
Date startTime = new GregorianCalendar(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0,0,0).getTime();
TimeChunker chunker = new TimeChunker(TimeChunker.MINUTE, startTime, new Date(System.currentTimeMillis()));
return chunker;
}
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public OnmsMonitoringLocationDefinitionList getRemoteLocationList(){
readLock();
try {
List<OnmsMonitoringLocationDefinition> monitors = m_locationMonitorDao.findAllMonitoringLocationDefinitions();
return new OnmsMonitoringLocationDefinitionList(monitors);
} finally {
readUnlock();
}
}
/**
* Currently only here for world IPv6 day, returns all nodelabels.
* @return
*/
@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("participants")
public String getParticipants(){
readLock();
try {
List<OnmsNode> nodes = m_nodeDao.findAll();
StringBuffer retVal = new StringBuffer();
retVal.append("{\"participants\":[");
for(int i = 0; i < nodes.size(); i++) {
OnmsNode node = nodes.get(i);
if(i == 0) {
retVal.append("{\"name\":\"" + node.getLabel() + "\"}");
}else {
retVal.append(",{\"name\":\"" + node.getLabel() + "\"}");
}
}
retVal.append("]}");
return retVal.toString();
} finally {
readUnlock();
}
}
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Path("availability")
public OnmsLocationAvailDefinitionList getAvailability() throws InterruptedException {
readLock();
try {
if(m_timer == null) {
MultivaluedMap<String, String> queryParameters = m_uriInfo.getQueryParameters();
m_defList = getAvailabilityList(createTimeChunker(queryParameters), getSortedApplications(), null, getSelectedNodes(queryParameters));
TimerTask task = new TimerTask() {
@Override
public void run() {
m_defList = m_transactionTemplate.execute(new TransactionCallback<OnmsLocationAvailDefinitionList>() {
public OnmsLocationAvailDefinitionList doInTransaction(TransactionStatus status) {
return getAvailabilityList(getTimeChunkerFromMidnight(), getSortedApplications(), null, null);
}
});
}
};
m_timer = new Timer("AvailCalculator-Timer");
m_timer.scheduleAtFixedRate(task, TimeChunker.MINUTE, TimeChunker.MINUTE);
}
return m_defList;
} finally {
readUnlock();
}
}
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Path("availability/{location}")
public OnmsLocationAvailDefinitionList getAvailabilityByLocation(@PathParam("location") String location) {
readLock();
try {
MultivaluedMap<String, String> queryParameters = m_uriInfo.getQueryParameters();
OnmsMonitoringLocationDefinition locationDefinition = m_locationMonitorDao.findMonitoringLocationDefinition(location);
Collection<OnmsLocationMonitor> monitors = m_locationMonitorDao.findByLocationDefinition(locationDefinition);
OnmsLocationAvailDefinitionList availList = getAvailabilityList(createTimeChunker(queryParameters), getSortedApplications(), monitors, null);
return availList;
} finally {
readUnlock();
}
}
/**
*
* @param timeChunker
* @param sortedApplications
* @param selectedMonitors
* @param selectedNodes
* @return
*/
private OnmsLocationAvailDefinitionList getAvailabilityList(TimeChunker timeChunker, List<OnmsApplication> sortedApplications, Collection<OnmsLocationMonitor> selectedMonitors, Collection<OnmsNode> selectedNodes) {
OnmsLocationAvailDefinitionList availList = new OnmsLocationAvailDefinitionList();
List<String> names = new ArrayList<String>(sortedApplications.size());
for(OnmsApplication app : sortedApplications) {
names.add(app.getName());
}
Collection<OnmsLocationSpecificStatus> statusesPeriod = m_locationMonitorDao.getStatusChangesBetweenForApplications(timeChunker.getStartDate(), timeChunker.getEndDate(), names);
AvailCalculator availCalc = new AvailCalculator(timeChunker);
removeUnneededMonitors(statusesPeriod, selectedMonitors);
removeUnneededServices(statusesPeriod, selectedNodes);
for(OnmsLocationSpecificStatus statusChange : statusesPeriod) {
availCalc.onStatusChange(statusChange);
}
int counter = 0;
for(int i =0; i < timeChunker.getSegmentCount(); i++) {
counter++;
TimeChunk timeChunk = timeChunker.getAt(i);
OnmsLocationAvailDataPoint point = new OnmsLocationAvailDataPoint();
point.setTime(timeChunk.getEndDate());
for(OnmsApplication application : sortedApplications) {
double percentage = availCalc.getAvailabilityFor(m_monitoredServiceDao.findByApplication(application), i);
String strPercent = new DecimalFormat("0.0").format(percentage * 100);
point.addAvailDefinition(new OnmsLocationAvailDefinition(application.getName(), strPercent));
}
availList.add(point);
}
System.err.println(new Date() + "After Calculations total loops: " + counter);
return availList;
}
private void removeUnneededServices(Collection<OnmsLocationSpecificStatus> statusesPeriod, Collection<OnmsNode> selectedNodes) {
if(selectedNodes != null) {
Collection<OnmsLocationSpecificStatus> unneededStatuses = new ArrayList<OnmsLocationSpecificStatus>();
for(OnmsLocationSpecificStatus status : statusesPeriod) {
for(OnmsNode node : selectedNodes) {
if(status.getMonitoredService().getNodeId() == node.getId()) {
unneededStatuses.add(status);
}
}
}
statusesPeriod.removeAll(unneededStatuses);
}
}
private void removeUnneededMonitors(Collection<OnmsLocationSpecificStatus> statusesPeriod, Collection<OnmsLocationMonitor> selectedMonitors) {
if(selectedMonitors != null) {
Collection<OnmsLocationSpecificStatus> unneededStatuses = new ArrayList<OnmsLocationSpecificStatus>();
for(OnmsLocationSpecificStatus status : statusesPeriod) {
for(OnmsLocationMonitor monitor : selectedMonitors) {
if(status.getLocationMonitor().getId() == monitor.getId()) {
unneededStatuses.add(status);
}
}
}
statusesPeriod.removeAll(unneededStatuses);
}
}
private int getResolution(MultivaluedMap<String, String> params) {
if(params.containsKey("resolution")) {
String resolution = params.getFirst("resolution");
if(resolution.equalsIgnoreCase("minute")) {
return TimeChunker.MINUTE;
} else if(resolution.equalsIgnoreCase("hourly")) {
return TimeChunker.HOURLY;
}else if(resolution.equalsIgnoreCase("daily")){
return TimeChunker.DAILY;
}else {
return TimeChunker.MINUTE;
}
} else {
return TimeChunker.MINUTE;
}
}
private Date getEndTime(MultivaluedMap<String, String> params) {
if(params.containsKey("endTime")) {
String value = params.getFirst("endTime");
return new Date(Long.valueOf(value));
} else {
return new Date();
}
}
private Date getStartTime(MultivaluedMap<String, String> params) {
if(params.containsKey("startTime")) {
String startTime = params.getFirst("startTime");
return new Date(Long.valueOf(startTime));
} else {
Calendar calendar = Calendar.getInstance();
return new GregorianCalendar(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0).getTime();
}
}
private Collection<OnmsNode> getSelectedNodes(MultivaluedMap<String, String> queryParameters) {
if(queryParameters.containsKey("host")) {
String nodeLabel = queryParameters.getFirst("host");
return m_nodeDao.findByLabel(nodeLabel);
}else {
return null;
}
}
private TimeChunker createTimeChunker(MultivaluedMap<String, String> params) {
TimeChunker timeChunker;
Date start = getStartTime(params);
Date end = getEndTime(params);
if((end.getTime() - start.getTime()) < TimeChunker.MINUTE) {
throw new IllegalArgumentException("The endTime has to be after the startTime by 5 minutes.\nCurrently the startTime is " + start + " and endTime is " + end);
}
timeChunker = new TimeChunker(getResolution(params), start, end);
return timeChunker;
}
private List<OnmsApplication> getSortedApplications() {
List<OnmsApplication> sortedApplications;
Collection<OnmsApplication> applications = m_applicationDao.findAll();
if (applications.size() == 0) {
throw new IllegalArgumentException("there are no applications");
}
sortedApplications = new ArrayList<OnmsApplication>(applications);
Collections.sort(sortedApplications);
return sortedApplications;
}
}