提交 6a186623 编写于 作者: K kohsuke

modified the Descriptor persistence scheme.

We used to use Map<String,Object> as a data store for Descriptor, but this requires a lot of boiler plate code to move values in/out from this Map, making the code uglier.
I modified this to just use XStream like the rest of the Hudson, so that the information can be persisted by simply storing them in fields.
Existing Descriptors are enhanced so that they can convert formats from pre-1.62 XML format.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@1126 71c3de6d-444a-0410-be80-ed276b4c234a
上级 329891f8
...@@ -51,11 +51,15 @@ public final class XmlFile { ...@@ -51,11 +51,15 @@ public final class XmlFile {
/** /**
* Loads the contents of this file into an existing object. * Loads the contents of this file into an existing object.
*
* @return
* The unmarshalled object. Usually the same as <tt>o</tt>, but would be different
* if the XML representation if completely new.
*/ */
public void unmarshal( Object o ) throws IOException { public Object unmarshal( Object o ) throws IOException {
Reader r = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8")); Reader r = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"));
try { try {
xs.unmarshal(new XppReader(r),o); return xs.unmarshal(new XppReader(r),o);
} catch (StreamException e) { } catch (StreamException e) {
throw new IOException2(e); throw new IOException2(e);
} catch(ConversionException e) { } catch(ConversionException e) {
......
...@@ -2,17 +2,17 @@ package hudson.model; ...@@ -2,17 +2,17 @@ package hudson.model;
import hudson.XmlFile; import hudson.XmlFile;
import hudson.scm.CVSSCM; import hudson.scm.CVSSCM;
import org.kohsuke.stapler.StaplerRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import org.kohsuke.stapler.StaplerRequest; import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Metadata about a configurable instance. * Metadata about a configurable instance.
...@@ -47,15 +47,23 @@ import org.kohsuke.stapler.StaplerRequest; ...@@ -47,15 +47,23 @@ import org.kohsuke.stapler.StaplerRequest;
* @see Describable * @see Describable
*/ */
public abstract class Descriptor<T extends Describable<T>> { public abstract class Descriptor<T extends Describable<T>> {
private Map<String,Object> properties; /**
* Up to Hudson 1.61 this was used as the primary persistence mechanism.
* Going forward Hudson simply persists all the non-transient fields
* of {@link Descriptor}, just like others, so this is pointless.
*
* @deprecated
*/
private transient Map<String,Object> properties;
/** /**
* The class being described by this descriptor. * The class being described by this descriptor.
*/ */
public final Class<? extends T> clazz; public transient final Class<? extends T> clazz;
protected Descriptor(Class<? extends T> clazz) { protected Descriptor(Class<? extends T> clazz) {
this.clazz = clazz; this.clazz = clazz;
load();
} }
/** /**
...@@ -92,21 +100,6 @@ public abstract class Descriptor<T extends Describable<T>> { ...@@ -92,21 +100,6 @@ public abstract class Descriptor<T extends Describable<T>> {
return clazz.isInstance(instance); return clazz.isInstance(instance);
} }
/**
* Returns the data store that can be used to store configuration info.
*
* <p>
* The data store is local to each {@link Descriptor}.
*
* @return
* never return null.
*/
protected synchronized Map<String,Object> getProperties() {
if(properties==null)
properties = load();
return properties;
}
/** /**
* Invoked when the global configuration page is submitted. * Invoked when the global configuration page is submitted.
* *
...@@ -132,27 +125,39 @@ public abstract class Descriptor<T extends Describable<T>> { ...@@ -132,27 +125,39 @@ public abstract class Descriptor<T extends Describable<T>> {
* Saves the configuration info to the disk. * Saves the configuration info to the disk.
*/ */
protected synchronized void save() { protected synchronized void save() {
if(properties!=null) try {
try { getConfigFile().write(this);
getConfigFile().write(properties); } catch (IOException e) {
} catch (IOException e) { LOGGER.log(Level.WARNING, "Failed to save "+getConfigFile(),e);
e.printStackTrace(); }
}
} }
private Map<String,Object> load() { private void load() {
// load // load
XmlFile file = getConfigFile(); XmlFile file = getConfigFile();
if(!file.exists()) if(!file.exists())
return new HashMap<String,Object>(); return;
try { try {
return (Map<String,Object>)file.read(); Object o = file.unmarshal(this);
if(o instanceof Map) {
// legacy format
convert((Map<String,Object>)o);
save(); // convert to the new format
}
} catch (IOException e) { } catch (IOException e) {
return new HashMap<String,Object>(); LOGGER.log(Level.WARNING, "Failed to load "+file, e);
} }
} }
/**
* {@link Descriptor}s that has existed &lt;= 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<String, Object> oldPropertyBag) {
}
private XmlFile getConfigFile() { private XmlFile getConfigFile() {
return new XmlFile(new File(Hudson.getInstance().getRootDir(),clazz.getName()+".xml")); return new XmlFile(new File(Hudson.getInstance().getRootDir(),clazz.getName()+".xml"));
} }
...@@ -203,4 +208,6 @@ public abstract class Descriptor<T extends Describable<T>> { ...@@ -203,4 +208,6 @@ public abstract class Descriptor<T extends Describable<T>> {
return formField; return formField;
} }
} }
private static final Logger LOGGER = Logger.getLogger(Descriptor.class.getName());
} }
...@@ -46,6 +46,7 @@ import java.util.Map; ...@@ -46,6 +46,7 @@ import java.util.Map;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.Set; import java.util.Set;
import java.util.HashSet; import java.util.HashSet;
import java.util.HashMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
...@@ -490,10 +491,29 @@ public class CVSSCM extends AbstractCVSFamilySCM { ...@@ -490,10 +491,29 @@ public class CVSSCM extends AbstractCVSFamilySCM {
static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor<SCM> implements ModelObject { public static final class DescriptorImpl extends Descriptor<SCM> implements ModelObject {
/**
* Path to <tt>.cvspass</tt>. Null to default.
*/
private String cvsPassFile;
/**
* Copy-on-write.
*/
private volatile Map<String,RepositoryBrowser> browsers = new HashMap<String,RepositoryBrowser>();
class RepositoryBrowser {
String diffURL;
String browseURL;
}
DescriptorImpl() { DescriptorImpl() {
super(CVSSCM.class); super(CVSSCM.class);
} }
protected void convert(Map<String, Object> oldPropertyBag) {
cvsPassFile = (String)oldPropertyBag.get("cvspass");
}
public String getDisplayName() { public String getDisplayName() {
return "CVS"; return "CVS";
} }
...@@ -510,14 +530,14 @@ public class CVSSCM extends AbstractCVSFamilySCM { ...@@ -510,14 +530,14 @@ public class CVSSCM extends AbstractCVSFamilySCM {
} }
public String getCvspassFile() { public String getCvspassFile() {
String value = (String)getProperties().get("cvspass"); String value = cvsPassFile;
if(value==null) if(value==null)
value = ""; value = "";
return value; return value;
} }
public void setCvspassFile(String value) { public void setCvspassFile(String value) {
getProperties().put("cvspass",value); cvsPassFile = value;
save(); save();
} }
...@@ -525,45 +545,35 @@ public class CVSSCM extends AbstractCVSFamilySCM { ...@@ -525,45 +545,35 @@ public class CVSSCM extends AbstractCVSFamilySCM {
* Gets the URL that shows the diff. * Gets the URL that shows the diff.
*/ */
public String getDiffURL(String cvsRoot, String pathName, String oldRev, String newRev) { public String getDiffURL(String cvsRoot, String pathName, String oldRev, String newRev) {
String url = getProperties().get("repository-browser.diff." + cvsRoot).toString(); RepositoryBrowser b = browsers.get(cvsRoot);
if(url==null) return null; if(b==null) return null;
return url.replaceAll("%%P",pathName).replace("%%r",oldRev).replace("%%R",newRev); return b.diffURL.replaceAll("%%P",pathName).replace("%%r",oldRev).replace("%%R",newRev);
} }
public boolean configure( HttpServletRequest req ) { public boolean configure( HttpServletRequest req ) {
setCvspassFile(req.getParameter("cvs_cvspass")); setCvspassFile(req.getParameter("cvs_cvspass"));
Map<String,Object> properties = getProperties(); Map<String,RepositoryBrowser> browsers = new HashMap<String, RepositoryBrowser>();
int i=0; int i=0;
while(true) { while(true) {
String root = req.getParameter("cvs_repobrowser_cvsroot" + i); String root = req.getParameter("cvs_repobrowser_cvsroot" + i);
if(root==null) break; if(root==null) break;
setBrowser(req.getParameter("cvs_repobrowser"+i), properties, root, "repository-browser."); RepositoryBrowser rb = new RepositoryBrowser();
setBrowser(req.getParameter("cvs_repobrowser_diff"+i), properties, root, "repository-browser.diff."); rb.browseURL = req.getParameter("cvs_repobrowser"+i);
rb.diffURL = req.getParameter("cvs_repobrowser_diff"+i);
browsers.put(root,rb);
i++; i++;
} }
this.browsers = browsers;
save(); save();
return true; return true;
} }
private void setBrowser(String key, Map<String, Object> 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<String,Object> getProperties() {
return super.getProperties();
}
// //
// web methods // web methods
// //
......
...@@ -409,10 +409,19 @@ public class SubversionSCM extends AbstractCVSFamilySCM { ...@@ -409,10 +409,19 @@ public class SubversionSCM extends AbstractCVSFamilySCM {
static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor<SCM> { public static final class DescriptorImpl extends Descriptor<SCM> {
/**
* Path to <tt>svn.exe</tt>. Null to default.
*/
private String svnExe;
DescriptorImpl() { DescriptorImpl() {
super(SubversionSCM.class); super(SubversionSCM.class);
} }
protected void convert(Map<String, Object> oldPropertyBag) {
svnExe = (String)oldPropertyBag.get("svn_exe");
}
public String getDisplayName() { public String getDisplayName() {
return "Subversion"; return "Subversion";
} }
...@@ -427,19 +436,19 @@ public class SubversionSCM extends AbstractCVSFamilySCM { ...@@ -427,19 +436,19 @@ public class SubversionSCM extends AbstractCVSFamilySCM {
} }
public String getSvnExe() { public String getSvnExe() {
String value = (String)getProperties().get("svn_exe"); String value = svnExe;
if(value==null) if(value==null)
value = "svn"; value = "svn";
return value; return value;
} }
public void setSvnExe(String value) { public void setSvnExe(String value) {
getProperties().put("svn_exe",value); svnExe = value;
save(); save();
} }
public boolean configure( HttpServletRequest req ) { public boolean configure( HttpServletRequest req ) {
setSvnExe(req.getParameter("svn_exe")); svnExe = req.getParameter("svn_exe");
return true; return true;
} }
......
package hudson.tasks; package hudson.tasks;
import hudson.CopyOnWrite;
import hudson.Launcher; import hudson.Launcher;
import hudson.Util; import hudson.Util;
import hudson.util.FormFieldValidator;
import hudson.model.Action;
import hudson.model.Build; import hudson.model.Build;
import hudson.model.BuildListener; import hudson.model.BuildListener;
import hudson.model.Descriptor; import hudson.model.Descriptor;
import hudson.model.Project; 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.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/** /**
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
...@@ -103,10 +102,18 @@ public class Ant extends Builder { ...@@ -103,10 +102,18 @@ public class Ant extends Builder {
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor<Builder> { public static final class DescriptorImpl extends Descriptor<Builder> {
@CopyOnWrite
private volatile AntInstallation[] installations = new AntInstallation[0];
private DescriptorImpl() { private DescriptorImpl() {
super(Ant.class); super(Ant.class);
} }
protected void convert(Map<String,Object> oldPropertyBag) {
if(oldPropertyBag.containsKey("installations"))
installations = (AntInstallation[]) oldPropertyBag.get("installations");
}
public String getHelpFile() { public String getHelpFile() {
return "/help/project-config/ant.html"; return "/help/project-config/ant.html";
} }
...@@ -116,12 +123,7 @@ public class Ant extends Builder { ...@@ -116,12 +123,7 @@ public class Ant extends Builder {
} }
public AntInstallation[] getInstallations() { public AntInstallation[] getInstallations() {
AntInstallation[] r = (AntInstallation[]) getProperties().get("installations"); return installations;
if(r==null)
return new AntInstallation[0];
return r.clone();
} }
public boolean configure(HttpServletRequest req) { public boolean configure(HttpServletRequest req) {
...@@ -142,7 +144,7 @@ public class Ant extends Builder { ...@@ -142,7 +144,7 @@ public class Ant extends Builder {
insts[i] = new AntInstallation(names[i],homes[i]); insts[i] = new AntInstallation(names[i],homes[i]);
} }
getProperties().put("installations",insts); this.installations = insts;
save(); save();
......
...@@ -12,13 +12,13 @@ import hudson.scm.ChangeLogSet.Entry; ...@@ -12,13 +12,13 @@ import hudson.scm.ChangeLogSet.Entry;
import org.apache.tools.ant.types.selectors.SelectorUtils; import org.apache.tools.ant.types.selectors.SelectorUtils;
import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerRequest;
import javax.mail.Address;
import javax.mail.Authenticator; import javax.mail.Authenticator;
import javax.mail.Message; import javax.mail.Message;
import javax.mail.MessagingException; import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication; import javax.mail.PasswordAuthentication;
import javax.mail.Session; import javax.mail.Session;
import javax.mail.Transport; import javax.mail.Transport;
import javax.mail.Address;
import javax.mail.internet.InternetAddress; import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
...@@ -27,13 +27,13 @@ import java.io.IOException; ...@@ -27,13 +27,13 @@ import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.Date;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
...@@ -77,11 +77,11 @@ public class Mailer extends Publisher { ...@@ -77,11 +77,11 @@ public class Mailer extends Publisher {
if(mail!=null) { if(mail!=null) {
Address[] allRecipients = mail.getAllRecipients(); Address[] allRecipients = mail.getAllRecipients();
if(allRecipients!=null) { if(allRecipients!=null) {
StringBuffer buf = new StringBuffer("Sending e-mails to "); StringBuffer buf = new StringBuffer("Sending e-mails to ");
for (Address a : allRecipients) for (Address a : allRecipients)
buf.append(' ').append(a); buf.append(' ').append(a);
listener.getLogger().println(buf); listener.getLogger().println(buf);
Transport.send(mail); Transport.send(mail);
} else { } else {
listener.getLogger().println("An attempt to send an e-mail" listener.getLogger().println("An attempt to send an e-mail"
+ " to empty list of recipients, ignored."); + " to empty list of recipients, ignored.");
...@@ -261,11 +261,50 @@ public class Mailer extends Publisher { ...@@ -261,11 +261,50 @@ public class Mailer extends Publisher {
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor<Publisher> { public static final class DescriptorImpl extends Descriptor<Publisher> {
/**
* 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 <tt>localhost</tt>.
*/
private String smtpHost;
public DescriptorImpl() { public DescriptorImpl() {
super(Mailer.class); super(Mailer.class);
} }
/**
* For backward compatibility.
*/
protected void convert(Map<String, Object> 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() { public String getDisplayName() {
return "E-mail Notification"; return "E-mail Notification";
} }
...@@ -275,17 +314,14 @@ public class Mailer extends Publisher { ...@@ -275,17 +314,14 @@ public class Mailer extends Publisher {
} }
public String getDefaultSuffix() { public String getDefaultSuffix() {
return (String)getProperties().get("mail.default.suffix"); return defaultSuffix;
} }
/** JavaMail session. */ /** JavaMail session. */
public Session createSession() { public Session createSession() {
Properties props = new Properties(System.getProperties()); Properties props = new Properties(System.getProperties());
// can't use putAll if(smtpHost!=null)
for (Map.Entry o : ((Map<?,?>)getProperties()).entrySet()) { props.put("mail.smtp.host",smtpHost);
if(o.getValue()!=null)
props.put(o.getKey(),o.getValue());
}
return Session.getInstance(props,getAuthenticator()); return Session.getInstance(props,getAuthenticator());
} }
...@@ -302,16 +338,20 @@ public class Mailer extends Publisher { ...@@ -302,16 +338,20 @@ public class Mailer extends Publisher {
public boolean configure(HttpServletRequest req) throws FormException { public boolean configure(HttpServletRequest req) throws FormException {
// this code is brain dead // this code is brain dead
getProperties().put("mail.smtp.host",nullify(req.getParameter("mailer_smtp_server"))); smtpHost = nullify(req.getParameter("mailer_smtp_server"));
getProperties().put("mail.admin.address",req.getParameter("mailer_admin_address")); adminAddress = req.getParameter("mailer_admin_address");
getProperties().put("mail.default.suffix",nullify(req.getParameter("mailer_default_suffix"))); defaultSuffix = nullify(req.getParameter("mailer_default_suffix"));
String url = nullify(req.getParameter("mailer_hudson_url")); String url = nullify(req.getParameter("mailer_hudson_url"));
if(url!=null && !url.endsWith("/")) if(url!=null && !url.endsWith("/"))
url += '/'; url += '/';
getProperties().put("mail.hudson.url",url); hudsonUrl = url;
getProperties().put("mail.hudson.smtpauth.username",nullify(req.getParameter("mailer.SMTPAuth.userName"))); if(req.getParameter("mailer.useSMTPAuth")!=null) {
getProperties().put("mail.hudson.smtpauth.password",nullify(req.getParameter("mailer.SMTPAuth.password"))); smtpAuthUsername = nullify(req.getParameter("mailer.SMTPAuth.userName"));
smtpAuthPassword = nullify(req.getParameter("mailer.SMTPAuth.password"));
} else {
smtpAuthUsername = smtpAuthPassword = null;
}
save(); save();
return super.configure(req); return super.configure(req);
...@@ -323,25 +363,25 @@ public class Mailer extends Publisher { ...@@ -323,25 +363,25 @@ public class Mailer extends Publisher {
} }
public String getSmtpServer() { public String getSmtpServer() {
return (String)getProperties().get("mail.smtp.host"); return smtpHost;
} }
public String getAdminAddress() { public String getAdminAddress() {
String v = (String)getProperties().get("mail.admin.address"); String v = adminAddress;
if(v==null) v = "address not configured yet <nobody>"; if(v==null) v = "address not configured yet <nobody>";
return v; return v;
} }
public String getUrl() { public String getUrl() {
return (String)getProperties().get("mail.hudson.url"); return hudsonUrl;
} }
public String getSmtpAuthUserName() { public String getSmtpAuthUserName() {
return (String)getProperties().get("mail.hudson.smtpauth.username"); return smtpAuthUsername;
} }
public String getSmtpAuthPassword() { public String getSmtpAuthPassword() {
return (String)getProperties().get("mail.hudson.smtpauth.password"); return smtpAuthPassword;
} }
/** Check whether a path (/-separated) will be archived. */ /** Check whether a path (/-separated) will be archived. */
...@@ -433,7 +473,6 @@ public class Mailer extends Publisher { ...@@ -433,7 +473,6 @@ public class Mailer extends Publisher {
StringBuilder sb = new StringBuilder(s.length() * 2); StringBuilder sb = new StringBuilder(s.length() * 2);
sb.append("\\Q"); sb.append("\\Q");
slashEIndex = 0;
int current = 0; int current = 0;
while ((slashEIndex = s.indexOf("\\E", current)) != -1) { while ((slashEIndex = s.indexOf("\\E", current)) != -1) {
sb.append(s.substring(current, slashEIndex)); sb.append(s.substring(current, slashEIndex));
......
package hudson.tasks; package hudson.tasks;
import hudson.CopyOnWrite;
import hudson.Launcher; import hudson.Launcher;
import hudson.Util; import hudson.Util;
import hudson.util.FormFieldValidator;
import hudson.model.Action;
import hudson.model.Build; import hudson.model.Build;
import hudson.model.BuildListener; import hudson.model.BuildListener;
import hudson.model.Descriptor; import hudson.model.Descriptor;
import hudson.model.Project; 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.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/** /**
* Build by using Maven. * Build by using Maven.
* *
...@@ -104,10 +103,19 @@ public class Maven extends Builder { ...@@ -104,10 +103,19 @@ public class Maven extends Builder {
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor<Builder> { public static final class DescriptorImpl extends Descriptor<Builder> {
@CopyOnWrite
private MavenInstallation[] installations = new MavenInstallation[0];
private DescriptorImpl() { private DescriptorImpl() {
super(Maven.class); super(Maven.class);
} }
protected void convert(Map<String, Object> oldPropertyBag) {
if(oldPropertyBag.containsKey("installations"))
installations = (MavenInstallation[]) oldPropertyBag.get("installations");
}
public String getHelpFile() { public String getHelpFile() {
return "/help/project-config/maven.html"; return "/help/project-config/maven.html";
} }
...@@ -117,12 +125,7 @@ public class Maven extends Builder { ...@@ -117,12 +125,7 @@ public class Maven extends Builder {
} }
public MavenInstallation[] getInstallations() { public MavenInstallation[] getInstallations() {
MavenInstallation[] r = (MavenInstallation[]) getProperties().get("installations"); return installations;
if(r==null)
return new MavenInstallation[0];
return r.clone();
} }
public boolean configure(HttpServletRequest req) { public boolean configure(HttpServletRequest req) {
...@@ -144,7 +147,7 @@ public class Maven extends Builder { ...@@ -144,7 +147,7 @@ public class Maven extends Builder {
insts[i] = new MavenInstallation(names[i],homes[i]); insts[i] = new MavenInstallation(names[i],homes[i]);
} }
getProperties().put("installations",insts); this.installations = insts;
save(); save();
......
...@@ -14,6 +14,7 @@ import javax.servlet.http.HttpServletRequest; ...@@ -14,6 +14,7 @@ import javax.servlet.http.HttpServletRequest;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.Map;
/** /**
* Executes a series of commands by using a shell. * Executes a series of commands by using a shell.
...@@ -93,19 +94,28 @@ public class Shell extends Builder { ...@@ -93,19 +94,28 @@ public class Shell extends Builder {
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor<Builder> { public static final class DescriptorImpl extends Descriptor<Builder> {
/**
* Shell executable, or null to default.
*/
private String shell;
private DescriptorImpl() { private DescriptorImpl() {
super(Shell.class); super(Shell.class);
} }
protected void convert(Map<String, Object> oldPropertyBag) {
shell = (String)oldPropertyBag.get("shell");
}
public String getShell() { public String getShell() {
String shell = (String)getProperties().get("shell");
if(shell==null) if(shell==null)
shell = isWindows()?"sh":"/bin/sh"; return isWindows()?"sh":"/bin/sh";
return shell; return shell;
} }
public void setShell(String shell) { public void setShell(String shell) {
getProperties().put("shell",shell); this.shell = shell;
save(); save();
} }
......
...@@ -130,10 +130,16 @@ public class SCMTrigger extends Trigger { ...@@ -130,10 +130,16 @@ public class SCMTrigger extends Trigger {
*/ */
transient volatile ExecutorService executor; transient volatile ExecutorService executor;
/**
* Max number of threads for SCM polling.
* 0 for unbounded.
*/
private int maximumThreads;
DescriptorImpl() { DescriptorImpl() {
super(SCMTrigger.class); super(SCMTrigger.class);
// create an executor // create an executor
update(getPollingThreadCount()); update();
} }
public ExecutorService getExecutor() { public ExecutorService getExecutor() {
...@@ -163,28 +169,24 @@ public class SCMTrigger extends Trigger { ...@@ -163,28 +169,24 @@ public class SCMTrigger extends Trigger {
* 0 if unlimited. * 0 if unlimited.
*/ */
public int getPollingThreadCount() { public int getPollingThreadCount() {
String value = (String)getProperties().get("poll_scm_threads"); return maximumThreads;
if(value==null)
return 0;
return Integer.parseInt(value);
} }
public void setPollingThreadCount(int n) { 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(); save();
update(n);
} }
/** /**
* Update the {@link ExecutorService} instance. * Update the {@link ExecutorService} instance.
*/ */
/*package*/ synchronized void update(int n) { /*package*/ synchronized void update() {
// fool proof
if(n<0) n=0;
if(n>100) n=0;
// swap to a new one, and shut down the old one gradually // 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; ExecutorService old = executor;
executor = newExec; executor = newExec;
if(old!=null) if(old!=null)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册