package jenkins; import hudson.Extension; import hudson.FilePath; import hudson.remoting.ChannelProperty; import java.io.File; import java.util.Collections; import java.util.concurrent.CopyOnWriteArrayList; /** * Maintains a bundle of {@link FilePathFilter} and implement a hook that broadcasts to all the filters. * * Accessible as channel property. * * @author Kohsuke Kawaguchi * @see FilePath * @since 1.THU */ class FilePathFilterAggregator extends FilePathFilter { private final CopyOnWriteArrayList<Entry> all = new CopyOnWriteArrayList<Entry>(); private class Entry implements Comparable<Entry> { final FilePathFilter filter; final double ordinal; private Entry(FilePathFilter filter, double ordinal) { this.filter = filter; this.ordinal = ordinal; } @Override public int compareTo(Entry that) { double d = this.ordinal - that.ordinal; if (d<0) return -1; if (d>0) return 1; // to create predictable order that doesn't depend on the insertion order, use class name // to break a tie return this.filter.getClass().getName().compareTo(that.filter.getClass().getName()); } } public final void add(FilePathFilter f) { add(f, DEFAULT_ORDINAL); } /** * * @param ordinal * Crude ordering control among {@link FilePathFilter} ala {@link Extension#ordinal()}. * A filter with a bigger value will get precedence. Defaults to 0. */ public void add(FilePathFilter f, double ordinal) { Entry e = new Entry(f, ordinal); int i = Collections.binarySearch(all, e, Collections.reverseOrder()); if (i>=0) all.add(i,e); else all.add(-i-1,e); } public void remove(FilePathFilter f) { for (Entry e : all) { if (e.filter==f) all.remove(e); } } /** * If no filter cares, what to do? */ protected boolean defaultAction() throws SecurityException { return false; } @Override public boolean read(File f) throws SecurityException { for (Entry e : all) { if (e.filter.read(f)) return true; } return defaultAction(); } @Override public boolean mkdirs(File f) throws SecurityException { for (Entry e : all) { if (e.filter.mkdirs(f)) return true; } return defaultAction(); } @Override public boolean write(File f) throws SecurityException { for (Entry e : all) { if (e.filter.write(f)) return true; } return defaultAction(); } @Override public boolean symlink(File f) throws SecurityException { for (Entry e : all) { if (e.filter.symlink(f)) return true; } return defaultAction(); } @Override public boolean create(File f) throws SecurityException { for (Entry e : all) { if (e.filter.create(f)) return true; } return defaultAction(); } @Override public boolean delete(File f) throws SecurityException { for (Entry e : all) { if (e.filter.delete(f)) return true; } return defaultAction(); } @Override public boolean stat(File f) throws SecurityException { for (Entry e : all) { if (e.filter.stat(f)) return true; } return defaultAction(); } @Override public String toString() { return "FilePathFilterAggregator" + all; } static final ChannelProperty<FilePathFilterAggregator> KEY = new ChannelProperty<FilePathFilterAggregator>(FilePathFilterAggregator.class, "FilePathFilters"); public static final int DEFAULT_ORDINAL = 0; }