package hudson.plugins.plot;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.matrix.MatrixConfiguration;
import hudson.matrix.MatrixRun;
import hudson.matrix.MatrixProject;
import hudson.model.Action;
import hudson.model.BuildListener;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.plugins.plot.Messages;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Publisher;
import hudson.util.FormValidation;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.json.JSONObject;
import org.apache.commons.lang.ObjectUtils;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
/**
*
* @author lucinka
*/
public class MatrixPlotPublisher extends AbstractPlotPublisher {
transient private Map<MatrixConfiguration, List<Plot>> plotsOfConfigurations = new HashMap<MatrixConfiguration, List<Plot>>();
transient private Map<String, List<Plot>> groupMap = new HashMap<String, List<Plot>>();
/**
* Configured plots.
*/
private List<Plot> plots = new ArrayList<Plot>();
public String urlGroupToOriginalGroup(String urlGroup, MatrixConfiguration c) {
if (urlGroup == null || "nogroup".equals(urlGroup)) {
return "Plots";
}
if (groupMap.containsKey(urlGroup)) {
List<Plot> plots = new ArrayList<Plot>();
for (Plot plot : groupMap.get(urlGroup)) {
if (ObjectUtils.equals(plot.getProject(), c)) {
plots.add(plot);
}
}
if (plots.size() > 0) {
return plots.get(0).group;
}
}
return "";
}
/**
* Returns all group names as the original user specified strings.
*/
public List<String> getOriginalGroups(MatrixConfiguration configuration) {
List<String> originalGroups = new ArrayList<String>();
for (String urlGroup : groupMap.keySet()) {
originalGroups
.add(urlGroupToOriginalGroup(urlGroup, configuration));
}
Collections.sort(originalGroups);
return originalGroups;
}
/**
* Reset Configuration and set plots settings for matrixConfiguration
*
* @param plots
* the new list of plots
*/
public void setPlots(List<Plot> plots) {
this.plots = plots;
groupMap = new HashMap<String, List<Plot>>();
plotsOfConfigurations = new HashMap<MatrixConfiguration, List<Plot>>();
}
/**
* Adds the new plot to the plot data structures managed by this object.
*
* @param plot
* the new plot
*/
public void addPlot(Plot plot) {
String urlGroup = originalGroupToUrlEncodedGroup(plot.getGroup());
if (groupMap.containsKey(urlGroup)) {
List<Plot> list = groupMap.get(urlGroup);
list.add(plot);
} else {
List<Plot> list = new ArrayList<Plot>();
list.add(plot);
groupMap.put(urlGroup, list);
}
if (plotsOfConfigurations.get((MatrixConfiguration) plot.getProject()) == null) {
List<Plot> list = new ArrayList<Plot>();
list.add(plot);
plotsOfConfigurations.put((MatrixConfiguration) plot.getProject(),
list);
} else {
plotsOfConfigurations.get((MatrixConfiguration) plot.getProject())
.add(plot);
}
}
/**
* Returns the entire list of plots managed by this object.
*/
public List<Plot> getPlots(MatrixConfiguration configuration) {
List<Plot> p = plotsOfConfigurations.get(configuration);
return (p != null) ? p : new ArrayList<Plot>();
}
public List<Plot> getPlots() {
return plots;
}
/**
* Returns the list of plots with the given group name. The given group must
* be the URL friendly form of the group name.
*/
public List<Plot> getPlots(String urlGroup,
MatrixConfiguration configuration) {
List<Plot> groupPlots = new ArrayList<Plot>();
List<Plot> p = groupMap.get(urlGroup);
if (p != null) {
for (Plot plot : p) {
if (ObjectUtils.equals(plot.getProject(), configuration)) {
groupPlots.add(plot);
}
}
}
return groupPlots;
}
/**
* Called by Jenkins.
*/
@Override
public Action getProjectAction(AbstractProject<?, ?> project) {
if (project instanceof MatrixConfiguration) {
return new MatrixPlotAction((MatrixConfiguration) project, this);
}
return null;
}
@Override
public boolean prebuild(AbstractBuild<?, ?> build, BuildListener listener) {
if (!plotsOfConfigurations.containsKey((MatrixConfiguration) build
.getProject())) {
for (Plot p : plots) {
Plot plot = new Plot(p.title, p.yaxis, p.group, p.numBuilds,
p.csvFileName, p.style, p.useDescr, p.getKeepRecords(),
p.getExclZero(), p.isLogarithmic(), p.yaxisMinimum, p.yaxisMaximum);
plot.series = p.series;
plot.setProject((MatrixConfiguration) build.getProject());
addPlot(plot);
}
}
return true;
}
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
BuildListener listener) throws IOException, InterruptedException {
if (!(build instanceof MatrixRun)) {
return true;
}
listener.getLogger().println("Recording plot data");
// add the build to each plot
for (Plot plot : plotsOfConfigurations.get(((MatrixRun) build)
.getProject())) {
plot.addBuild(build, listener.getLogger());
}
// misconfigured plots will not fail a build so always return true
return true;
}
/**
* Setup the groupMap upon deserialization.
*/
private Object readResolve() {
setPlots(plots);
return this;
}
@Extension
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
/**
* Called by Jenkins.
*/
@Override
public BuildStepDescriptor<Publisher> getDescriptor() {
return DESCRIPTOR;
}
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {
public DescriptorImpl() {
super(MatrixPlotPublisher.class);
}
public String getDisplayName() {
return Messages.Plot_Publisher_DisplayName();
}
@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return MatrixProject.class.isAssignableFrom(jobType);
}
/**
* Called when the user saves the project configuration.
*/
@Override
public Publisher newInstance(StaplerRequest req, JSONObject formData)
throws FormException {
MatrixPlotPublisher publisher = new MatrixPlotPublisher();
List<Plot> plots = new ArrayList<Plot>();
for (Object data : SeriesFactory.getArray(formData.get("plots"))) {
plots.add(bindPlot((JSONObject) data, req));
}
publisher.setPlots(plots);
return publisher;
}
private static Plot bindPlot(JSONObject data, StaplerRequest req) {
Plot p = req.bindJSON(Plot.class, data);
p.series = SeriesFactory.createSeriesList(data.get("series"), req);
return p;
}
/**
* Checks if the series file is valid.
*/
public FormValidation doCheckSeriesFile(
@AncestorInPath AbstractProject project,
@QueryParameter String value) throws IOException {
return FilePath.validateFileMask(project.getSomeWorkspace(), value);
}
}
}