package hudson.plugins.disk_usage;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Run;
import hudson.model.Hudson;
import hudson.util.ChartUtil;
import hudson.util.ChartUtil.NumberOnlyBuildLabel;
import hudson.util.ColorPalette;
import hudson.util.DataSetBuilder;
import hudson.util.ShiftedCategoryAxis;
import hudson.plugins.disk_usage.DiskUsageProperty.DiskUsageDescriptor;
import java.awt.BasicStroke;
import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* Disk usage of a project
*
* @author dvrzalik
*/
public class ProjectDiskUsageAction extends DiskUsageAction {
AbstractProject<? extends AbstractProject, ? extends AbstractBuild> project;
public ProjectDiskUsageAction(AbstractProject<? extends AbstractProject, ? extends AbstractBuild> project) {
this.project = project;
}
@Override
public String getUrlName() {
return "disk-usage";
}
/**
* @return Disk usage for all builds
*/
public DiskUsage getDiskUsage() {
DiskUsage du = new DiskUsage(0, 0);
if (project != null) {
BuildDiskUsageAction action = null;
Iterator<? extends AbstractBuild> buildIterator = project.getBuilds().iterator();
while ((action == null) && buildIterator.hasNext()) {
action = buildIterator.next().getAction(BuildDiskUsageAction.class);
}
if (action != null) {
DiskUsage bdu = action.getDiskUsage();
//Take last available workspace size
du.wsUsage = bdu.getWsUsage();
du.buildUsage += bdu.getBuildUsage();
}
while (buildIterator.hasNext()) {
action = buildIterator.next().getAction(BuildDiskUsageAction.class);
if (action != null) {
du.buildUsage += action.getDiskUsage().getBuildUsage();
}
}
}
return du;
}
public BuildDiskUsageAction getLastBuildAction() {
Run run = project.getLastBuild();
if (run != null) {
return run.getAction(BuildDiskUsageAction.class);
}
return null;
}
/**
* Generates a graph with disk usage trend
*
*/
public void doGraph(StaplerRequest req, StaplerResponse rsp) throws IOException {
if (ChartUtil.awtProblemCause != null) {
// not available. send out error message
rsp.sendRedirect2(req.getContextPath() + "/images/headless.png");
return;
}
//TODO if(nothing_changed) return;
DataSetBuilder<String, NumberOnlyBuildLabel> dsb = new DataSetBuilder<String, NumberOnlyBuildLabel>();
List<Object[]> usages = new ArrayList<Object[]>();
long maxValue = 0;
//First iteration just to get scale of the y-axis
for (AbstractBuild build : project.getBuilds()) {
BuildDiskUsageAction dua = build.getAction(BuildDiskUsageAction.class);
if (dua != null) {
DiskUsage usage = dua.getDiskUsage();
maxValue = Math.max(maxValue, Math.max(usage.wsUsage, usage.getBuildUsage()));
usages.add(new Object[]{build, usage.wsUsage, usage.getBuildUsage()});
}
}
int floor = (int) DiskUsage.getScale(maxValue);
String unit = DiskUsage.getUnitString(floor);
double base = Math.pow(1024, floor);
for (Object[] usage : usages) {
NumberOnlyBuildLabel label = new NumberOnlyBuildLabel((AbstractBuild) usage[0]);
dsb.add(((Long) usage[1]) / base, "workspace", label);
dsb.add(((Long) usage[2]) / base, "build", label);
}
ChartUtil.generateGraph(req, rsp, createChart(req, dsb.build(), unit), 350, 150);
}
private JFreeChart createChart(StaplerRequest req, CategoryDataset dataset, String unit) {
final JFreeChart chart = ChartFactory.createLineChart(
null, // chart title
null, // unused
"disk usage (" + unit + ")", // range axis label
dataset, // data
PlotOrientation.VERTICAL, // orientation
true, // include legend
true, // tooltips
false // urls
);
final LegendTitle legend = chart.getLegend();
legend.setPosition(RectangleEdge.RIGHT);
chart.setBackgroundPaint(Color.white);
final CategoryPlot plot = chart.getCategoryPlot();
plot.setBackgroundPaint(Color.WHITE);
plot.setOutlinePaint(null);
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.black);
CategoryAxis domainAxis = new ShiftedCategoryAxis(null);
plot.setDomainAxis(domainAxis);
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
domainAxis.setLowerMargin(0.0);
domainAxis.setUpperMargin(0.0);
domainAxis.setCategoryMargin(0.0);
final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
rangeAxis.setLowerBound(0);
final LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
renderer.setStroke(new BasicStroke(4.0f));
ColorPalette.apply(renderer);
plot.setInsets(new RectangleInsets(5.0, 0, 0, 5.0));
return chart;
}
/** Shortcut for the jelly view */
public boolean showGraph() {
return Hudson.getInstance().getDescriptorByType(DiskUsageDescriptor.class).isShowGraph();
}
}