/******************************************************************************* * * Copyright (c) 2004-2009 Oracle Corporation. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * Kohsuke Kawaguchi * * *******************************************************************************/ package hudson.matrix; import hudson.DescriptorExtensionList; import hudson.ExtensionPoint; import hudson.Util; import hudson.model.AbstractDescribableImpl; import hudson.model.Hudson; import hudson.util.QuotedStringTokenizer; import org.apache.commons.collections.CollectionUtils; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.DataBoundConstructor; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Arrays; import java.util.Map; /** * Configuration axis. * * <p> This class represents a single dimension of the configuration matrix. For * example, the JAX-WS RI test configuration might include one axis * "container={glassfish,tomcat,jetty}" and another axis * "stax={sjsxp,woodstox}", and so on. * * @author Kohsuke Kawaguchi */ public class Axis extends AbstractDescribableImpl<Axis> implements Comparable<Axis>, Iterable<String>, ExtensionPoint { /** * Name of this axis. Used as a variable name. * * @deprecated as of 1.373 Use {@link #getName()} */ public final String name; /** * Possible values for this axis. * * @deprecated as of 1.373 Use {@link #getValues()} */ //TODO: review and check whether we can do it private public final List<String> values; public Axis(String name, List<String> values) { this.name = name; this.values = new ArrayList<String>(values); if (values.isEmpty()) { throw new IllegalArgumentException(); // bug in the code } } public Axis(String name, String... values) { this(name, Arrays.asList(values)); } /** * Used to build {@link Axis} from form. * * Axis with empty values need to be removed later. */ @DataBoundConstructor public Axis(String name, String valueString) { this.name = name; this.values = new ArrayList<String>(Arrays.asList(Util.tokenize(valueString))); } /** * Returns true if this axis is a system-reserved axis that * <strike>has</strike> used to have af special treatment. * * @deprecated as of 1.373 System vs user difference are generalized into * extension point. */ public boolean isSystem() { return false; } public Iterator<String> iterator() { return getValues().iterator(); } public int size() { return getValues().size(); } public String value(int index) { return getValues().get(index); } /** * The inverse of {@link #value(int)}. */ public int indexOf(String value) { return values.indexOf(value); } /** * Axis is fully ordered so that we can convert between a list of axis and a * string unambiguously. */ public int compareTo(Axis that) { return this.name.compareTo(that.name); } /** * Name of this axis. Used as a variable name. */ public String getName() { return name; } /** * Possible values for this axis. */ public List<String> getValues() { return Collections.unmodifiableList(values); } @Override public AxisDescriptor getDescriptor() { return (AxisDescriptor) super.getDescriptor(); } @Override public String toString() { return new StringBuilder().append(name).append("={").append(Util.join(values, ",")).append('}').toString(); } /** * Used for generating the config UI. If the axis is big and occupies a lot * of space, use newline for separator to display multi-line text. */ public String getValueString() { int len = 0; for (String value : values) { len += value.length(); } char delim = len > 30 ? '\n' : ' '; // Build string connected with delimiter, quoting as needed StringBuilder buf = new StringBuilder(len + values.size() * 3); for (String value : values) { buf.append(delim).append(QuotedStringTokenizer.quote(value, "")); } return buf.substring(1); } /** * Parses the submitted form (where possible values are presented as a list * of checkboxes) and creates an axis */ public static Axis parsePrefixed(StaplerRequest req, String name) { List<String> values = new ArrayList<String>(); String prefix = name + '.'; Enumeration e = req.getParameterNames(); while (e.hasMoreElements()) { String paramName = (String) e.nextElement(); if (paramName.startsWith(prefix)) { values.add(paramName.substring(prefix.length())); } } if (values.isEmpty()) { return null; } return new Axis(name, values); } /** * Previously we used to persist {@link Axis}, but now those are divided * into subtypes. So upon deserialization, resolve to the proper type. */ public Object readResolve() { if (getClass() != Axis.class) { return this; } if (getName().equals("jdk")) { return new JDKAxis(getValues()); } if (getName().equals("label")) { return new LabelAxis(getName(), getValues()); } return new TextAxis(getName(), getValues()); } /** * Returns all the registered {@link AxisDescriptor}s. */ public static DescriptorExtensionList<Axis, AxisDescriptor> all() { return Hudson.getInstance().<Axis, AxisDescriptor>getDescriptorList(Axis.class); } /** * Converts the selected value (which is among {@link #values}) and adds * that to the given map, which serves as the build variables. */ public void addBuildVariable(String value, Map<String, String> map) { map.put(name, value); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Axis axis = (Axis) o; if (name != null ? !name.equals(axis.name) : axis.name != null) { return false; } if (values != null ? !CollectionUtils.isEqualCollection(values, axis.values) : axis.values != null) { return false; } return true; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (values != null ? values.hashCode() : 0); return result; } }