All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.plugins.analysis.graph.GraphConfiguration Maven / Gradle / Ivy

The newest version!
package hudson.plugins.analysis.graph;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONObject;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import hudson.model.AbstractProject;

import hudson.util.FormValidation;

/**
 * Configuration properties of a trend graph.
 */
public class GraphConfiguration  {
    private static final int MAXIMUM_SIZE = 2000;
    private static final int MINIMUM_SIZE = 25;

    private static final boolean DEFAULT_USE_BUILD_DATE = false;
    private static final int DEFAULT_BUILD_COUNT = 50;
    private static final int DEFAULT_DAY_COUNT = 30;
    private static final int DEFAULT_WIDTH = 500;
    private static final int DEFAULT_HEIGHT = 200;
    private static final BuildResultGraph DEFAULT_GRAPH = new PriorityGraph();

    /** Separator of cookie values. */
    protected static final String SEPARATOR = "!";

    /** The height of the trend graph. */
    private int height;
    /** The width of the trend graph. */
    private int width;
    /** The type of the graph. */
    private BuildResultGraph graphType;
    /** The number of builds to consider. */
    private int buildCount;
    /** The number of days to consider. */
    private int dayCount;
    /** Determines if the build date or the build number should be used as domain. */
    private boolean useBuildDate;

    /** Maps graph ID's to graphs. */
    private final Map graphId2Graph = Maps.newHashMap();
    /** Available graphs in the order to display. */
    private final List availableGraphs;

    /**
     * Creates a configuration for a deactivated graph.
     *
     * @return a configuration for a deactivated graph
     */
    public static GraphConfiguration createDeactivated() {
        return new GraphConfiguration(new NullGraph());
    }

    /**
     * Creates a default configuration.
     *
     * @return a default configuration
     */
    public static GraphConfiguration createDefault() {
        return new GraphConfiguration(DEFAULT_GRAPH);
    }

    /**
     * Creates a new instance of {@link GraphConfiguration}.
     *
     * @param availableGraphs
     *            the available build graphs
     */
    public GraphConfiguration(final Collection availableGraphs) {
        this.availableGraphs = ImmutableList.copyOf(availableGraphs);
        for (BuildResultGraph graph : availableGraphs) {
            graphId2Graph.put(graph.getId(), graph);
        }
    }

    /**
     * Creates a new instance of {@link GraphConfiguration}.
     *
     * @param availableGraphs
     *            the available build graphs
     */
    public GraphConfiguration(final BuildResultGraph... availableGraphs) {
        this(Arrays.asList(availableGraphs));
    }

    /**
     * Creates a new instance of {@link GraphConfiguration}.
     *
     * @param graph
     *            the graph to use
     */
    public GraphConfiguration(final BuildResultGraph graph) {
        reset();

        availableGraphs = Lists.newArrayList();
        graphType = graph;
        availableGraphs.add(graphType);
    }

    /**
     * Parses the provided string and initializes the members. If the string is
     * not in the expected format, then false is returned and the
     * members are reset to their default values.
     *
     * @param value
     *            the initialization value stored in the format
     *            width!height!buildCount!dayCount!graphType
     * @return true is the initialization was successful,
     *         false otherwise
     * @see #serializeToString()
     */
    public boolean initializeFrom(final String value) {
        return resetIfInvalid(intializeFromStringValue(value));
    }

    /**
     * Initializes this configuration with the specified values.
     *
     * @param width
     *            the width of the graph
     * @param height
     *            the height of the graph
     * @return true is the initialization was successful,
     *         false otherwise
     */
    public boolean initializeFrom(final int width, final int height) { // NOCHECKSTYLE
        return initializeFrom(width, height, 0);
    }

    /**
     * Initializes this configuration with the specified values.
     *
     * @param width
     *            the width of the graph
     * @param height
     *            the height of the graph
     * @param dayCount
     *            the number of days to build the graph for
     * @return true is the initialization was successful,
     *         false otherwise
     */
    public boolean initializeFrom(final int width, final int height, final int dayCount) { // NOCHECKSTYLE
        this.width = width;
        this.height = height;
        this.dayCount = dayCount;
        buildCount = 0;
        useBuildDate = true;

        return resetIfInvalid(isValid(width, height, buildCount, dayCount, graphType));
    }

    /**
     * Initializes this configuration with the specified values.
     *
     * @param width
     *            the width of the graph
     * @param height
     *            the height of the graph
     * @param dayCountString
     *            the number of days to build the graph for
     * @return true is the initialization was successful,
     *         false otherwise
     */
    public boolean initializeFrom(final String width, final String height, final String dayCountString) { // NOCHECKSTYLE
        try {
            if (StringUtils.isBlank(dayCountString)) {
                dayCount = 0;
            }
            else {
                dayCount = Integer.parseInt(dayCountString);
            }

            return initializeFrom(Integer.parseInt(width), Integer.parseInt(height), dayCount);
        }
        catch (NumberFormatException exception) {
            reset();

            return false;
        }
    }

    /**
     * Resets this configuration if the result is false.
     *
     * @param isSuccessful
     *            the result of the conversion
     * @return the result
     */
    private boolean resetIfInvalid(final boolean isSuccessful) {
        if (!isSuccessful) {
            reset();
        }

        return isSuccessful;
    }

    /**
     * See {@link #initializeFrom(String)}.
     *
     * @param value the initialization value
     * @return true is the initialization was successful,
     *         false otherwise
     */
    // CHECKSTYLE:CONSTANTS-OFF
    private boolean intializeFromStringValue(final String value) {
        if (StringUtils.isBlank(value)) {
            return false;
        }

        String[] values = StringUtils.split(value, SEPARATOR);
        if (values.length < 6) {
            return false;
        }

        try {
            width = Integer.parseInt(values[0]);
            height = Integer.parseInt(values[1]);
            buildCount = Integer.parseInt(values[2]);
            dayCount = Integer.parseInt(values[3]);
            graphType = graphId2Graph.get(values[4]);
            if ("0".equals(values[5])) {
                useBuildDate = false;
            }
            else if ("1".equals(values[5])) {
                useBuildDate = true;
            }
            else {
                return false;
            }
        }
        catch (NumberFormatException exception) {
            return false;
        }
        catch (IllegalArgumentException exception) {
            return false;
        }

        String[] localConfiguration = new String[values.length - 6];
        System.arraycopy(values, 6, localConfiguration, 0, values.length - 6);
        boolean isLocalValid = initializeLocal(localConfiguration);

        return isLocalValid && isValid(width, height, buildCount, dayCount, graphType);
    }
    // CHECKSTYLE:CONSTANTS-ON

