All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.model.Hudson Maven / Gradle / Ivy

package hudson.model;

import com.thoughtworks.xstream.XStream;
import groovy.lang.GroovyShell;
import hudson.Launcher;
import hudson.Plugin;
import hudson.PluginManager;
import hudson.PluginWrapper;
import hudson.Util;
import hudson.XmlFile;
import hudson.model.Descriptor.FormException;
import hudson.model.listeners.JobListener;
import hudson.scm.CVSSCM;
import hudson.scm.SCM;
import hudson.scm.SCMS;
import hudson.tasks.BuildStep;
import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import hudson.tasks.BuildWrappers;
import hudson.tasks.BuildWrapper;
import hudson.tasks.Mailer;
import hudson.triggers.Trigger;
import hudson.triggers.Triggers;
import hudson.util.FormFieldValidator;
import hudson.util.XStream2;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
import java.util.logging.LogRecord;

/**
 * Root object of the system.
 *
 * @author Kohsuke Kawaguchi
 */
public final class Hudson extends JobCollection implements Node {
    private transient final Queue queue = new Queue();

    /**
     * {@link Computer}s in this Hudson system. Read-only.
     */
    private transient final Map computers = new HashMap();

    /**
     * Number of executors of the master node.
     */
    private int numExecutors = 2;

    /**
     * False to enable anyone to do anything.
     */
    private boolean useSecurity = false;

    /**
     * Message displayed in the top page.
     */
    private String systemMessage;

    /**
     * Root directory of the system.
     */
    public transient final File root;

    /**
     * All {@link Job}s keyed by their names.
     */
    /*package*/ transient final Map jobs = new TreeMap();

    /**
     * The sole instance.
     */
    private static Hudson theInstance;

    private transient boolean isQuietingDown;
    private transient boolean terminating;

    private List jdks;

    /**
     * Set of installed cluster nodes.
     *
     * We use this field with copy-on-write semantics.
     * This field has mutable list (to keep the serialization look clean),
     * but it shall never be modified. Only new completely populated slave
     * list can be set here.
     */
    private volatile List slaves;

    /**
     * Quiet period.
     *
     * This is {@link Integer} so that we can initialize it to '5' for upgrading users.
     */
    /*package*/ Integer quietPeriod;

    /**
     * {@link View}s.
     */
    private List views;   // can't initialize it eagerly for backward compatibility

    private transient final FingerprintMap fingerprintMap = new FingerprintMap();

    /**
     * Loaded plugins.
     */
    public transient final PluginManager pluginManager;

    /**
     * List of reigstered {@link JobListener}s.
     */
    private transient List jobListeners = new Vector();

    public static Hudson getInstance() {
        return theInstance;
    }


    public Hudson(File root, ServletContext context) throws IOException {
        this.root = root;
        if(theInstance!=null)
            throw new IllegalStateException("second instance");
        theInstance = this;

        // load plugins.
        pluginManager = new PluginManager(context);

        load();
        if(slaves==null)    slaves = new ArrayList();
        updateComputerList();

        getQueue().load();
    }

    /**
     * If you are calling this on Hudson something is wrong.
     *
     * @deprecated
     */
    @Deprecated
    public String getNodeName() {
        return "";
    }

    public String getNodeDescription() {
        return "the master Hudson node";
    }

    public String getDescription() {
        return systemMessage;
    }

    public PluginManager getPluginManager() {
        return pluginManager;
    }

    /**
     * Gets the SCM descriptor by name. Primarily used for making them web-visible.
     */
    public Descriptor getScm(String shortClassName) {
        return findDescriptor(shortClassName,SCMS.SCMS);
    }

    /**
     * Gets the builder descriptor by name. Primarily used for making them web-visible.
     */
    public Descriptor getBuilder(String shortClassName) {
        return findDescriptor(shortClassName, BuildStep.BUILDERS);
    }

    /**
     * Gets the publisher descriptor by name. Primarily used for making them web-visible.
     */
    public Descriptor getPublisher(String shortClassName) {
        return findDescriptor(shortClassName, BuildStep.PUBLISHERS);
    }

    /**
     * Finds a descriptor that has the specified name.
     */
    private >
    Descriptor findDescriptor(String shortClassName, Collection> descriptors) {
        String name = '.'+shortClassName;
        for (Descriptor d : descriptors) {
            if(d.clazz.getName().endsWith(name))
                return d;
        }
        return null;
    }

    /**
     * Adds a new {@link JobListener}.
     *
     * @see #removeListener(JobListener) 
     */
    public void addListener(JobListener l) {
        jobListeners.add(l);
    }

    /**
     * Deletes an existing {@link JobListener}.
     *
     * @return
     *      true if the listener was indeed registered.
     */
    public boolean removeListener(JobListener l ) {
        return jobListeners.remove(l);
    }

    /**
     * Gets the plugin object from its short name.
     *
     * 

* This allows URL hudson/plugin/ID to be served by the views * of the plugin class. */ public Plugin getPlugin(String shortName) { PluginWrapper p = pluginManager.getPlugin(shortName); if(p==null) return null; return p.plugin; } /** * Synonym to {@link #getNodeDescription()}. */ public String getSystemMessage() { return systemMessage; } public Launcher createLauncher(TaskListener listener) { return new Launcher(listener); } /** * Updates {@link #computers} by using {@link #getSlaves()}. * *

* This method tries to reuse existing {@link Computer} objects * so that we won't upset {@link Executor}s running in it. */ private void updateComputerList() { synchronized(computers) { Map byName = new HashMap(); for (Computer c : computers.values()) { if(c.getNode()==null) continue; // this computer is gone byName.put(c.getNode().getNodeName(),c); } Set old = new HashSet(computers.values()); Set used = new HashSet(); updateComputer(this, byName, used); for (Slave s : getSlaves()) updateComputer(s, byName, used); // find out what computers are removed, and kill off all executors. // when all executors exit, it will be removed from the computers map. // so don't remove too quickly old.removeAll(used); for (Computer c : old) { c.kill(); } } getQueue().scheduleMaintenance(); } private void updateComputer(Node n, Map byNameMap, Set used) { Computer c; c = byNameMap.get(n.getNodeName()); if(c==null) { if(n.getNumExecutors()>0) computers.put(n,c=new Computer(n)); } else { c.setNode(n); } used.add(c); } /*package*/ void removeComputer(Computer computer) { synchronized(computers) { Iterator> itr=computers.entrySet().iterator(); while(itr.hasNext()) { if(itr.next().getValue()==computer) { itr.remove(); return; } } } throw new IllegalStateException("Trying to remove unknown computer"); } /** * Gets the snapshot of all the jobs. */ public synchronized List getJobs() { return new ArrayList(jobs.values()); } /** * Gets the snapshot of all the projects. */ public synchronized List getProjects() { List r = new ArrayList(); for (Job job : jobs.values()) { if(job instanceof Project) r.add((Project)job); } return r; } /** * Gets the names of all the {@link Job}s. */ public synchronized Collection getJobNames() { return new AbstractList() { private final List jobs = getJobs(); public String get(int index) { return jobs.get(index).getName(); } public int size() { return jobs.size(); } }; } /** * Every job belongs to us. * * @deprecated * why are you calling a method that always return true? */ @Deprecated public boolean containsJob(Job job) { return true; } public synchronized JobCollection getView(String name) { if(views!=null) { for (View v : views) { if(v.getViewName().equals(name)) return v; } } if(this.getViewName().equals(name)) return this; else return null; } /** * Gets the read-only list of all {@link JobCollection}s. */ public synchronized JobCollection[] getViews() { if(views==null) views = new ArrayList(); JobCollection[] r = new JobCollection[views.size()+1]; views.toArray(r); // sort Views and put "all" at the very beginning r[r.length-1] = r[0]; Arrays.sort(r,1,r.length,JobCollection.SORTER); r[0] = this; return r; } public synchronized void deleteView(View view) throws IOException { if(views!=null) { views.remove(view); save(); } } public String getViewName() { return "All"; } /** * Gets the read-only list of all {@link Computer}s. */ public Computer[] getComputers() { synchronized(computers) { Computer[] r = computers.values().toArray(new Computer[computers.size()]); Arrays.sort(r,new Comparator() { public int compare(Computer lhs, Computer rhs) { if(lhs.getNode()==Hudson.this) return -1; if(rhs.getNode()==Hudson.this) return 1; return lhs.getNode().getNodeName().compareTo(rhs.getNode().getNodeName()); } }); return r; } } public Computer getComputer(String name) { synchronized(computers) { for (Computer c : computers.values()) { if(c.getNode().getNodeName().equals(name)) return c; } } return null; } public Queue getQueue() { return queue; } public String getDisplayName() { return "Hudson"; } public List getJDKs() { if(jdks==null) jdks = new ArrayList(); return jdks; } /** * Gets the JDK installation of the given name, or returns null. */ public JDK getJDK(String name) { for (JDK j : getJDKs()) { if(j.getName().equals(name)) return j; } return null; } /** * Gets the slave node of the give name, hooked under this Hudson. */ public Slave getSlave(String name) { for (Slave s : getSlaves()) { if(s.getNodeName().equals(name)) return s; } return null; } public List getSlaves() { return Collections.unmodifiableList(slaves); } /** * Gets the system default quiet period. */ public int getQuietPeriod() { return quietPeriod!=null ? quietPeriod : 5; } /** * @deprecated * Why are you calling a method that always returns ""? * Perhaps you meant {@link #getRootUrl()}. */ public String getUrl() { return ""; } /** * Gets the absolute URL of Hudson, * such as "http://localhost/hudson/". * *

* Also note that when serving user requests from HTTP, you should always use * {@link HttpServletRequest} to determine the full URL, instead of using this * (this is because one host may have multiple names, and {@link HttpServletRequest} * accurately represents what the current user used.) * *

* This information is rather only meant to be useful for sending out messages * via non-HTTP channels, like SMTP or IRC, with a link back to Hudson website. * * @return * This method returns null if this parameter is not configured by the user. * The caller must gracefully deal with this situation. * The returned URL will always have the trailing '/'. * @since 1.66 */ public String getRootUrl() { // for compatibility. the actual data is stored in Mailer return Mailer.DESCRIPTOR.getUrl(); } public File getRootDir() { return root; } public boolean isUseSecurity() { return useSecurity; } public void setUseSecurity(boolean useSecurity) { this.useSecurity = useSecurity; } /** * Returns true if Hudson is quieting down. *

* No further jobs will be executed unless it * can be finished while other current pending builds * are still in progress. */ public boolean isQuietingDown() { return isQuietingDown; } /** * Returns true if the container initiated the termination of the web application. */ public boolean isTerminating() { return terminating; } /** * Gets the job of the given name. * * @return null * if such a project doesn't exist. */ public synchronized Job getJob(String name) { return jobs.get(name); } /** * Gets the user of the given name. * * @return * This method returns a non-null object for any user name, without validation. */ public User getUser(String name) { return User.get(name); } /** * Creates a new job. * * @throws IllegalArgumentException * if the project of the given name already exists. */ public synchronized Job createProject( JobDescriptor type, String name ) throws IOException { if(jobs.containsKey(name)) throw new IllegalArgumentException(); Job job; try { job = type.newInstance(name); } catch (Exception e) { throw new IllegalArgumentException(e); } job.save(); jobs.put(name,job); return job; } /** * Called in response to {@link Job#doDoDelete(StaplerRequest, StaplerResponse)} */ /*package*/ void deleteJob(Job job) throws IOException { synchronized(jobListeners) { for (JobListener l : jobListeners) l.onDeleted(job); } jobs.remove(job.getName()); if(views!=null) { for (View v : views) { synchronized(v) { v.jobNames.remove(job.getName()); } } save(); } } /** * Called by {@link Job#renameTo(String)} to update relevant data structure. * assumed to be synchronized on Hudson by the caller. */ /*package*/ void onRenamed(Job job, String oldName, String newName) throws IOException { jobs.remove(oldName); jobs.put(newName,job); if(views!=null) { for (View v : views) { synchronized(v) { if(v.jobNames.remove(oldName)) v.jobNames.add(newName); } } save(); } } public FingerprintMap getFingerprintMap() { return fingerprintMap; } // if no fingrer print matches, display "not found page". public Object getFingerprint( String md5sum ) throws IOException { Fingerprint r = fingerprintMap.get(md5sum); if(r==null) return new NoFingerprintMatch(md5sum); else return r; } /** * Gets a {@link Fingerprint} object if it exists. * Otherwise null. */ public Fingerprint _getFingerprint( String md5sum ) throws IOException { return fingerprintMap.get(md5sum); } /** * The file we save our configuration. */ private XmlFile getConfigFile() { return new XmlFile(XSTREAM, new File(root,"config.xml")); } public int getNumExecutors() { return numExecutors; } public Mode getMode() { return Mode.NORMAL; } private synchronized void load() throws IOException { XmlFile cfg = getConfigFile(); if(cfg.exists()) cfg.unmarshal(this); File projectsDir = new File(root,"jobs"); if(!projectsDir.isDirectory() && !projectsDir.mkdirs()) { if(projectsDir.exists()) throw new IOException(projectsDir+" is not a directory"); throw new IOException("Unable to create "+projectsDir+"\nPermission issue? Please create this directory manually."); } File[] subdirs = projectsDir.listFiles(new FileFilter() { public boolean accept(File child) { return child.isDirectory(); } }); jobs.clear(); for (File subdir : subdirs) { try { Job p = Job.load(this,subdir); jobs.put(p.getName(), p); } catch (IOException e) { e.printStackTrace(); // TODO: logging } } } /** * Save the settings to a file. */ public synchronized void save() throws IOException { getConfigFile().write(this); } /** * Called to shut down the system. */ public void cleanUp() { terminating = true; synchronized(computers) { for( Computer c : computers.values() ) c.interrupt(); } ExternalJob.reloadThread.interrupt(); Trigger.timer.cancel(); if(pluginManager!=null) // be defensive. there could be some ugly timing related issues pluginManager.stop(); getQueue().save(); } // // // actions // // /** * Accepts submission from the configuration page. */ public synchronized void doConfigSubmit( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { try { if(!Hudson.adminCheck(req,rsp)) return; req.setCharacterEncoding("UTF-8"); useSecurity = req.getParameter("use_security")!=null; numExecutors = Integer.parseInt(req.getParameter("numExecutors")); quietPeriod = Integer.parseInt(req.getParameter("quiet_period")); systemMessage = Util.nullify(req.getParameter("system_message")); {// update slave list List newSlaves = new ArrayList(); String[] names = req.getParameterValues("slave_name"); String[] descriptions = req.getParameterValues("slave_description"); String[] executors = req.getParameterValues("slave_executors"); String[] cmds = req.getParameterValues("slave_command"); String[] rfs = req.getParameterValues("slave_remoteFS"); String[] lfs = req.getParameterValues("slave_localFS"); String[] mode = req.getParameterValues("slave_mode"); if(names!=null && descriptions!=null && executors!=null && cmds!=null && rfs!=null && lfs!=null && mode!=null) { int len = Util.min(names.length,descriptions.length,executors.length,cmds.length,rfs.length, lfs.length, mode.length); for(int i=0;i d : BuildStep.BUILDERS ) result &= d.configure(req); for( Descriptor d : BuildStep.PUBLISHERS ) result &= d.configure(req); for( Descriptor d : BuildWrappers.WRAPPERS ) result &= d.configure(req); for( Descriptor scmd : SCMS.SCMS ) result &= scmd.configure(req); for( Descriptor d : Triggers.TRIGGERS ) result &= d.configure(req); save(); if(result) rsp.sendRedirect("."); // go to the top page else rsp.sendRedirect("configure"); // back to config } catch (FormException e) { sendError(e,req,rsp); } } /** * Accepts the new description. */ public synchronized void doSubmitDescription( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { if(!Hudson.adminCheck(req,rsp)) return; req.setCharacterEncoding("UTF-8"); systemMessage = req.getParameter("description"); save(); rsp.sendRedirect("."); } public synchronized void doQuietDown( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { if(!Hudson.adminCheck(req,rsp)) return; isQuietingDown = true; rsp.sendRedirect2("."); } public synchronized void doCancelQuietDown( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { if(!Hudson.adminCheck(req,rsp)) return; isQuietingDown = false; getQueue().scheduleMaintenance(); rsp.sendRedirect2("."); } public synchronized Job doCreateJob( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { if(!Hudson.adminCheck(req,rsp)) return null; req.setCharacterEncoding("UTF-8"); String name = req.getParameter("name").trim(); String jobType = req.getParameter("type"); String mode = req.getParameter("mode"); try { checkGoodName(name); } catch (ParseException e) { sendError(e,req,rsp); return null; } if(getJob(name)!=null) { sendError("A job already exists with the name '"+name+"'",req,rsp); return null; } if(mode==null) { rsp.sendError(HttpServletResponse.SC_BAD_REQUEST); return null; } Job result; if(mode.equals("newJob")) { if(jobType ==null) { // request forged? rsp.sendError(HttpServletResponse.SC_BAD_REQUEST); return null; } // redirect to the project config screen result = createProject(Jobs.getDescriptor(jobType), name); } else { Job src = getJob(req.getParameter("from")); if(src==null) { rsp.sendError(HttpServletResponse.SC_BAD_REQUEST); return null; } result = createProject((JobDescriptor)src.getDescriptor(),name); // copy config Util.copyFile(src.getConfigFile(),result.getConfigFile()); // reload from the new config result = Job.load(this,result.getRootDir()); result.nextBuildNumber = 1; // reset the next build number jobs.put(name,result); } synchronized(jobListeners) { for (JobListener l : jobListeners) l.onCreated(result); } rsp.sendRedirect2(req.getContextPath()+'/'+result.getUrl()+"configure"); return result; } public synchronized void doCreateView( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { if(!Hudson.adminCheck(req,rsp)) return; req.setCharacterEncoding("UTF-8"); String name = req.getParameter("name"); try { checkGoodName(name); } catch (ParseException e) { sendError(e, req, rsp); return; } View v = new View(this, name); if(views==null) views = new Vector(); views.add(v); save(); // redirect to the config screen rsp.sendRedirect2("./"+v.getUrl()+"configure"); } /** * Check if the given name is suitable as a name * for job, view, etc. * * @throws ParseException * if the given name is not good */ public static void checkGoodName(String name) throws ParseException { if(name==null || name.length()==0) throw new ParseException("No name is specified",0); for( int i=0; i".indexOf(ch)!=-1) throw new ParseException("'"+ch+"' is an unsafe character",i); } // looks good } /** * Called once the user logs in. Just forward to the top page. */ public synchronized void doLoginEntry( StaplerRequest req, StaplerResponse rsp ) throws IOException { rsp.sendRedirect2(req.getContextPath()+"/"); } /** * Called once the user logs in. Just forward to the top page. */ public synchronized void doLogout( StaplerRequest req, StaplerResponse rsp ) throws IOException { HttpSession session = req.getSession(false); if(session!=null) session.invalidate(); rsp.sendRedirect2(req.getContextPath()+"/"); } /** * Reloads the configuration. */ public synchronized void doReload( StaplerRequest req, StaplerResponse rsp ) throws IOException { if(!Hudson.adminCheck(req,rsp)) return; load(); rsp.sendRedirect2(req.getContextPath()+"/"); } /** * Uploads a plugin. */ public void doUploadPlugin( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { try { if(!Hudson.adminCheck(req,rsp)) return; ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); // Parse the request FileItem fileItem = (FileItem) upload.parseRequest(req).get(0); String fileName = Util.getFileName(fileItem.getName()); if(!fileName.endsWith(".hpi")) { sendError(fileName+" is not a Hudson plugin",req,rsp); return; } fileItem.write(new File(getPluginManager().rootDir, fileName)); fileItem.delete(); rsp.sendRedirect2("managePlugins"); } catch (IOException e) { throw e; } catch (Exception e) {// grrr. fileItem.write throws this throw new ServletException(e); } } /** * Do a finger-print check. */ public void doDoFingerprintCheck( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { try { ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); // Parse the request @SuppressWarnings("unchecked") // pre-generics lib List items = upload.parseRequest(req); rsp.sendRedirect2(req.getContextPath()+"/fingerprint/"+ getDigestOf(items.get(0).getInputStream())+'/'); // if an error occur and we fail to do this, it will still be cleaned up // when GC-ed. for (FileItem item : items) item.delete(); } catch (FileUploadException e) { throw new ServletException(e); // I'm not sure what the implication of this } } public String getDigestOf(InputStream source) throws IOException, ServletException { try { MessageDigest md5 = MessageDigest.getInstance("MD5"); DigestInputStream in =new DigestInputStream(source,md5); byte[] buf = new byte[8192]; try { while(in.read(buf)>0) ; // simply discard the input } finally { in.close(); } return Util.toHexString(md5.digest()); } catch (NoSuchAlgorithmException e) { throw new ServletException(e); // impossible } } /** * Serves static resources without the "Last-Modified" header to work around * a bug in Firefox. * *

* See https://bugzilla.mozilla.org/show_bug.cgi?id=89419 */ public void doNocacheImages( StaplerRequest req, StaplerResponse rsp ) throws IOException { String path = req.getRestOfPath(); if(path.length()==0) path = "/"; if(path.indexOf("..")!=-1 || path.length()<1) { // don't serve anything other than files in the artifacts dir rsp.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } File f = new File(req.getServletContext().getRealPath("/images"),path.substring(1)); if(!f.exists()) { rsp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } if(f.isDirectory()) { // listing not allowed rsp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } FileInputStream in = new FileInputStream(f); // serve the file String contentType = req.getServletContext().getMimeType(f.getPath()); rsp.setContentType(contentType); rsp.setContentLength((int)f.length()); byte[] buf = new byte[1024]; int len; while((len=in.read(buf))>0) rsp.getOutputStream().write(buf,0,len); in.close(); } /** * For debugging. Expose URL to perfrom GC. */ public void doGc( StaplerRequest req, StaplerResponse rsp ) throws IOException { System.gc(); rsp.setStatus(HttpServletResponse.SC_OK); rsp.setContentType("text/plain"); rsp.getWriter().println("GCed"); } /** * For system diagnostics. * Run arbitraary Groovy script. */ public void doScript( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { if(!adminCheck(req,rsp)) return; // ability to run arbitrary script is dangerous String text = req.getParameter("script"); if(text!=null) { GroovyShell shell = new GroovyShell(); StringWriter out = new StringWriter(); PrintWriter pw = new PrintWriter(out); shell.setVariable("out", pw); try { Object output = shell.evaluate(text); if(output!=null) pw.println("Result: "+output); } catch (Throwable t) { t.printStackTrace(pw); } req.setAttribute("output",out); } req.getView(this,"_script.jelly").forward(req,rsp); } /** * Changes the icon size by changing the cookie */ public void doIconSize( StaplerRequest req, StaplerResponse rsp ) throws IOException { rsp.addCookie(new Cookie("iconSize",req.getQueryString())); String ref = req.getHeader("Referer"); if(ref==null) ref="."; rsp.sendRedirect2(ref); } public void doFingerprintCleanup( StaplerRequest req, StaplerResponse rsp ) throws IOException { FingerprintCleanupThread.invoke(); rsp.setStatus(HttpServletResponse.SC_OK); rsp.setContentType("text/plain"); rsp.getWriter().println("Invoked"); } public void doWorkspaceCleanup( StaplerRequest req, StaplerResponse rsp ) throws IOException { WorkspaceCleanupThread.invoke(); rsp.setStatus(HttpServletResponse.SC_OK); rsp.setContentType("text/plain"); rsp.getWriter().println("Invoked"); } /** * Checks if the path is a valid path. */ public void doCheckLocalFSRoot( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { // this can be used to check the existence of a file on the server, so needs to be protected new FormFieldValidator(req,rsp,true) { public void check() throws IOException, ServletException { File f = getFileParameter("value"); if(f.isDirectory()) {// OK ok(); } else {// nope if(f.exists()) { error(f+" is not a directory"); } else { error("No such directory: "+f); } } } }.process(); } /** * Checks if the JAVA_HOME is a valid JAVA_HOME path. */ public void doJavaHomeCheck( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { // this can be used to check the existence of a file on the server, so needs to be protected new FormFieldValidator(req,rsp,true) { public void check() throws IOException, ServletException { File f = getFileParameter("value"); if(!f.isDirectory()) { error(f+" is not a directory"); return; } File toolsJar = new File(f,"lib/tools.jar"); if(!toolsJar.exists()) { error(f+" doesn't look like a JDK directory"); return; } ok(); } }.process(); } public static boolean isWindows() { return File.pathSeparatorChar==';'; } /** * Returns all {@code CVSROOT} strings used in the current Hudson installation. * *

* Ideally this shouldn't be defined in here * but EL doesn't provide a convenient way of invoking a static function, * so I'm putting it here for now. */ public Set getAllCvsRoots() { Set r = new TreeSet(); for( Project p : getProjects() ) { SCM scm = p.getScm(); if (scm instanceof CVSSCM) { CVSSCM cvsscm = (CVSSCM) scm; r.add(cvsscm.getCvsRoot()); } } return r; } public static boolean adminCheck(StaplerRequest req,StaplerResponse rsp) throws IOException { if(!getInstance().isUseSecurity()) return true; if(req.isUserInRole("admin")) return true; rsp.sendError(StaplerResponse.SC_FORBIDDEN); return false; } /** * Live view of recent {@link LogRecord}s produced by Hudson. */ public static List logRecords = Collections.emptyList(); // initialized to dummy value to avoid NPE /** * Thread-safe reusable {@link XStream}. */ private static final XStream XSTREAM = new XStream2(); static { XSTREAM.alias("hudson",Hudson.class); XSTREAM.alias("slave",Slave.class); XSTREAM.alias("view",View.class); XSTREAM.alias("jdk",JDK.class); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy