diff --git a/core/src/main/java/jenkins/util/io/FileBoolean.java b/core/src/main/java/jenkins/util/io/FileBoolean.java new file mode 100644 index 000000000000..3800ae287f7b --- /dev/null +++ b/core/src/main/java/jenkins/util/io/FileBoolean.java @@ -0,0 +1,61 @@ +package jenkins.util.io; + +import jenkins.model.Jenkins; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Uses a presence/absence of a file as a persisted boolean storage. + * + *

+ * This is convenient when you need to store just a few bits of infrequently accessed information + * as you can forget the explicit persistence of it. This class masks I/O problem, so if the persistence + * fails, you'll get no error report. + * + * @author Kohsuke Kawaguchi + * @since 1.498 + */ +public class FileBoolean { + private final File file; + + public FileBoolean(File file) { + this.file = file; + } + + public FileBoolean(Class owner, String name) { + this(new File(Jenkins.getInstance().getRootDir(),owner.getName().replace('$','.')+'/'+name)); + } + + /** + * Gets the current state. True if the file exists, false if it doesn't. + */ + public boolean get() { + return file.exists(); + } + + public boolean isOn() { return get(); } + public boolean isOff() { return !get(); } + + public void set(boolean b) { + if (b) on(); else off(); + } + + public void on() { + try { + file.getParentFile().mkdirs(); + new FileOutputStream(file).close(); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Failed to touch "+file); + } + } + + public void off() { + file.delete(); + } + + private static final Logger LOGGER = Logger.getLogger(FileBoolean.class.getName()); +} diff --git a/core/src/main/java/jenkins/util/xstream/XStreamDOM.java b/core/src/main/java/jenkins/util/xstream/XStreamDOM.java index eef29647f495..e5011d5662cc 100644 --- a/core/src/main/java/jenkins/util/xstream/XStreamDOM.java +++ b/core/src/main/java/jenkins/util/xstream/XStreamDOM.java @@ -35,10 +35,21 @@ import com.thoughtworks.xstream.io.xml.AbstractXmlWriter; import com.thoughtworks.xstream.io.xml.DocumentReader; import com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer; +import com.thoughtworks.xstream.io.xml.XppDriver; import hudson.Util; import hudson.util.VariableResolver; +import hudson.util.XStream2; +import org.apache.commons.io.IOUtils; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -61,6 +72,16 @@ * The reverse operation is {@link #from(XStream, Object)} method, which marshals an object * into {@link XStreamDOM}. * + *

+ * You can also use this class to parse an entire XML document into a DOM like tree with + * {@link #from(HierarchicalStreamReader)} and {@link #writeTo(HierarchicalStreamWriter)}. + * These two methods support variants that accept other forms. + *

+ * Whereas the above methods read from and write to {@link HierarchicalStreamReader} and, + * {@link HierarchicalStreamWriter}, we can also create {@link HierarchicalStreamReader} + * that read from DOM and {@link HierarchicalStreamWriter} that writes to DOM. See + * {@link #newReader()} and {@link #newWriter()} for those operations. + * * @author Kohsuke Kawaguchi * @since 1.473 */ @@ -184,6 +205,21 @@ public static WriterImpl newWriter() { return new WriterImpl(); } + /** + * Writes this {@link XStreamDOM} into {@link OutputStream}. + */ + public void writeTo(OutputStream os) { + writeTo(new XppDriver().createWriter(os)); + } + + public void writeTo(Writer w) { + writeTo(new XppDriver().createWriter(w)); + } + + public void writeTo(HierarchicalStreamWriter w) { + new ConverterImpl().marshal(this,w,null); + } + /** * Marshals the given object with the given XStream into {@link XStreamDOM} and return it. */ @@ -193,6 +229,25 @@ public static XStreamDOM from(XStream xs, Object obj) { return w.getOutput(); } + public static XStreamDOM from(InputStream in) { + return from(new XppDriver().createReader(in)); + } + + public static XStreamDOM from(Reader in) { + return from(new XppDriver().createReader(in)); + } + + public static XStreamDOM from(HierarchicalStreamReader in) { + return new ConverterImpl().unmarshalElement(in, null); + } + + public Map getAttributeMap() { + Map r = new HashMap(); + for (int i=0; i + + abc +