    /**
     * Parses the provided array of string values and initializes the members of
     * the local configuration. If the values are not in the expected format,
     * then false is returned and the members are reset to their
     * default values.
     * 

The provided default implementation simply returns true. *

* * @param localConfiguration * the initialization values * @return true is the initialization was successful, * false otherwise * @see #serializeToString() */ protected boolean initializeLocal(final String[] localConfiguration) { return true; } /** * Parses the provided JSON object and initializes the members. If the JSON * object is not in the expected format, then false is returned * and the members are reset to their default values. * * @param value * the initialization value * @return true is the initialization was successful, * false otherwise * @see #serializeToString() */ public boolean initializeFrom(final JSONObject value) { return resetIfInvalid(initializeFromJsonObject(value)); } /** * See {@link #initializeFrom(JSONObject)}. * * @param value the initialization value * @return true is the initialization was successful, * false otherwise */ private boolean initializeFromJsonObject(final JSONObject value) { width = value.getInt("width"); height = value.getInt("height"); String buildCountString = value.getString("buildCountString"); buildCount = 0; if (StringUtils.isNotBlank(buildCountString)) { buildCount = value.getInt("buildCountString"); } String dayCountString = value.getString("dayCountString"); dayCount = 0; if (StringUtils.isNotBlank(dayCountString)) { dayCount = value.getInt("dayCountString"); } String grapyTypeString = value.getString("graphType"); graphType = graphId2Graph.get(grapyTypeString); useBuildDate = value.getBoolean("useBuildDateAsDomain"); boolean isLocalValid = initializeLocal(value); return isLocalValid && isValid(width, height, buildCount, dayCount, graphType); } /** * Parses the provided JSON object and initializes the members of * the local configuration. If the values are not in the expected format, * then false is returned and the members are reset to their * default values. *

The provided default implementation simply returns true. *

* * @param localConfiguration * the initialization values * @return true is the initialization was successful, * false otherwise * @see #serializeToString() */ protected boolean initializeLocal(final JSONObject localConfiguration) { return true; } /** * Reads the specified file, parses the content and initializes the members. * If the string is not in the expected format of the file could not be * read, then false is returned and the members are reset to * their default values. * * @param file * the file with the initialization values * @return true is the initialization was successful, * false otherwise * @see #serializeToString() */ public boolean initializeFromFile(final File file) { return initializeFrom(readFromDefaultsFile(file)); } /** * Creates a file with for the default values. * * @param project * the project used as directory for the file * @param pluginName * the name of the plug-in * @return the created file */ protected File createDefaultsFile(final AbstractProject project, final String pluginName) { return new File(project.getRootDir(), pluginName + ".txt"); } /** * Returns the build count as a string. If no build count is defined, then an * empty string is returned. * * @return the day count string */ public String getBuildCountString() { if (isBuildCountDefined()) { return String.valueOf(getBuildCount()); } else { return StringUtils.EMPTY; } } /** * Returns the day count as a string. If no day count is defined, then an * empty string is returned. * * @return the day count string */ public String getDayCountString() { if (isDayCountDefined()) { return String.valueOf(getDayCount()); } else { return StringUtils.EMPTY; } } /** * Reads the default values from file. * * @param defaultsFile * the file with the default values * @return the default values from file. */ private String readFromDefaultsFile(final File defaultsFile) { String defaultValue = StringUtils.EMPTY; FileInputStream input = null; try { input = new FileInputStream(defaultsFile); defaultValue = IOUtils.toString(input); } catch (IOException exception) { // ignore } finally { IOUtils.closeQuietly(input); } return defaultValue; } /** * Resets the graph configuration to the default values. */ private void reset() { height = DEFAULT_HEIGHT; width = DEFAULT_WIDTH; buildCount = DEFAULT_BUILD_COUNT; dayCount = DEFAULT_DAY_COUNT; graphType = DEFAULT_GRAPH; useBuildDate = DEFAULT_USE_BUILD_DATE; } /** * Serializes the values of this configuration. * * @return serialized configuration * @see #initializeFrom(String) */ public String serializeToString() { return width + SEPARATOR + height + SEPARATOR + buildCount + SEPARATOR + dayCount + SEPARATOR + graphType.getId() + SEPARATOR + serializeBoolean(useBuildDate); } /** * Serializes a boolean. * * @param value the value * @return serialized value */ protected String serializeBoolean(final boolean value) { if (value) { return "1"; } else { return "0"; } } /** * Returns whether the configuration parameters are valid. * * @param newWidth * the new width * @param newHeight * the new height * @param newBuildCount * the new build count * @param newDayCount * the new day count * @param newGraphType * the new graph type * @return true if the configuration parameters are valid, * false otherwise. */ //CHECKSTYLE:OFF protected static boolean isValid(final int newWidth, final int newHeight, final int newBuildCount, final int newDayCount, final BuildResultGraph newGraphType) { return isValidWidth(newWidth) && isValidHeight(newHeight) && newGraphType != null && newDayCount >= 0 && isValidBuildCount(newBuildCount); } //CHECKSTYLE:ON /** * Returns if the build count is valid. * * @param newBuildCount * the new build count * @return true if the build count is valid. */ protected static boolean isValidBuildCount(final int newBuildCount) { return newBuildCount == 0 || newBuildCount > 1; } /** * Returns whether the width is valid. * * @param newWidth * the new width * @return true if the width is valid, false * otherwise */ protected static boolean isValidWidth(final int newWidth) { return newWidth > MINIMUM_SIZE && newWidth < MAXIMUM_SIZE; } /** * Returns whether the width is valid. * * @param newHeight * the new height * @return true if the width is valid, false * otherwise */ protected static boolean isValidHeight(final int newHeight) { return newHeight > MINIMUM_SIZE && newHeight < MAXIMUM_SIZE; } /** * Returns the height. * * @return the height */ public int getHeight() { return height; } /** * Returns the width. * * @return the width */ public int getWidth() { return width; } /** * Returns whether the build date or the build number should be used as domain. * * @return the build date or the build number should be used as domain */ public boolean useBuildDateAsDomain() { return useBuildDate; } /** * Returns the number of builds to consider. * * @return the number of builds to consider */ public int getBuildCount() { return buildCount; } /** * Returns whether a valid build count is defined. * * @return true if there is a valid build count is defined, * false otherwise */ public boolean isBuildCountDefined() { return buildCount > 1; } /** * Returns the number of days to consider. * * @return the number of days to consider */ public int getDayCount() { return dayCount; } /** * Returns whether a valid day count is defined. * * @return true if there is a valid day count is defined, * false otherwise */ public boolean isDayCountDefined() { return dayCount > 0; } /** * Returns the type of the graph. * * @return the type */ public BuildResultGraph getGraphType() { return graphType; } /** * Returns whether this instance is initialized with its default values. * * @return true if this instance is initialized with its default values. */ // CHECKSTYLE:OFF public boolean isDefault() { return width == DEFAULT_WIDTH && height == DEFAULT_HEIGHT && graphType == DEFAULT_GRAPH // NOPMD && buildCount == DEFAULT_BUILD_COUNT && dayCount == DEFAULT_DAY_COUNT && useBuildDate == DEFAULT_USE_BUILD_DATE; } // CHECKSTYLE:ON /** * Returns whether the trend graph is visible or not. * * @return true, if the trend graph is visible, false otherwise */ public boolean isVisible() { return graphType.isVisible(); } /** {@inheritDoc} */ @Override public String toString() { return "type: " + graphType + ", size: " + width + "x" + height + ", # builds " + buildCount + ", # days " + dayCount + ", useBuildDate:" + useBuildDate; } /** * Returns the registered graphs. * * @return the registered graphs */ public Collection getRegisteredGraphs() { return availableGraphs; } /** * Returns the graph with the specified ID. * * @param graphId * the graph ID * @return the graph with the specified ID. If the graph is not found, then * {@link #DEFAULT_GRAPH} is returned. */ public BuildResultGraph getGraph(final String graphId) { if (graphId2Graph.containsKey(graphId)) { return graphId2Graph.get(graphId); } else { return DEFAULT_GRAPH; } } /** * Performs on-the-fly validation on the trend graph height. * * @param height * the height * @return the form validation */ public static FormValidation checkHeight(final String height) { try { if (isValidHeight(Integer.valueOf(height))) { return FormValidation.ok(); } } catch (NumberFormatException f) { // ignore } return FormValidation.error("Invalid height value: " + height); } /** {@inheritDoc} */ @Override // CHECKSTYLE:OFF public int hashCode() { int prime = 31; int result = 1; result = prime * result + buildCount; result = prime * result + dayCount; result = prime * result + ((graphType == null) ? 0 : graphType.getId().hashCode()); result = prime * result + height; result = prime * result + (useBuildDate ? 1231 : 1237); result = prime * result + width; return result; } // CHECKSTYLE:ON /** {@inheritDoc} */ @Override // NOCHECKSTYLE @SuppressWarnings("PMD") // CHECKSTYLE:OFF public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } GraphConfiguration other = (GraphConfiguration)obj; if (buildCount != other.buildCount) { return false; } if (dayCount != other.dayCount) { return false; } if (graphType == null) { if (other.graphType != null) { return false; } } else if (!graphType.getId().equals(other.graphType.getId())) { return false; } if (height != other.height) { return false; } if (useBuildDate != other.useBuildDate) { return false; } if (width != other.width) { return false; } return true; } // CHECKSTYLE:ON }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy