/*
* The MIT License
*
* Copyright 2013 Sony Mobile Communications AB. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.sonyericsson.jenkins.plugins.bfa;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import org.kohsuke.stapler.StaplerRequest;
import com.sonyericsson.jenkins.plugins.bfa.graphs.GraphCache;
import com.sonyericsson.jenkins.plugins.bfa.graphs.GraphType;
import hudson.model.ModelObject;
import hudson.model.RootAction;
import hudson.util.Graph;
/**
* Abstract class to handle the detailed graphs pages.
* @author Christoffer Lauri <christoffer.lauri@sonymobile.com>
*
*/
public abstract class BfaGraphAction implements RootAction {
/**
* Url-parameter for indicating time period to show in a graph.
*/
protected static final String URL_PARAM_TIME_PERIOD = "time";
/**
* Url-parameter for indicating which graph to show.
*/
protected static final String URL_PARAM_WHICH_GRAPH = "which";
/**
* Url-parameter for indicating whether to show or hide aborted builds.
*/
protected static final String URL_PARAM_SHOW_ABORTED = "showAborted";
/**
* Url-parameter for indicating whether to show for all masters or not.
*/
protected static final String URL_PARAM_ALL_MASTERS = "allMasters";
/**
* Url-parameter value for 'today'.
*/
protected static final String URL_PARAM_VALUE_TODAY = "today";
/**
* Url-parameter value for 'month'.
*/
protected static final String URL_PARAM_VALUE_MONTH = "month";
/**
* Url-parameter value for 'max'.
*/
protected static final String URL_PARAM_VALUE_MAX = "max";
/**
* Default width for graphs on detail pages.
*/
protected static final int DEFAULT_GRAPH_WIDTH = 700;
/**
* Default height for graphs on detail pages.
*/
protected static final int DEFAULT_GRAPH_HEIGHT = 500;
/**
* Constant for "ABORTED"-cause (used to exclude such {@link FailureCause}s).
*/
protected static final String EXCLUDE_ABORTED = "ABORTED";
/**
* Separator between different parts of graph IDs.
*/
protected static final char ID_SEPARATOR = '-';
/**
* Get the owner.
* @return The owner
*/
public abstract ModelObject getOwner();
/**
* Returns an array of {@link GraphType}s, where each element represents
* a graph. These are the types used to display the graphs/images
* on the detailed graphs page, that is, they will be the 'which'-parameter
* to getGraph(GraphType which, Date ...).
* The graphs are displayed in the same order as the numbers in the array.
* @return An array of {@link GraphType}s where each element
* represents a graph to display
*/
public abstract GraphType[] getGraphTypes();
/**
* Get the title to display in the top of the detailed graphs page.
* @return The title as a String
*/
public abstract String getGraphsPageTitle();
/**
* Get the graph corresponding to the specified arguments.
* @param which Which graph to display
* @param timePeriod How old statistics should be included in the graph
* @param hideManAborted Hide manually aborted causes
* @param allMasters Show for all masters
* @param rawReqParams The url parameters that came with the request
* @return A Graph
*/
protected abstract Graph getGraph(GraphType which, Date timePeriod,
boolean hideManAborted, boolean allMasters,
Map<String, String> rawReqParams);
/**
* Get the Graph corresponding to the url-parameters.
* Parameters:
* - time : how far back should statistics be included
* - which : which graph to display
* - showAborted : show manually aborted
* - allMasters : show for all masters
* @param req The StaplerRequest
* @return A graph
*/
public Graph getGraph(StaplerRequest req) {
final Map<String, String> rawReqParams = new HashMap<String, String>();
String reqTimePeriod = req.getParameter(URL_PARAM_TIME_PERIOD);
if (reqTimePeriod == null || !reqTimePeriod.matches(URL_PARAM_VALUE_MONTH + "|" + URL_PARAM_VALUE_MAX)) {
reqTimePeriod = URL_PARAM_VALUE_TODAY; // The default value
}
rawReqParams.put(URL_PARAM_TIME_PERIOD, reqTimePeriod);
String reqWhich = req.getParameter(URL_PARAM_WHICH_GRAPH);
rawReqParams.put(URL_PARAM_WHICH_GRAPH, reqWhich);
String showAborted = req.getParameter(URL_PARAM_SHOW_ABORTED);
rawReqParams.put(URL_PARAM_SHOW_ABORTED, showAborted);
String allMasters = req.getParameter(URL_PARAM_ALL_MASTERS);
rawReqParams.put(URL_PARAM_ALL_MASTERS, allMasters);
final Date sinceDate = getDateForUrlStr(reqTimePeriod);
int tmpWhichGraph = -1;
try {
tmpWhichGraph = Integer.parseInt(reqWhich);
} catch (NumberFormatException e) {
e.printStackTrace();
}
final GraphType whichGraph = GraphType.toEnum(tmpWhichGraph);
final boolean hideAborted = "0".equals(showAborted);
final boolean forAllMasters = "1".equals(allMasters);
String id = getGraphCacheId(whichGraph, reqTimePeriod, hideAborted, forAllMasters);
Graph graphToReturn = null;
try {
graphToReturn = GraphCache.getInstance().get(id, new Callable<Graph>() {
@Override
public Graph call() throws Exception {
// The requested graph isn't cached, so create a new one.
Graph g = getGraph(whichGraph, sinceDate, hideAborted, forAllMasters, rawReqParams);
if (g != null) {
return g;
}
// According to documentation, null must not be returned; either
// a non-null value must be returned, or an an exception thrown
throw new ExecutionException("Graph-parameters not valid", null);
} });
} catch (ExecutionException e) {
// An exception will occur when a graph cannot be generated,
// e.g. when erroneous url-parameters have been specified
e.printStackTrace();
}
return graphToReturn;
}
/**
* Get a unique id used in the caching of the graph.
* @param whichGraph Which graph
* @param reqTimePeriod The selected time period
* @param hideAborted Hide aborted builds
* @param forAllMasters For all masters
* @return An id corresponding to the specified arguments
*/
protected abstract String getGraphCacheId(GraphType whichGraph,
String reqTimePeriod, boolean hideAborted, boolean forAllMasters);
/**
* Helper for groovy-views; Get the default width of graphs on detailed pages.
* @return The default height of graphs on the detailed graphs-page
*/
public int getDefaultGraphWidth() {
return DEFAULT_GRAPH_WIDTH;
}
/**
* Helper for groovy-views; Get the default height of graphs on detailed pages.
* @return The default height of graphs on the detailed graphs-page
*/
public int getDefaultGraphHeight() {
return DEFAULT_GRAPH_HEIGHT;
}
/**
* Helper for the groovy-views; show/hide Masters-switch.
* Whether to show links for switching between all masters
* and the own master.
* @return True to show the switch, otherwise false
*/
public boolean showMasterSwitch() {
return false;
}
/**
* Helper for the groovy-views; show/hide info text for graph delay.
* The info text will inform the user about the delay for graphs
* because of caching.
* @return True to show the text, otherwise false
*/
public boolean showGraphDelayText() {
return false;
}
/**
* Get a Date object corresponding to the specified string.
* (today|month).
* @param str The String
* @return A Date, or null if not equal to "today" or "month"
*/
private Date getDateForUrlStr(String str) {
Calendar cal = Calendar.getInstance();
Date date = null;
if (URL_PARAM_VALUE_TODAY.equals(str)) {
cal.add(Calendar.DAY_OF_YEAR, -1);
date = cal.getTime();
} else if (URL_PARAM_VALUE_MONTH.equals(str)) {
cal.add(Calendar.MONTH, -1);
date = cal.getTime();
} // max time => return null
return date;
}
}