org.miloss.fgsms.services.rs.impl.reports.AvailabilityByService.java Source code

Java tutorial

Introduction

Here is the source code for org.miloss.fgsms.services.rs.impl.reports.AvailabilityByService.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.miloss.fgsms.services.rs.impl.reports;

import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.List;
import javax.xml.ws.WebServiceContext;
import org.apache.log4j.Level;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.TimeSeriesDataItem;
import org.miloss.fgsms.common.DBUtils;
import org.miloss.fgsms.common.UserIdentityUtil;
import org.miloss.fgsms.common.Utility;
import org.miloss.fgsms.services.interfaces.common.PolicyType;
import org.miloss.fgsms.services.interfaces.common.SecurityWrapper;
import org.miloss.fgsms.services.interfaces.common.TimeRange;
import org.miloss.fgsms.plugins.reporting.ReportGeneratorPlugin;
import org.miloss.fgsms.services.interfaces.common.NameValuePair;
import static org.miloss.fgsms.services.rs.impl.Reporting.getFilePathDelimitor;
import static org.miloss.fgsms.services.rs.impl.Reporting.log;
import org.miloss.fgsms.services.rs.impl.StatusRecordsExt;

/**
 *
 * @author AO
 */
public class AvailabilityByService implements ReportGeneratorPlugin {

    @Override
    public String GetDisplayName() {
        return "Availability By Service";
    }

    @Override
    public String GetHtmlFormattedHelp() {
        return "This represents the availability over time. A value of 1 " + "represents operational and 0 "
                + "represents non-operational status. "
                + "For web services, this is limited by the ability for the Bueller component to a) connect to the service and b) authenticate to it.";
    }

    @Override
    public List<PolicyType> GetAppliesTo() {
        ArrayList<PolicyType> ret = new ArrayList<PolicyType>();
        ret.add(PolicyType.TRANSACTIONAL);
        ret.add(PolicyType.MACHINE);
        ret.add(PolicyType.PROCESS);
        ret.add(PolicyType.STATISTICAL);
        ret.add(PolicyType.STATUS);
        return ret;
    }

    @Override
    public void generateReport(OutputStreamWriter data, List<String> urls, String path, List<String> files,
            TimeRange range, String currentuser, SecurityWrapper classification, WebServiceContext ctx)
            throws IOException {

        Connection con = Utility.getPerformanceDBConnection();
        try {

            JFreeChart chart = null;

            data.append("<hr /><h2>").append(GetDisplayName()).append("</h2>");
            data.append(GetHtmlFormattedHelp() + "<br />");
            data.append(
                    "<table class=\"table table-hover\"><tr><th>URI</th><th>Number of status changes</th><th>Percent Uptime</th><th>Percent Downtime</th></tr>");
            DecimalFormat percentFormat = new DecimalFormat("###.#####");
            TimeSeriesCollection col = new TimeSeriesCollection();
            for (int i = 0; i < urls.size(); i++) {
                //https://github.com/mil-oss/fgsms/issues/112
                if (!UserIdentityUtil.hasReadAccess(currentuser, "getReport", urls.get(i), classification, ctx)) {
                    continue;
                }
                String url = Utility.encodeHTML(BaseReportGenerator.getPolicyDisplayName(urls.get(i)));
                TimeSeries s1 = new TimeSeries(url, org.jfree.data.time.Millisecond.class);
                try {
                    data.append("<tr><td>").append(url).append("</td>");
                    List<StatusRecordsExt> records = getStatusRecords(urls.get(i), range, con);
                    //special case, no status records available
                    if (records == null || records.isEmpty()) {
                        data.append("<td>-</td><td>-</td></tr>");
                        continue;
                    }
                    double uptime = getUptimePercentage(records, range);
                    data.append("<td>").append(records.size() + "").append("</td><td>")
                            .append(percentFormat.format(uptime)).append("</td><td>")
                            .append(percentFormat.format(100 - uptime)).append("</td></tr>");
                    TimeSeriesDataItem t = null;
                    for (int k = 0; k < records.size(); k++) {
                        if (records.get(k).status) {
                            try {
                                t = new TimeSeriesDataItem(new Millisecond(records.get(k).gcal.getTime()), 1);
                                s1.addOrUpdate(t);
                            } catch (Exception ex) {
                                log.log(Level.WARN, null, ex);
                            }
                        } else {
                            try {
                                t = new TimeSeriesDataItem(new Millisecond(records.get(k).gcal.getTime()), 0);
                                s1.addOrUpdate(t);
                            } catch (Exception ex) {
                                log.log(Level.WARN, null, ex);
                            }
                        }
                        col.addSeries(s1);
                    }

                } catch (Exception ex) {
                    log.log(Level.ERROR, "Error opening or querying the database.", ex);
                }

            }
            chart = org.jfree.chart.ChartFactory.createTimeSeriesChart(GetDisplayName(), "Timestamp", "Status", col,
                    true, false, false);

            data.append("</table>");
            try {
                ChartUtilities.saveChartAsPNG(new File(
                        path + getFilePathDelimitor() + "image_" + this.getClass().getSimpleName() + ".png"), chart,
                        1500, 800);
                data.append("<img src=\"image_").append(this.getClass().getSimpleName()).append(".png\">");
                files.add(path + getFilePathDelimitor() + "image_" + this.getClass().getSimpleName() + ".png");

            } catch (IOException ex) {
                log.log(Level.ERROR, "Error saving chart image for request", ex);
            }
        } catch (Exception ex) {
            log.log(Level.ERROR, null, ex);
        } finally {
            DBUtils.safeClose(con);
        }
    }

    private List<StatusRecordsExt> getStatusRecords(String url, TimeRange range, Connection con) {
        List<StatusRecordsExt> ret = new ArrayList<StatusRecordsExt>();
        //first get the record just before the start of the range, if it exists
        PreparedStatement com = null;
        ResultSet rs = null;
        try {
            com = con.prepareStatement(
                    "select status from availability where uri=? and  utcdatetime < ? order by utcdatetime desc limit 1;");
            com.setString(1, url);
            com.setLong(2, range.getStart().getTimeInMillis());
            rs = com.executeQuery();
            if (rs.next()) {
                //add a record for the exact start time of the range
                StatusRecordsExt x = new StatusRecordsExt();
                x.gcal = new GregorianCalendar();
                x.gcal.setTimeInMillis(range.getStart().getTimeInMillis());
                x.status = rs.getBoolean("status");
                ret.add(x);
            }
        } catch (Exception ex) {
            log.log(Level.WARN, null, ex);
        } finally {
            DBUtils.safeClose(rs);
            DBUtils.safeClose(com);
        }
        try {
            //get everything within the range
            com = con.prepareStatement(
                    "select * from availability where uri=? and  utcdatetime >= ?  and utcdatetime <=? order by utcdatetime asc;");
            com.setString(1, url);
            com.setLong(2, range.getStart().getTimeInMillis());
            com.setLong(3, range.getEnd().getTimeInMillis());
            rs = com.executeQuery();
            boolean lastStatus = true;
            while (rs.next()) {
                //in order to produce a square wave style chart, inject an additional point for this time-1 for the same status
                //as the previous item
                if (!ret.isEmpty()) {
                    StatusRecordsExt get = ret.get(ret.size() - 1);
                    StatusRecordsExt x = new StatusRecordsExt();
                    x.gcal = new GregorianCalendar();
                    x.gcal.setTimeInMillis(rs.getLong("utcdatetime") - 1);
                    x.status = get.status;
                    ret.add(x);
                }
                StatusRecordsExt x = new StatusRecordsExt();
                x.gcal = new GregorianCalendar();
                x.gcal.setTimeInMillis(rs.getLong("utcdatetime"));
                x.status = rs.getBoolean("status");
                lastStatus = x.status;
                ret.add(x);
            }

            StatusRecordsExt x = new StatusRecordsExt();
            x.gcal = new GregorianCalendar();
            x.gcal.setTimeInMillis(range.getEnd().getTimeInMillis());
            x.status = lastStatus;
            ret.add(x);

            //getting the next record isn't important in this case as we are only interested in data within the range.
            return ret;
        } catch (Exception ex) {

            log.log(Level.WARN, null, ex);
        } finally {
            DBUtils.safeClose(rs);
            DBUtils.safeClose(com);
        }
        return null;
    }

    /**
     *
     * @param records a non empty list
     * @param range
     * @return
     */
    private double getUptimePercentage(List<StatusRecordsExt> records, TimeRange range) {
        long totaluptime = 0;
        long totaltime = range.getEnd().getTimeInMillis() - range.getStart().getTimeInMillis();
        if (records.size() == 1) {
            if (records.get(0).status) {
                return 100;
            } else {
                return 0;
            }
        }
        for (int i = 0; i < records.size() - 1; i++) {
            if (records.get(i).status) {
                totaluptime += records.get(i + 1).gcal.getTimeInMillis() - records.get(i).gcal.getTimeInMillis();
            }
        }
        if (records.get(records.size() - 1).status) {
            totaluptime += range.getEnd().getTimeInMillis()
                    - records.get(records.size() - 1).gcal.getTimeInMillis();
        }
        if (totaltime > 0) {
            return (double) ((double) totaluptime / (double) totaltime * 100D);
        }
        return -1;
    }

    @Override
    public List<NameValuePair> GetRequiredParameters() {
        return Collections.EMPTY_LIST;
    }

    @Override
    public List<NameValuePair> GetOptionalParameters() {
        return Collections.EMPTY_LIST;
    }

}