package hudson.plugins.analysis.core; import java.io.IOException; import java.util.List; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import com.google.common.collect.Lists; import hudson.model.Action; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.plugins.analysis.graph.BuildResultGraph; import hudson.plugins.analysis.graph.DefaultGraphConfigurationView; import hudson.plugins.analysis.graph.DifferenceGraph; import hudson.plugins.analysis.graph.EmptyGraph; import hudson.plugins.analysis.graph.GraphConfiguration; import hudson.plugins.analysis.graph.HealthGraph; import hudson.plugins.analysis.graph.NewVersusFixedGraph; import hudson.plugins.analysis.graph.NullGraph; import hudson.plugins.analysis.graph.PriorityGraph; import hudson.plugins.analysis.graph.UserGraphConfigurationView; import hudson.plugins.analysis.graph.GraphConfigurationView; import hudson.plugins.analysis.graph.TrendDetails; import hudson.util.Graph; /** * A project action displays a link on the side panel of a project. This action * also is responsible to render the historical trend via its associated * 'floatingBox.jelly' view. * * @param <T> * result action type * @author Ulli Hafner */ public abstract class AbstractProjectAction<T extends ResultAction<?>> implements Action { // NOCHECKSTYLE /** Project that owns this action. */ private final AbstractProject<?, ?> project; /** The type of the result action. */ private final Class<T> resultActionType; /** The icon URL of this action: it will be shown as soon as a result is available. */ private final String iconUrl; /** Plug-in URL. */ private final String url; /** Plug-in results URL. */ private final String resultUrl; /** * Creates a new instance of <code>AbstractProjectAction</code>. * * @param project * the project that owns this action * @param resultActionType * the type of the result action * @param plugin * the plug-in that owns this action */ public AbstractProjectAction(final AbstractProject<?, ?> project, final Class<T> resultActionType, final PluginDescriptor plugin) { this.project = project; this.resultActionType = resultActionType; iconUrl = plugin.getIconUrl(); url = plugin.getPluginName(); resultUrl = plugin.getPluginResultUrlName(); } /** * Returns the title of the trend graph. * * @return the title of the trend graph. */ public abstract String getTrendName(); /** * Returns the project. * * @return the project */ public final AbstractProject<?, ?> getProject() { return project; } /** * Returns the graph configuration for this project. * * @param link * not used * @param request * Stapler request * @param response * Stapler response * @return the dynamic result of the analysis (detail page). */ public Object getDynamic(final String link, final StaplerRequest request, final StaplerResponse response) { if ("configureDefaults".equals(link)) { return createDefaultConfiguration(); } else if ("configure".equals(link)) { return createUserConfiguration(request); } else { return null; } } /** * Returns the trend graph details. * * @param request * Stapler request * @return the details */ public Object getTrendDetails(final StaplerRequest request) { return new TrendDetails(getProject(), getTrendGraph(request)); } /** * Returns the trend graph. * * @return the current trend graph */ public Object getTrendGraph() { return getTrendGraph(Stapler.getCurrentRequest()); } /** * Returns the configured trend graph. * * @param request * Stapler request * @return the trend graph */ public Graph getTrendGraph(final StaplerRequest request) { return createUserConfiguration(request).getGraphRenderer(); } /** * Returns whether the trend graph is visible. * * @param request * the request to get the cookie from * @return the graph configuration */ public boolean isTrendVisible(final StaplerRequest request) { return hasValidResults() && createUserConfiguration(request).isVisible(); } /** * Returns whether the trend graph is deactivated. * * @param request * the request to get the cookie from * @return the graph configuration */ public boolean isTrendDeactivated(final StaplerRequest request) { return createUserConfiguration(request).isDeactivated(); } /** * Creates a view to configure the trend graph for the current user. * * @param request * Stapler request * @return a view to configure the trend graph for the current user */ protected GraphConfigurationView createUserConfiguration(final StaplerRequest request) { if (hasValidResults()) { return new UserGraphConfigurationView(createConfiguration(), getProject(), getUrlName(), request.getCookies(), getLastAction()); } else { return new UserGraphConfigurationView(createConfiguration(), getProject(), getUrlName(), request.getCookies()); } } /** * Creates a view to configure the trend graph defaults. * * @return a view to configure the trend graph defaults */ protected GraphConfigurationView createDefaultConfiguration() { if (hasValidResults()) { return new DefaultGraphConfigurationView(createConfiguration(), getProject(), getUrlName(), getLastAction()); } else { return new DefaultGraphConfigurationView(createConfiguration(), getProject(), getUrlName()); } } /** * Creates the graph configuration. * * @return the graph configuration */ private GraphConfiguration createConfiguration() { return createConfiguration(getAvailableGraphs()); } /** * Returns the sorted list of available graphs. * * @return the available graphs */ protected List<BuildResultGraph> getAvailableGraphs() { List<BuildResultGraph> availableGraphs = Lists.newArrayList(); availableGraphs.add(new NewVersusFixedGraph()); availableGraphs.add(new PriorityGraph()); if (hasValidResults()) { availableGraphs.add(new HealthGraph(getLastAction().getHealthDescriptor())); } else { availableGraphs.add(new HealthGraph(new NullHealthDescriptor())); } availableGraphs.add(new DifferenceGraph()); availableGraphs.add(new EmptyGraph()); availableGraphs.add(new NullGraph()); return availableGraphs; } /** * Creates the graph configuration. * * @param availableGraphs * the available graphs * @return the graph configuration. */ protected GraphConfiguration createConfiguration(final List<BuildResultGraph> availableGraphs) { return new GraphConfiguration(availableGraphs); } /** * Returns whether we have enough valid results in order to draw a * meaningful graph. * * @return <code>true</code> if the results are valid in order to draw a * graph */ public final boolean hasValidResults() { AbstractBuild<?, ?> build = getLastFinishedBuild(); if (build != null) { BuildHistory history = new BuildHistory(build, resultActionType); return history.hasPreviousResult(); } return false; } /** * Returns the icon URL for the side-panel in the project screen. If there * is no valid result yet, then <code>null</code> is returned. * * @return the icon URL for the side-panel in the project screen */ public String getIconFileName() { ResultAction<?> lastAction = getLastAction(); if (lastAction != null && lastAction.getResult().hasAnnotations()) { return iconUrl; } return null; } /** {@inheritDoc} */ public final String getUrlName() { return url; } /** * Returns the last valid result action. * * @return the last valid result action, or <code>null</code> if no such action is found */ public ResultAction<?> getLastAction() { AbstractBuild<?, ?> lastBuild = getLastFinishedBuild(); if (lastBuild != null) { return lastBuild.getAction(resultActionType); } return null; } /** * Returns the last finished build. * * @return the last finished build or <code>null</code> if there is no * such build */ public AbstractBuild<?, ?> getLastFinishedBuild() { AbstractBuild<?, ?> lastBuild = project.getLastBuild(); while (lastBuild != null && (lastBuild.isBuilding() || lastBuild.getAction(resultActionType) == null)) { lastBuild = lastBuild.getPreviousBuild(); } return lastBuild; } /** * * Redirects the index page to the last result. * * @param request * Stapler request * @param response * Stapler response * @throws IOException * in case of an error */ public void doIndex(final StaplerRequest request, final StaplerResponse response) throws IOException { AbstractBuild<?, ?> build = getLastFinishedBuild(); if (build != null) { response.sendRedirect2(String.format("../%d/%s", build.getNumber(), resultUrl)); } } }