package hudson.plugins.cigame.model; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; import com.google.common.base.Predicates; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; import com.google.common.collect.Sets; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import hudson.model.Run; import org.kohsuke.stapler.export.Exported; import javax.annotation.Nonnull; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.SortedSet; public class ScoreHistoryEntry { /* * The runs that are the cause for us giving you the award. */ private SortedSet<Run<?,?>> awardingRuns; /* * The score that has been awarded. */ private double awardedScore; public ScoreHistoryEntry() { } public ScoreHistoryEntry(Collection<? extends Run<?,?>> awardingRuns, double awardedScore) { this.setAwardingRuns(awardingRuns); this.awardedScore = awardedScore; } public Set<Run<?,?>> getAwardingRuns() { return awardingRuns; } public void setAwardingRuns(Collection<? extends Run<?,?>> awardingRuns) { this.awardingRuns = Sets.newTreeSet(Ordering.natural().reverse()); this.awardingRuns.addAll(Collections2.filter(awardingRuns, Predicates.notNull())); } public double getAwardedScore() { return awardedScore; } @Exported public String getAwardedScoreString() { if(awardedScore > 0) { return "+" + String.valueOf(awardedScore); } else { return String.valueOf(awardedScore); } } public void setAwardedScore(double awardedScore) { this.awardedScore = awardedScore; } public static ScoreHistoryEntry fromScoreAward(@Nonnull List<? extends Run<?,?>> accountableBuilds, double accountedScore) { return new ScoreHistoryEntry(accountableBuilds, accountedScore); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ScoreHistoryEntry that = (ScoreHistoryEntry) o; if (Double.compare(that.awardedScore, awardedScore) != 0) return false; return Objects.equal(this.awardingRuns, that.awardingRuns); } @Override public int hashCode() { return Objects.hashCode(this.awardedScore, this.awardingRuns); } @Override public String toString() { return Objects.toStringHelper(this) .add("awardedScore", getAwardedScoreString()) .add("awardingRuns", awardingRuns) .toString(); } @SuppressWarnings("unused") public static final class ConverterImpl implements Converter { private RunCreationStrategy runCreationStrategy; public ConverterImpl() { this(new DefaultRunCreationStrategy()); } public ConverterImpl(RunCreationStrategy runCreationStrategy) { this.runCreationStrategy = runCreationStrategy; } public boolean canConvert(Class type) { return type==ScoreHistoryEntry.class; } public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { ScoreHistoryEntry entry = (ScoreHistoryEntry) source; writer.startNode("score"); writer.setValue(String.valueOf(entry.getAwardedScore())); writer.endNode(); writer.startNode("accountableRuns"); for (Run run : entry.awardingRuns) { writer.startNode("run"); writer.setValue(run.getExternalizableId()); writer.endNode(); } writer.endNode(); } public Object unmarshal(HierarchicalStreamReader reader, final UnmarshallingContext context) { double score; reader.moveDown(); score = Double.valueOf(reader.getValue()); reader.moveUp(); reader.moveDown(); List<Run<?,?>> awardingRuns = Lists.newArrayList(); while(reader.hasMoreChildren()) { reader.moveDown(); String externalId = reader.getValue(); awardingRuns.add(this.runCreationStrategy.createRunFromExternalId(externalId)); reader.moveUp(); } reader.moveUp(); return ScoreHistoryEntry.fromScoreAward(awardingRuns, score); } } @VisibleForTesting protected Run<?, ?> runFromExternalId(String externalId) { return Run.fromExternalizableId(externalId); } public interface RunCreationStrategy { Run<?,?> createRunFromExternalId(String externalId); } public static class DefaultRunCreationStrategy implements RunCreationStrategy { public Run<?, ?> createRunFromExternalId(String externalId) { return Run.fromExternalizableId(externalId); } } }