package jenkins.security.s2m; import hudson.CopyOnWrite; import hudson.util.TextFile; import jenkins.model.Jenkins; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.util.Collection; /** * Abstraction of a line-by-line configuration text file that gets parsed into some in-memory data form. * * @author Kohsuke Kawaguchi */ abstract class ConfigFile<T,COL extends Collection<T>> extends TextFile { @CopyOnWrite protected volatile COL parsed; public ConfigFile(File file) { super(file); } protected abstract COL create(); protected abstract COL readOnly(COL base); public synchronized void load() { COL result = create(); if (exists()) { for (String line : lines()) { if (line.startsWith("#")) continue; // comment T r = parse(line); if (r != null) result.add(r); } } parsed = readOnly(result); } /** * Goes through the parser with the given text to make sure it doesn't yield any error. */ public void parseTest(String candidate) { try { BufferedReader r = new BufferedReader(new StringReader(candidate)); String line; while ((line=r.readLine())!=null) { if (line.startsWith("#")) continue; // comment parse(line); } } catch (IOException e) { throw new IllegalArgumentException(e); // can't happen but just in case } } protected abstract T parse(String line); public synchronized void set(String newContent) throws IOException { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); write(newContent); load(); } public synchronized void append(String additional) throws IOException { String s = read(); if (!s.endsWith("\n")) s += "\n"; s+= additional; set(s); } public COL get() { // load upon the first use if (parsed==null) { synchronized (this) { if (parsed==null) load(); } } return parsed; } }