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

hudson.model.RunMap Maven / Gradle / Ivy

package hudson.model;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Logger;
import java.text.SimpleDateFormat;
import java.text.ParseException;

/**
 * {@link Map} from build number to {@link Run}.
 *
 * 

* This class is multi-thread safe by using copy-on-write technique, * and it also updates the bi-directional links within {@link Run} * accordingly. * * @author Kohsuke Kawaguchi */ public final class RunMap> extends AbstractMap implements SortedMap { // copy-on-write map private transient volatile SortedMap builds = new TreeMap(COMPARATOR); /** * Read-only view of this map. */ private final SortedMap view = Collections.unmodifiableSortedMap(this); public Set> entrySet() { // since the map is copy-on-write, make sure no one modifies it return Collections.unmodifiableSet(builds.entrySet()); } public synchronized R put(R value) { return put(value.getNumber(),value); } public synchronized R put(Integer key, R value) { // copy-on-write update TreeMap m = new TreeMap(builds); R r = update(m, key, value); this.builds = m; return r; } public synchronized void putAll(Map rhs) { // copy-on-write update TreeMap m = new TreeMap(builds); for (Map.Entry e : rhs.entrySet()) update(m, e.getKey(), e.getValue()); this.builds = m; } private R update(TreeMap m, Integer key, R value) { // things are bit tricky because this map is order so that the newest one comes first, // yet 'nextBuild' refers to the newer build. R first = m.isEmpty() ? null : m.get(m.firstKey()); R r = m.put(key, value); SortedMap head = m.headMap(key); if(!head.isEmpty()) { R prev = m.get(head.lastKey()); value.previousBuild = prev.previousBuild; value.nextBuild = prev; if(value.previousBuild!=null) value.previousBuild.nextBuild = value; prev.previousBuild=value; } else { value.previousBuild = first; value.nextBuild = null; if(first!=null) first.nextBuild = value; } return r; } public synchronized boolean remove(R run) { if(run.nextBuild!=null) run.nextBuild.previousBuild = run.previousBuild; if(run.previousBuild!=null) run.previousBuild.nextBuild = run.nextBuild; // copy-on-write update TreeMap m = new TreeMap(builds); R r = m.remove(run.getNumber()); this.builds = m; return r!=null; } public synchronized void reset(TreeMap builds) { this.builds = new TreeMap(COMPARATOR); putAll(builds); } /** * Gets the read-only view of this map. */ public SortedMap getView() { return view; } // // SortedMap delegation // public Comparator comparator() { return builds.comparator(); } public SortedMap subMap(Integer fromKey, Integer toKey) { return builds.subMap(fromKey, toKey); } public SortedMap headMap(Integer toKey) { return builds.headMap(toKey); } public SortedMap tailMap(Integer fromKey) { return builds.tailMap(fromKey); } public Integer firstKey() { return builds.firstKey(); } public Integer lastKey() { return builds.lastKey(); } public static final Comparator COMPARATOR = new Comparator() { public int compare(Comparable o1, Comparable o2) { return -o1.compareTo(o2); } }; /** * {@link Run} factory. */ public interface Constructor> { R create(File dir) throws IOException; } /** * Fills in {@link RunMap} by loading build records from the file system. * * @param job * Job that owns this map. * @param cons * Used to create new instance of {@link Run}. */ public synchronized void load(Job job, Constructor cons) { final SimpleDateFormat formatter = Run.ID_FORMATTER.get(); TreeMap builds = new TreeMap(RunMap.COMPARATOR); File buildDir = job.getBuildDir(); buildDir.mkdirs(); String[] buildDirs = buildDir.list(new FilenameFilter() { public boolean accept(File dir, String name) { // HUDSON-1461 sometimes create bogus data directories with impossible dates, such as year 0, April 31st, // or August 0th. Date object doesn't roundtrip those, so we eventually fail to load this data. // Don't even bother trying. if (!isCorrectDate(name)) { LOGGER.fine("Skipping "+new File(dir,name)); return false; } return !name.startsWith("0000") && new File(dir,name).isDirectory(); } private boolean isCorrectDate(String name) { try { if(formatter.format(formatter.parse(name)).equals(name)) return true; } catch (ParseException e) { // fall through } return false; } }); for( String build : buildDirs ) { File d = new File(buildDir,build); if(new File(d,"build.xml").exists()) { // if the build result file isn't in the directory, ignore it. try { R b = cons.create(d); builds.put( b.getNumber(), b ); } catch (IOException e) { e.printStackTrace(); } catch (InstantiationError e) { e.printStackTrace(); } } } reset(builds); } private static final Logger LOGGER = Logger.getLogger(RunMap.class.getName()); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy