> {
return clazz.isInstance(instance);
}
- /**
- * Returns the data store that can be used to store configuration info.
- *
- *
- * The data store is local to each {@link Descriptor}.
- *
- * @return
- * never return null.
- */
- protected synchronized Map getProperties() {
- if(properties==null)
- properties = load();
- return properties;
- }
-
/**
* Invoked when the global configuration page is submitted.
*
@@ -132,27 +125,39 @@ public abstract class Descriptor> {
* Saves the configuration info to the disk.
*/
protected synchronized void save() {
- if(properties!=null)
- try {
- getConfigFile().write(properties);
- } catch (IOException e) {
- e.printStackTrace();
- }
+ try {
+ getConfigFile().write(this);
+ } catch (IOException e) {
+ LOGGER.log(Level.WARNING, "Failed to save "+getConfigFile(),e);
+ }
}
- private Map load() {
+ private void load() {
// load
XmlFile file = getConfigFile();
if(!file.exists())
- return new HashMap();
+ return;
try {
- return (Map)file.read();
+ Object o = file.unmarshal(this);
+ if(o instanceof Map) {
+ // legacy format
+ convert((Map)o);
+ save(); // convert to the new format
+ }
} catch (IOException e) {
- return new HashMap();
+ LOGGER.log(Level.WARNING, "Failed to load "+file, e);
}
}
+ /**
+ * {@link Descriptor}s that has existed <= 1.61 needs to
+ * be able to read in the old configuration in a property bag
+ * and reflect that into the new layout.
+ */
+ protected void convert(Map oldPropertyBag) {
+ }
+
private XmlFile getConfigFile() {
return new XmlFile(new File(Hudson.getInstance().getRootDir(),clazz.getName()+".xml"));
}
@@ -203,4 +208,6 @@ public abstract class Descriptor> {
return formField;
}
}
+
+ private static final Logger LOGGER = Logger.getLogger(Descriptor.class.getName());
}
diff --git a/core/src/main/java/hudson/scm/CVSSCM.java b/core/src/main/java/hudson/scm/CVSSCM.java
index 3acdd9da47..2b9d87236b 100644
--- a/core/src/main/java/hudson/scm/CVSSCM.java
+++ b/core/src/main/java/hudson/scm/CVSSCM.java
@@ -46,6 +46,7 @@ import java.util.Map;
import java.util.StringTokenizer;
import java.util.Set;
import java.util.HashSet;
+import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -490,10 +491,29 @@ public class CVSSCM extends AbstractCVSFamilySCM {
static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor implements ModelObject {
+ /**
+ * Path to .cvspass. Null to default.
+ */
+ private String cvsPassFile;
+
+ /**
+ * Copy-on-write.
+ */
+ private volatile Map browsers = new HashMap();
+
+ class RepositoryBrowser {
+ String diffURL;
+ String browseURL;
+ }
+
DescriptorImpl() {
super(CVSSCM.class);
}
+ protected void convert(Map oldPropertyBag) {
+ cvsPassFile = (String)oldPropertyBag.get("cvspass");
+ }
+
public String getDisplayName() {
return "CVS";
}
@@ -510,14 +530,14 @@ public class CVSSCM extends AbstractCVSFamilySCM {
}
public String getCvspassFile() {
- String value = (String)getProperties().get("cvspass");
+ String value = cvsPassFile;
if(value==null)
value = "";
return value;
}
public void setCvspassFile(String value) {
- getProperties().put("cvspass",value);
+ cvsPassFile = value;
save();
}
@@ -525,45 +545,35 @@ public class CVSSCM extends AbstractCVSFamilySCM {
* Gets the URL that shows the diff.
*/
public String getDiffURL(String cvsRoot, String pathName, String oldRev, String newRev) {
- String url = getProperties().get("repository-browser.diff." + cvsRoot).toString();
- if(url==null) return null;
- return url.replaceAll("%%P",pathName).replace("%%r",oldRev).replace("%%R",newRev);
+ RepositoryBrowser b = browsers.get(cvsRoot);
+ if(b==null) return null;
+ return b.diffURL.replaceAll("%%P",pathName).replace("%%r",oldRev).replace("%%R",newRev);
}
public boolean configure( HttpServletRequest req ) {
setCvspassFile(req.getParameter("cvs_cvspass"));
- Map properties = getProperties();
-
+ Map browsers = new HashMap();
int i=0;
while(true) {
String root = req.getParameter("cvs_repobrowser_cvsroot" + i);
if(root==null) break;
- setBrowser(req.getParameter("cvs_repobrowser"+i), properties, root, "repository-browser.");
- setBrowser(req.getParameter("cvs_repobrowser_diff"+i), properties, root, "repository-browser.diff.");
+ RepositoryBrowser rb = new RepositoryBrowser();
+ rb.browseURL = req.getParameter("cvs_repobrowser"+i);
+ rb.diffURL = req.getParameter("cvs_repobrowser_diff"+i);
+ browsers.put(root,rb);
+
i++;
}
+ this.browsers = browsers;
save();
return true;
}
- private void setBrowser(String key, Map properties, String root, String prefi) {
- String value = Util.nullify(key);
- if(value==null) {
- properties.remove(prefi +root);
- } else {
- properties.put(prefi +root,value);
- }
- }
-
- public Map getProperties() {
- return super.getProperties();
- }
-
//
// web methods
//
diff --git a/core/src/main/java/hudson/scm/SubversionSCM.java b/core/src/main/java/hudson/scm/SubversionSCM.java
index 9bf0473c41..30df663c85 100644
--- a/core/src/main/java/hudson/scm/SubversionSCM.java
+++ b/core/src/main/java/hudson/scm/SubversionSCM.java
@@ -409,10 +409,19 @@ public class SubversionSCM extends AbstractCVSFamilySCM {
static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor {
+ /**
+ * Path to svn.exe. Null to default.
+ */
+ private String svnExe;
+
DescriptorImpl() {
super(SubversionSCM.class);
}
+ protected void convert(Map oldPropertyBag) {
+ svnExe = (String)oldPropertyBag.get("svn_exe");
+ }
+
public String getDisplayName() {
return "Subversion";
}
@@ -427,19 +436,19 @@ public class SubversionSCM extends AbstractCVSFamilySCM {
}
public String getSvnExe() {
- String value = (String)getProperties().get("svn_exe");
+ String value = svnExe;
if(value==null)
value = "svn";
return value;
}
public void setSvnExe(String value) {
- getProperties().put("svn_exe",value);
+ svnExe = value;
save();
}
public boolean configure( HttpServletRequest req ) {
- setSvnExe(req.getParameter("svn_exe"));
+ svnExe = req.getParameter("svn_exe");
return true;
}
diff --git a/core/src/main/java/hudson/tasks/Ant.java b/core/src/main/java/hudson/tasks/Ant.java
index 3fd3013eaf..a09c2dfaab 100644
--- a/core/src/main/java/hudson/tasks/Ant.java
+++ b/core/src/main/java/hudson/tasks/Ant.java
@@ -1,23 +1,22 @@
package hudson.tasks;
+import hudson.CopyOnWrite;
import hudson.Launcher;
import hudson.Util;
-import hudson.util.FormFieldValidator;
-import hudson.model.Action;
import hudson.model.Build;
import hudson.model.BuildListener;
import hudson.model.Descriptor;
import hudson.model.Project;
+import hudson.util.FormFieldValidator;
+import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerResponse;
-import javax.servlet.http.HttpServletRequest;
import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Map;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
-
/**
* @author Kohsuke Kawaguchi
*/
@@ -103,10 +102,18 @@ public class Ant extends Builder {
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor {
+ @CopyOnWrite
+ private volatile AntInstallation[] installations = new AntInstallation[0];
+
private DescriptorImpl() {
super(Ant.class);
}
+ protected void convert(Map oldPropertyBag) {
+ if(oldPropertyBag.containsKey("installations"))
+ installations = (AntInstallation[]) oldPropertyBag.get("installations");
+ }
+
public String getHelpFile() {
return "/help/project-config/ant.html";
}
@@ -116,12 +123,7 @@ public class Ant extends Builder {
}
public AntInstallation[] getInstallations() {
- AntInstallation[] r = (AntInstallation[]) getProperties().get("installations");
-
- if(r==null)
- return new AntInstallation[0];
-
- return r.clone();
+ return installations;
}
public boolean configure(HttpServletRequest req) {
@@ -142,7 +144,7 @@ public class Ant extends Builder {
insts[i] = new AntInstallation(names[i],homes[i]);
}
- getProperties().put("installations",insts);
+ this.installations = insts;
save();
diff --git a/core/src/main/java/hudson/tasks/Mailer.java b/core/src/main/java/hudson/tasks/Mailer.java
index 5acc1edc85..8fe4323ce9 100644
--- a/core/src/main/java/hudson/tasks/Mailer.java
+++ b/core/src/main/java/hudson/tasks/Mailer.java
@@ -12,13 +12,13 @@ import hudson.scm.ChangeLogSet.Entry;
import org.apache.tools.ant.types.selectors.SelectorUtils;
import org.kohsuke.stapler.StaplerRequest;
+import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
-import javax.mail.Address;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
@@ -27,13 +27,13 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
+import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
-import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@@ -77,11 +77,11 @@ public class Mailer extends Publisher {
if(mail!=null) {
Address[] allRecipients = mail.getAllRecipients();
if(allRecipients!=null) {
- StringBuffer buf = new StringBuffer("Sending e-mails to ");
+ StringBuffer buf = new StringBuffer("Sending e-mails to ");
for (Address a : allRecipients)
- buf.append(' ').append(a);
- listener.getLogger().println(buf);
- Transport.send(mail);
+ buf.append(' ').append(a);
+ listener.getLogger().println(buf);
+ Transport.send(mail);
} else {
listener.getLogger().println("An attempt to send an e-mail"
+ " to empty list of recipients, ignored.");
@@ -261,11 +261,50 @@ public class Mailer extends Publisher {
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor {
+ /**
+ * The default e-mail address suffix appended to the user name found from changelog,
+ * to send e-mails. Null if not configured.
+ */
+ private String defaultSuffix;
+
+ /**
+ * Hudson's own URL, to put into the e-mail.
+ */
+ private String hudsonUrl;
+
+ /**
+ * If non-null, use SMTP-AUTH with these information.
+ */
+ private String smtpAuthPassword,smtpAuthUsername;
+
+ /**
+ * The e-mail address that Hudson puts to "From:" field in outgoing e-mails.
+ * Null if unconfigured.
+ */
+ private String adminAddress;
+
+ /**
+ * The SMTP server to use for sending e-mail. Null for default to the environment,
+ * which is usually localhost.
+ */
+ private String smtpHost;
public DescriptorImpl() {
super(Mailer.class);
}
+ /**
+ * For backward compatibility.
+ */
+ protected void convert(Map oldPropertyBag) {
+ defaultSuffix = (String)oldPropertyBag.get("mail.default.suffix");
+ hudsonUrl = (String)oldPropertyBag.get("mail.hudson.url");
+ smtpAuthUsername = (String)oldPropertyBag.get("mail.hudson.smtpauth.username");
+ smtpAuthPassword = (String)oldPropertyBag.get("mail.hudson.smtpauth.password");
+ adminAddress = (String)oldPropertyBag.get("mail.admin.address");
+ smtpHost = (String)oldPropertyBag.get("mail.smtp.host");
+ }
+
public String getDisplayName() {
return "E-mail Notification";
}
@@ -275,17 +314,14 @@ public class Mailer extends Publisher {
}
public String getDefaultSuffix() {
- return (String)getProperties().get("mail.default.suffix");
+ return defaultSuffix;
}
/** JavaMail session. */
public Session createSession() {
Properties props = new Properties(System.getProperties());
- // can't use putAll
- for (Map.Entry o : ((Map,?>)getProperties()).entrySet()) {
- if(o.getValue()!=null)
- props.put(o.getKey(),o.getValue());
- }
+ if(smtpHost!=null)
+ props.put("mail.smtp.host",smtpHost);
return Session.getInstance(props,getAuthenticator());
}
@@ -302,16 +338,20 @@ public class Mailer extends Publisher {
public boolean configure(HttpServletRequest req) throws FormException {
// this code is brain dead
- getProperties().put("mail.smtp.host",nullify(req.getParameter("mailer_smtp_server")));
- getProperties().put("mail.admin.address",req.getParameter("mailer_admin_address"));
- getProperties().put("mail.default.suffix",nullify(req.getParameter("mailer_default_suffix")));
+ smtpHost = nullify(req.getParameter("mailer_smtp_server"));
+ adminAddress = req.getParameter("mailer_admin_address");
+ defaultSuffix = nullify(req.getParameter("mailer_default_suffix"));
String url = nullify(req.getParameter("mailer_hudson_url"));
if(url!=null && !url.endsWith("/"))
url += '/';
- getProperties().put("mail.hudson.url",url);
+ hudsonUrl = url;
- getProperties().put("mail.hudson.smtpauth.username",nullify(req.getParameter("mailer.SMTPAuth.userName")));
- getProperties().put("mail.hudson.smtpauth.password",nullify(req.getParameter("mailer.SMTPAuth.password")));
+ if(req.getParameter("mailer.useSMTPAuth")!=null) {
+ smtpAuthUsername = nullify(req.getParameter("mailer.SMTPAuth.userName"));
+ smtpAuthPassword = nullify(req.getParameter("mailer.SMTPAuth.password"));
+ } else {
+ smtpAuthUsername = smtpAuthPassword = null;
+ }
save();
return super.configure(req);
@@ -323,25 +363,25 @@ public class Mailer extends Publisher {
}
public String getSmtpServer() {
- return (String)getProperties().get("mail.smtp.host");
+ return smtpHost;
}
public String getAdminAddress() {
- String v = (String)getProperties().get("mail.admin.address");
+ String v = adminAddress;
if(v==null) v = "address not configured yet ";
return v;
}
public String getUrl() {
- return (String)getProperties().get("mail.hudson.url");
+ return hudsonUrl;
}
public String getSmtpAuthUserName() {
- return (String)getProperties().get("mail.hudson.smtpauth.username");
+ return smtpAuthUsername;
}
public String getSmtpAuthPassword() {
- return (String)getProperties().get("mail.hudson.smtpauth.password");
+ return smtpAuthPassword;
}
/** Check whether a path (/-separated) will be archived. */
@@ -433,7 +473,6 @@ public class Mailer extends Publisher {
StringBuilder sb = new StringBuilder(s.length() * 2);
sb.append("\\Q");
- slashEIndex = 0;
int current = 0;
while ((slashEIndex = s.indexOf("\\E", current)) != -1) {
sb.append(s.substring(current, slashEIndex));
diff --git a/core/src/main/java/hudson/tasks/Maven.java b/core/src/main/java/hudson/tasks/Maven.java
index b554d1cd87..73d2b6d245 100644
--- a/core/src/main/java/hudson/tasks/Maven.java
+++ b/core/src/main/java/hudson/tasks/Maven.java
@@ -1,23 +1,22 @@
package hudson.tasks;
+import hudson.CopyOnWrite;
import hudson.Launcher;
import hudson.Util;
-import hudson.util.FormFieldValidator;
-import hudson.model.Action;
import hudson.model.Build;
import hudson.model.BuildListener;
import hudson.model.Descriptor;
import hudson.model.Project;
+import hudson.util.FormFieldValidator;
+import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerResponse;
-import javax.servlet.http.HttpServletRequest;
import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Map;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
-
/**
* Build by using Maven.
*
@@ -104,10 +103,19 @@ public class Maven extends Builder {
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor {
+ @CopyOnWrite
+ private MavenInstallation[] installations = new MavenInstallation[0];
+
private DescriptorImpl() {
super(Maven.class);
}
+
+ protected void convert(Map oldPropertyBag) {
+ if(oldPropertyBag.containsKey("installations"))
+ installations = (MavenInstallation[]) oldPropertyBag.get("installations");
+ }
+
public String getHelpFile() {
return "/help/project-config/maven.html";
}
@@ -117,12 +125,7 @@ public class Maven extends Builder {
}
public MavenInstallation[] getInstallations() {
- MavenInstallation[] r = (MavenInstallation[]) getProperties().get("installations");
-
- if(r==null)
- return new MavenInstallation[0];
-
- return r.clone();
+ return installations;
}
public boolean configure(HttpServletRequest req) {
@@ -144,7 +147,7 @@ public class Maven extends Builder {
insts[i] = new MavenInstallation(names[i],homes[i]);
}
- getProperties().put("installations",insts);
+ this.installations = insts;
save();
diff --git a/core/src/main/java/hudson/tasks/Shell.java b/core/src/main/java/hudson/tasks/Shell.java
index 747e3ab279..c845337b2a 100644
--- a/core/src/main/java/hudson/tasks/Shell.java
+++ b/core/src/main/java/hudson/tasks/Shell.java
@@ -14,6 +14,7 @@ import javax.servlet.http.HttpServletRequest;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
+import java.util.Map;
/**
* Executes a series of commands by using a shell.
@@ -93,19 +94,28 @@ public class Shell extends Builder {
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor {
+ /**
+ * Shell executable, or null to default.
+ */
+ private String shell;
+
private DescriptorImpl() {
super(Shell.class);
}
+
+ protected void convert(Map oldPropertyBag) {
+ shell = (String)oldPropertyBag.get("shell");
+ }
+
public String getShell() {
- String shell = (String)getProperties().get("shell");
if(shell==null)
- shell = isWindows()?"sh":"/bin/sh";
+ return isWindows()?"sh":"/bin/sh";
return shell;
}
public void setShell(String shell) {
- getProperties().put("shell",shell);
+ this.shell = shell;
save();
}
diff --git a/core/src/main/java/hudson/triggers/SCMTrigger.java b/core/src/main/java/hudson/triggers/SCMTrigger.java
index 36957e8467..3f80bc8a03 100644
--- a/core/src/main/java/hudson/triggers/SCMTrigger.java
+++ b/core/src/main/java/hudson/triggers/SCMTrigger.java
@@ -130,10 +130,16 @@ public class SCMTrigger extends Trigger {
*/
transient volatile ExecutorService executor;
+ /**
+ * Max number of threads for SCM polling.
+ * 0 for unbounded.
+ */
+ private int maximumThreads;
+
DescriptorImpl() {
super(SCMTrigger.class);
// create an executor
- update(getPollingThreadCount());
+ update();
}
public ExecutorService getExecutor() {
@@ -163,28 +169,24 @@ public class SCMTrigger extends Trigger {
* 0 if unlimited.
*/
public int getPollingThreadCount() {
- String value = (String)getProperties().get("poll_scm_threads");
- if(value==null)
- return 0;
- return Integer.parseInt(value);
+ return maximumThreads;
}
public void setPollingThreadCount(int n) {
- getProperties().put("poll_scm_threads",String.valueOf(n));
+ // fool proof
+ if(n<0) n=0;
+ if(n>100) n=100;
+
+ maximumThreads = n;
save();
- update(n);
}
/**
* Update the {@link ExecutorService} instance.
*/
- /*package*/ synchronized void update(int n) {
- // fool proof
- if(n<0) n=0;
- if(n>100) n=0;
-
+ /*package*/ synchronized void update() {
// swap to a new one, and shut down the old one gradually
- ExecutorService newExec = n==0 ? Executors.newCachedThreadPool() : Executors.newFixedThreadPool(n);
+ ExecutorService newExec = maximumThreads==0 ? Executors.newCachedThreadPool() : Executors.newFixedThreadPool(maximumThreads);
ExecutorService old = executor;
executor = newExec;
if(old!=null)