Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* *****************************************************************************
*
* Copyright (c) 2004-2013 Oracle Corporation.
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
* Kohsuke Kawaguchi, Winston Prakash, Nikita Levyankov, Erik Ramfelt, Koichi
* Fujikawa, Seiji Sogabe, Stephen Connolly, Tom Huybrechts, Alan Harder, Duncan
* Mills
*
******************************************************************************
*/
package hudson.model;
import com.thoughtworks.xstream.XStream;
import hudson.BulkChange;
import hudson.DNSMultiCast;
import hudson.DescriptorExtensionList;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.ExtensionListView;
import hudson.ExtensionPoint;
import hudson.FilePath;
import hudson.Functions;
import hudson.GlobalMessage;
import hudson.Launcher;
import hudson.Launcher.LocalLauncher;
import hudson.LocalPluginManager;
import hudson.Lookup;
import hudson.Plugin;
import hudson.PluginManager;
import hudson.PluginWrapper;
import hudson.ProxyConfiguration;
import hudson.StructuredForm;
import hudson.TcpSlaveAgentListener;
import hudson.UDPBroadcastThread;
import hudson.Util;
import static hudson.Util.fixEmpty;
import static hudson.Util.fixNull;
import hudson.XmlFile;
import hudson.cli.CLICommand;
import hudson.cli.CliEntryPoint;
import hudson.cli.CliManagerImpl;
import hudson.cli.declarative.CLIMethod;
import hudson.cli.declarative.CLIResolver;
import hudson.init.InitMilestone;
import static hudson.init.InitMilestone.*;
import hudson.init.InitReactorListener;
import hudson.init.InitStrategy;
import hudson.lifecycle.Lifecycle;
import hudson.lifecycle.RestartNotSupportedException;
import hudson.logging.LogRecorderManager;
import hudson.markup.MarkupFormatter;
import hudson.model.Descriptor.FormException;
import hudson.model.labels.LabelAtom;
import hudson.model.listeners.ItemListener;
import hudson.model.listeners.SCMListener;
import hudson.model.listeners.SaveableListener;
import hudson.remoting.Channel;
import hudson.remoting.LocalChannel;
import hudson.remoting.VirtualChannel;
import hudson.scm.RepositoryBrowser;
import hudson.scm.SCM;
import hudson.search.CollectionSearchIndex;
import hudson.search.SearchIndexBuilder;
import hudson.security.*;
import hudson.security.csrf.CrumbIssuer;
import hudson.slaves.Cloud;
import hudson.slaves.ComputerListener;
import hudson.slaves.DumbSlave;
import hudson.slaves.NodeDescriptor;
import hudson.slaves.NodeList;
import hudson.slaves.NodeProperty;
import hudson.slaves.NodePropertyDescriptor;
import hudson.slaves.NodeProvisioner;
import hudson.slaves.OfflineCause;
import hudson.slaves.RetentionStrategy;
import hudson.tasks.BuildWrapper;
import hudson.tasks.Builder;
import hudson.tasks.Mailer;
import hudson.tasks.Publisher;
import hudson.triggers.Trigger;
import hudson.triggers.TriggerDescriptor;
import hudson.util.AdministrativeError;
import hudson.util.CaseInsensitiveComparator;
import hudson.util.ClockDifference;
import hudson.util.CopyOnWriteList;
import hudson.util.CopyOnWriteMap;
import hudson.util.DaemonThreadFactory;
import hudson.util.DescribableList;
import hudson.util.FormValidation;
import hudson.util.Futures;
import hudson.util.HudsonIsLoading;
import hudson.util.HudsonIsRestarting;
import hudson.util.Iterators;
import hudson.util.Memoizer;
import hudson.util.MultipartFormDataParser;
import hudson.util.RemotingDiagnostics;
import hudson.util.RemotingDiagnostics.HeapDump;
import hudson.util.Service;
import hudson.util.StreamTaskListener;
import hudson.util.VersionNumber;
import hudson.util.XStream2;
import hudson.views.DefaultMyViewsTabBar;
import hudson.views.DefaultViewsTabBar;
import hudson.views.MyViewsTabBar;
import hudson.views.ViewsTabBar;
import hudson.widgets.Widget;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.BindException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.Collator;
import java.text.NumberFormat;
import java.text.ParseException;
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.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.crypto.SecretKey;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import static javax.servlet.http.HttpServletResponse.*;
import net.sf.json.JSONObject;
import org.antlr.runtime.RecognitionException;
import org.apache.commons.jelly.JellyException;
import org.apache.commons.jelly.Script;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.commons.logging.LogFactory;
import org.eclipse.hudson.WebAppController;
import org.eclipse.hudson.plugins.PluginCenter;
import org.eclipse.hudson.script.ScriptSupport;
import org.eclipse.hudson.security.HudsonSecurityEntitiesHolder;
import org.eclipse.hudson.security.HudsonSecurityManager;
import org.eclipse.hudson.security.team.Team;
import org.eclipse.hudson.security.team.TeamManager;
import org.jvnet.hudson.reactor.Executable;
import org.jvnet.hudson.reactor.Milestone;
import org.jvnet.hudson.reactor.Reactor;
import org.jvnet.hudson.reactor.ReactorException;
import org.jvnet.hudson.reactor.ReactorListener;
import org.jvnet.hudson.reactor.Task;
import org.jvnet.hudson.reactor.TaskBuilder;
import org.jvnet.hudson.reactor.TaskGraphBuilder;
import org.jvnet.hudson.reactor.TaskGraphBuilder.Handle;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
import org.kohsuke.stapler.Ancestor;
import org.kohsuke.stapler.HttpRedirect;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.MetaClass;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerFallback;
import org.kohsuke.stapler.StaplerProxy;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.WebApp;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import org.kohsuke.stapler.framework.adjunct.AdjunctManager;
import org.kohsuke.stapler.jelly.JellyClassLoaderTearOff;
import org.kohsuke.stapler.jelly.JellyRequestDispatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.xml.sax.InputSource;
/**
* Root object of the system.
*
* @author Kohsuke Kawaguchi
* @author Nikita Levyankov
*/
@ExportedBean
public final class Hudson extends Node implements ItemGroup, StaplerProxy, StaplerFallback, ViewGroup, AccessControlled, DescriptorByNameOwner {
private transient Logger logger = LoggerFactory.getLogger(Hudson.class);
private transient final Queue queue;
/**
* Stores various objects scoped to {@link Hudson}.
*/
public transient final Lookup lookup = new Lookup();
/**
* {@link Computer}s in this Hudson system. Read-only.
*/
private transient final Map computers = new CopyOnWriteMap.Hash();
/**
* We update this field to the current version of Hudson whenever we save
* {@code config.xml}. This can be used to detect when an upgrade happens
* from one version to next.
*
*
* Since this field is introduced starting 1.301, "1.0" is used to represent
* every version up to 1.300. This value may also include non-standard
* versions like "1.301-SNAPSHOT" or "?", etc., so parsing needs to be done
* with a care.
*
* @since 1.301
*/
// this field needs to be at the very top so that other components can look at this value even during unmarshalling
private String version = "1.0";
/**
* Number of executors of the master node.
*/
private int numExecutors = 2;
/**
* Job allocation strategy.
*/
private Mode mode = Mode.NORMAL;
/**
* Message displayed in the top page.
*/
private String systemMessage;
/**
* Optional privacy message to be printed at the base of each page, this can
* be used for CopyRight, Confidentiality information and so forth
* Introduced Hudson 3.0.1
*/
private String privacyMessage;
/**
* Optional identifier for the instance to be printed on each page
* Introduced Hudson 3.0.1
*/
private String instanceTag;
private static transient final String HUDSON_WORKSPACES_PROPERTY_KEY = "HUDSON_WORKSPACES";
/**
* Workspace root dir which could be configured by setting HUDSON_WORKSPACES
* property.
*/
private volatile String configuredWorkspaceRoot;
/**
* Root directory of the system.
*/
public transient final File root;
/**
* Where are we in the initialization?
*/
private transient volatile InitMilestone initLevel = InitMilestone.STARTED;
/**
* All {@link Item}s keyed by their {@link Item#getName() name}s.
*/
/*package*/ transient final Map items = new CopyOnWriteMap.Tree(CaseInsensitiveComparator.INSTANCE);
/**
* A cache of top level items
*/
private transient final TopLevelItemsCache itemsCache = new TopLevelItemsCache();
/**
* The sole instance.
*/
private static Hudson theInstance;
private transient volatile boolean isQuietingDown;
private transient volatile boolean terminating;
private transient volatile boolean safeRestarting;
private List jdks = new ArrayList();
private transient volatile DependencyGraph dependencyGraph;
/**
* Currently active Views tab bar.
*/
private volatile ViewsTabBar viewsTabBar = new DefaultViewsTabBar();
/**
* Currently active My Views tab bar.
*/
private volatile MyViewsTabBar myViewsTabBar = new DefaultMyViewsTabBar();
/**
* Script support (if available)
*/
private volatile ScriptSupport scriptSupport;
private Boolean allowUnsecuredAction = false;
private Boolean allowCli = false;
/**
* All {@link ExtensionList} keyed by their
* {@link ExtensionList#extensionType}.
*/
private transient final Memoizer extensionLists = new Memoizer() {
public ExtensionList compute(Class key) {
return ExtensionList.create(Hudson.this, key);
}
};
/**
* All {@link DescriptorExtensionList} keyed by their
* {@link DescriptorExtensionList#describableType}.
*/
private transient final Memoizer descriptorLists = new Memoizer() {
public DescriptorExtensionList compute(Class key) {
return DescriptorExtensionList.createDescriptorList(Hudson.this, key);
}
};
/**
* Active {@link Cloud}s.
*/
public final CloudList clouds = new CloudList(this);
public static class CloudList extends DescribableList> {
public CloudList(Hudson h) {
super(h);
}
// needed for XStream deserialization
public CloudList() {
}
public Cloud getByName(String name) {
for (Cloud c : this) {
if (c.name.equals(name)) {
return c;
}
}
return null;
}
@Override
protected void onModified() throws IOException {
super.onModified();
Hudson.getInstance().trimLabels();
}
}
/**
* 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.
*
* The field name should be really {@code nodes}, but again the backward
* compatibility prevents us from renaming.
*/
private volatile NodeList slaves;
/**
* Quiet period.
*
* This is {@link Integer} so that we can initialize it to '5' for upgrading
* users.
*/
/*package*/ Integer quietPeriod;
/**
* Global default for {@link AbstractProject#getScmCheckoutRetryCount()}
*/
/*package*/ int scmCheckoutRetryCount;
/**
* {@link View}s.
*/
private final CopyOnWriteArrayList views = new CopyOnWriteArrayList();
/**
* Name of the primary view.
*
* Start with null, so that we can upgrade pre-1.269 data well.
*
* @since 1.269
*/
private volatile String primaryView;
private transient final FingerprintMap fingerprintMap = new FingerprintMap();
/**
* Loaded plugins.
*/
public transient final PluginManager pluginManager;
private transient PluginCenter pluginCenter;
public transient volatile TcpSlaveAgentListener tcpSlaveAgentListener;
private transient UDPBroadcastThread udpBroadcastThread;
private transient DNSMultiCast dnsMultiCast;
/**
* List of registered {@link ItemListener}s.
*
* @deprecated as of 1.286
*/
private transient final CopyOnWriteList itemListeners = ExtensionListView.createCopyOnWriteList(ItemListener.class);
/**
* List of registered {@link SCMListener}s.
*/
private transient final CopyOnWriteList scmListeners = new CopyOnWriteList();
/**
* List of registered {@link ComputerListener}s.
*
* @deprecated as of 1.286
*/
private transient final CopyOnWriteList computerListeners = ExtensionListView.createCopyOnWriteList(ComputerListener.class);
/**
* Whitespace-separated labels assigned to the master as a {@link Node}.
*/
private String label = "";
/**
* {@link hudson.security.csrf.CrumbIssuer}
*/
private volatile CrumbIssuer crumbIssuer;
/**
* All labels known to Hudson. This allows us to reuse the same label
* instances as much as possible, even though that's not a strict
* requirement.
*/
private transient final ConcurrentHashMap labels = new ConcurrentHashMap();
/**
* Load statistics of the entire system.
*/
@Exported
public transient final OverallLoadStatistics overallLoad = new OverallLoadStatistics();
/**
* {@link NodeProvisioner} that reacts to {@link OverallLoadStatistics}.
*/
public transient final NodeProvisioner overallNodeProvisioner = new NodeProvisioner(null, overallLoad);
public transient final ServletContext servletContext;
/**
* Transient action list. Useful for adding navigation items to the
* navigation bar on the left.
*/
private transient final List actions = new CopyOnWriteArrayList();
/**
* List of master node properties
*/
private DescribableList, NodePropertyDescriptor> nodeProperties = new DescribableList, NodePropertyDescriptor>(this);
/**
* List of global properties
*/
private DescribableList, NodePropertyDescriptor> globalNodeProperties = new DescribableList, NodePropertyDescriptor>(this);
/**
* {@link AdministrativeMonitor}s installed on this system.
*
* @see AdministrativeMonitor
*/
public transient final List administrativeMonitors = getExtensionList(AdministrativeMonitor.class);
/*package*/ final CopyOnWriteArraySet disabledAdministrativeMonitors = new CopyOnWriteArraySet();
/**
* Widgets on Hudson.
*/
private transient final List widgets = getExtensionList(Widget.class);
/**
* Use Blue ball instead of the default green ball
*/
private Boolean useBlueBall = false;
/**
* {@link AdjunctManager}
*/
private transient final AdjunctManager adjuncts;
/**
* Code that handles {@link ItemGroup} work.
*/
private transient final ItemGroupMixIn itemGroupMixIn = new ItemGroupMixIn(this, this) {
@Override
protected void add(TopLevelItem item) {
assert item.getRootDir().exists();
final LazyTopLevelItem lzItem = Items.newLazyTopLevelItem(item);
items.put(item.getName(), lzItem);
}
@Override
protected File getRootDirFor(String name) {
return Hudson.this.getRootDirFor(name);
}
/**
* send the browser to the config page use View to trim
* view/{default-view} from URL if possible
*/
@Override
protected String redirectAfterCreateItem(StaplerRequest req, TopLevelItem result) throws IOException {
String redirect = result.getUrl() + "configure";
List ancestors = req.getAncestors();
for (int i = ancestors.size() - 1; i >= 0; i--) {
Object o = ancestors.get(i).getObject();
if (o instanceof View) {
redirect = req.getContextPath() + '/' + ((View) o).getUrl() + redirect;
break;
}
}
return redirect;
}
};
public static class HudsonDateFormat extends FastDateFormat {
public HudsonDateFormat(String format) {
super(format, TimeZone.getDefault(), Locale.getDefault());
}
}
@CLIResolver
public static Hudson getInstance() {
return theInstance;
}
private transient final UpdateCenter updateCenter = new UpdateCenter();
/**
* True if the user opted out from the statistics tracking. We'll never send
* anything if this is true.
*/
private Boolean noUsageStatistics;
/**
* Number of times Hudson has been started in this JVM.
*/
private static int invocationCount = 0;
/**
* HTTP proxy configuration.
*/
public transient volatile ProxyConfiguration proxy;
/**
* Bound to "/log".
*/
private transient final LogRecorderManager log = new LogRecorderManager();
public Hudson(File root, ServletContext context) throws IOException, InterruptedException, ReactorException {
this(root, context, null, false);
}
public Hudson(File root, ServletContext context, PluginManager pluginManager) throws IOException, InterruptedException, ReactorException {
this(root, context, pluginManager, false);
}
/**
* @param pluginManager If non-null, use existing plugin manager. create a
* new one.
*/
public Hudson(File root, ServletContext context, PluginManager pluginManager, boolean restart) throws IOException, InterruptedException, ReactorException {
// As hudson is starting, grant this process full control
HudsonSecurityManager.grantFullControl();
try {
this.root = root;
this.servletContext = context;
computeVersion(context);
if (theInstance != null) {
if (!restart) {
throw new IllegalStateException("second instance");
}
}
theInstance = this;
invocationCount++;
// doing this early allows InitStrategy to set environment upfront
final InitStrategy is = InitStrategy.get(Thread.currentThread().getContextClassLoader());
// In case reinitializing for soft restart, cancel all events
if (Trigger.timer != null) {
Trigger.timer.cancel();
Trigger.timer.purge();
}
Trigger.timer = new Timer("Hudson cron thread " + invocationCount);
queue = new Queue(CONSISTENT_HASH ? LoadBalancer.CONSISTENT_HASH : LoadBalancer.DEFAULT);
try {
dependencyGraph = DependencyGraph.EMPTY;
} catch (InternalError e) {
if (e.getMessage().contains("window server")) {
throw new Error("Looks like the server runs without X. Please specify -Djava.awt.headless=true as JVM option", e);
}
throw e;
}
try {
proxy = new ProxyConfiguration(getRootDir());
} catch (IOException e) {
logger.error("Failed to load proxy configuration", e);
}
if (pluginManager == null) {
pluginManager = new LocalPluginManager(this);
}
this.pluginManager = pluginManager;
pluginCenter = new PluginCenter(root);
// JSON binding needs to be able to see all the classes from all the plugins
WebApp.get(servletContext).setClassLoader(pluginManager.uberClassLoader);
adjuncts = new AdjunctManager(servletContext, pluginManager.uberClassLoader, "adjuncts/" + VERSION_HASH);
// initialization consists of ...
executeReactor(is,
pluginManager.initTasks(is), // loading and preparing plugins
loadTasks(), // load jobs
InitMilestone.ordering() // forced ordering among key milestones
);
if (KILL_AFTER_LOAD) {
System.exit(0);
}
int slaveAgentPort = HudsonSecurityEntitiesHolder.getHudsonSecurityManager().getSlaveAgentPort();
if (slaveAgentPort != -1) {
try {
tcpSlaveAgentListener = new TcpSlaveAgentListener(slaveAgentPort);
} catch (BindException e) {
new AdministrativeError(getClass().getName() + ".tcpBind",
"Failed to listen to incoming slave connection",
"Failed to listen to incoming slave connection. Change the port number to solve the problem.", e);
}
} else {
tcpSlaveAgentListener = null;
}
try {
udpBroadcastThread = new UDPBroadcastThread(this);
udpBroadcastThread.start();
} catch (IOException e) {
logger.warn("Faild to broadcast over UDP", e);
}
dnsMultiCast = new DNSMultiCast(this);
updateComputerList();
// master is online now
{
Computer c = toComputer();
if (c != null) {
for (ComputerListener cl : ComputerListener.all()) {
cl.onOnline(c, StreamTaskListener.fromStdout());
}
}
}
for (ItemListener l : ItemListener.all()) {
l.onLoaded();
}
if (!ScriptSupport.getAvailableScriptSupports().isEmpty()) {
scriptSupport = ScriptSupport.getAvailableScriptSupports().get(0);
}
} finally {
HudsonSecurityManager.resetFullControl();
}
}
/**
* Executes a reactor.
*
* @param is If non-null, this can be consulted for ignoring some tasks.
* Only used during the initialization of Hudson.
*/
private void executeReactor(final InitStrategy is, TaskBuilder... builders) throws IOException, InterruptedException, ReactorException {
Reactor reactor = new Reactor(builders) {
/**
* Sets the thread name to the task for better diagnostics.
*/
@Override
protected void runTask(Task task) throws Exception {
if (is != null && is.skipInitTask(task)) {
return;
}
// full access in the initialization thread
HudsonSecurityManager.grantFullControl();
String taskName = task.getDisplayName();
Thread t = Thread.currentThread();
String name = t.getName();
if (taskName != null) {
t.setName(taskName);
}
try {
long start = System.currentTimeMillis();
super.runTask(task);
if (LOG_STARTUP_PERFORMANCE) {
logger.info(String.format("Took %dms for %s by %s",
System.currentTimeMillis() - start, taskName, name));
}
} finally {
t.setName(name);
HudsonSecurityManager.resetFullControl();
}
}
};
ExecutorService es;
if (PARALLEL_LOAD) {
es = new ThreadPoolExecutor(
TWICE_CPU_NUM, TWICE_CPU_NUM, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new DaemonThreadFactory());
} else {
es = Executors.newSingleThreadExecutor(new DaemonThreadFactory());
}
try {
reactor.execute(es, buildReactorListener());
} finally {
es.shutdownNow(); // upon a successful return the executor queue should be empty. Upon an exception, we want to cancel all pending tasks
}
}
/**
* Aggregates all the listeners into one and returns it.
*
*
* At this point plugins are not loaded yet, so we fall back to the
* META-INF/services look up to discover implementations. As such there's no
* way for plugins to participate into this process.
*/
private ReactorListener buildReactorListener() throws IOException {
List r = (List) Service.loadInstances(Thread.currentThread().getContextClassLoader(), InitReactorListener.class);
r.add(new ReactorListener() {
public void onTaskStarted(Task t) {
logger.debug("Started {}", t.getDisplayName());
}
public void onTaskCompleted(Task t) {
logger.debug("Completed {}", t.getDisplayName());
}
public void onTaskFailed(Task t, Throwable err, boolean fatal) {
logger.error("Failed " + t.getDisplayName(), err);
}
public void onAttained(Milestone milestone) {
String s = "Attained " + milestone.toString();
if (milestone instanceof InitMilestone) {
initLevel = (InitMilestone) milestone;
s = initLevel.toString();
}
logger.info(s);
}
});
return new ReactorListener.Aggregator(r);
}
public TcpSlaveAgentListener getTcpSlaveAgentListener() {
return tcpSlaveAgentListener;
}
/**
* Makes {@link AdjunctManager} URL-bound. The dummy parameter allows us to
* use different URLs for the same adjunct, for proper cache handling.
*/
public AdjunctManager getAdjuncts(String dummy) {
return adjuncts;
}
/**
* If you are calling this on Hudson something is wrong.
*
* @deprecated
*/
@Deprecated
@Override
public String getNodeName() {
return "";
}
public void setNodeName(String name) {
throw new UnsupportedOperationException(); // not allowed
}
public String getNodeDescription() {
return Messages.Hudson_NodeDescription();
}
@Exported
public String getDescription() {
return systemMessage;
}
public PluginManager getPluginManager() {
return pluginManager;
}
public PluginCenter getPluginCenter() {
return pluginCenter;
}
/**
* @return true if team management is enabled
* @since 3.1.0
*/
public boolean isTeamManagementEnabled() {
return getTeamManager().isTeamManagementEnabled();
}
/**
* TeamManager is returned whether or not Team based authorization is set.
*
* @return TeamManager
* @since 3.1.0
*/
public TeamManager getTeamManager() {
return getSecurityManager().getTeamManager();
}
/**
* Do not use this API, for internal purpose only
*
* @since 3.1.0
*/
public void replaceItem(String oldItemName, String newItemName) {
if (items.containsKey(oldItemName)) {
TopLevelItem item = items.get(oldItemName);
items.remove(oldItemName);
items.put(newItemName, item);
}
}
public HudsonSecurityManager getSecurityManager() {
return HudsonSecurityEntitiesHolder.getHudsonSecurityManager();
}
public UpdateCenter getUpdateCenter() {
return updateCenter;
}
public boolean isUsageStatisticsCollected() {
return noUsageStatistics == null || !noUsageStatistics;
}
public void setNoUsageStatistics(Boolean noUsageStatistics) throws IOException {
this.noUsageStatistics = noUsageStatistics;
save();
}
public View.People getPeople() {
return new View.People(this);
}
/**
* Does this {@link View} has any associated user information recorded?
*/
public boolean hasPeople() {
return View.People.isApplicable(items.values());
}
public Api getApi() {
return new Api(this);
}
/**
* Returns a secret key that survives across container start/stop.
*
* This value is useful for implementing some of the security features.
*/
public String getSecretKey() {
return getSecurityManager().getSecretKey();
}
/**
* Gets {@linkplain #getSecretKey() the secret key} as a key for AES-128.
*
* @since 1.308
*/
public SecretKey getSecretKeyAsAES128() {
return getSecurityManager().getSecretKeyAsAES128();
}
/**
* Gets the SCM descriptor by name. Primarily used for making them
* web-visible.
*/
public Descriptor getScm(String shortClassName) {
return findDescriptor(shortClassName, SCM.all());
}
/**
* Gets the repository browser descriptor by name. Primarily used for making
* them web-visible.
*/
public Descriptor> getRepositoryBrowser(String shortClassName) {
return findDescriptor(shortClassName, RepositoryBrowser.all());
}
/**
* Gets the builder descriptor by name. Primarily used for making them
* web-visible.
*/
public Descriptor getBuilder(String shortClassName) {
return findDescriptor(shortClassName, Builder.all());
}
/**
* Gets the build wrapper descriptor by name. Primarily used for making them
* web-visible.
*/
public Descriptor getBuildWrapper(String shortClassName) {
return findDescriptor(shortClassName, BuildWrapper.all());
}
/**
* Gets the publisher descriptor by name. Primarily used for making them
* web-visible.
*/
public Descriptor getPublisher(String shortClassName) {
return findDescriptor(shortClassName, Publisher.all());
}
/**
* Gets the trigger descriptor by name. Primarily used for making them
* web-visible.
*/
public TriggerDescriptor getTrigger(String shortClassName) {
return (TriggerDescriptor) findDescriptor(shortClassName, Trigger.all());
}
/**
* Gets the retention strategy descriptor by name. Primarily used for making
* them web-visible.
*/
public Descriptor> getRetentionStrategy(String shortClassName) {
return findDescriptor(shortClassName, RetentionStrategy.all());
}
/**
* Gets the {@link JobPropertyDescriptor} by name. Primarily used for making
* them web-visible.
*/
public JobPropertyDescriptor getJobProperty(String shortClassName) {
// combining these two lines triggers javac bug. See issue #610.
Descriptor d = findDescriptor(shortClassName, JobPropertyDescriptor.all());
return (JobPropertyDescriptor) d;
}
/**
* Exposes {@link Descriptor} by its name to URL.
*
* After doing all the {@code getXXX(shortClassName)} methods, I finally
* realized that this just doesn't scale.
*
* @param id Either {@link Descriptor#getId()} (recommended) or the short
* name of a {@link Describable} subtype (for compatibility)
*/
public Descriptor getDescriptor(String id) {
// legacy descriptors that are reigstered manually doesn't show up in getExtensionList, so check them explicitly.
for (Descriptor d : Iterators.sequence(getExtensionList(Descriptor.class), DescriptorExtensionList.listLegacyInstances())) {
String name = d.getId();
if (name.equals(id)) {
return d;
}
if (name.substring(name.lastIndexOf('.') + 1).equals(id)) {
return d;
}
}
return null;
}
/**
* Alias for {@link #getDescriptor(String)}.
*/
public Descriptor getDescriptorByName(String id) {
return getDescriptor(id);
}
/**
* Gets the {@link Descriptor} that corresponds to the given
* {@link Describable} type.
*
* If you have an instance of {@code type} and call
* {@link Describable#getDescriptor()}, you'll get the same instance that
* this method returns.
*/
public Descriptor getDescriptor(Class extends Describable> type) {
for (Descriptor d : getExtensionList(Descriptor.class)) {
if (d.clazz == type) {
return d;
}
}
return null;
}
/**
* Works just like {@link #getDescriptor(Class)} but don't take no for an
* answer.
*
* @throws AssertionError If the descriptor is missing.
* @since 1.326
*/
public Descriptor getDescriptorOrDie(Class extends Describable> type) {
Descriptor d = getDescriptor(type);
if (d == null) {
throw new AssertionError(type + " is missing its descriptor");
}
return d;
}
/**
* Gets the {@link Descriptor} instance in the current Hudson by its type.
*/
public T getDescriptorByType(Class type) {
for (Descriptor d : getExtensionList(Descriptor.class)) {
if (d.getClass() == type) {
return type.cast(d);
}
}
return null;
}
/**
* Gets the {@link SecurityRealm} descriptors by name. Primarily used for
* making them web-visible.
*/
public Descriptor getSecurityRealms(String shortClassName) {
return findDescriptor(shortClassName, SecurityRealm.all());
}
/**
* Finds a descriptor that has the specified name.
*/
private > Descriptor findDescriptor(String shortClassName, Collection extends Descriptor> descriptors) {
String name = '.' + shortClassName;
for (Descriptor d : descriptors) {
if (d.clazz.getName().endsWith(name)) {
return d;
}
}
return null;
}
/**
* Gets all the installed {@link ItemListener}s.
*
* @deprecated as of 1.286. Use {@link ItemListener#all()}.
*/
public CopyOnWriteList getJobListeners() {
return itemListeners;
}
/**
* Gets all the installed {@link SCMListener}s.
*/
public CopyOnWriteList getSCMListeners() {
return scmListeners;
}
/**
* Gets all the installed {@link ComputerListener}s.
*
* @deprecated as of 1.286. Use {@link ComputerListener#all()}.
*/
public CopyOnWriteList getComputerListeners() {
return computerListeners;
}
/**
* 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.getPlugin();
}
/**
* Gets the plugin object from its class.
*
*
* This allows easy storage of plugin information in the plugin singleton
* without every plugin reimplementing the singleton pattern.
*
* @param clazz The plugin class (beware class-loader fun, this will
* probably only work from within the hpi that defines the plugin class, it
* may or may not work in other cases)
*
* @return The plugin instance.
*/
@SuppressWarnings("unchecked")
public
P getPlugin(Class
clazz) {
PluginWrapper p = pluginManager.getPlugin(clazz);
if (p == null) {
return null;
}
return (P) p.getPlugin();
}
/**
* Gets the plugin objects from their super-class.
*
* @param clazz The plugin class (beware class-loader fun)
*
* @return The plugin instances.
*/
public
List
getPlugins(Class
clazz) {
List
result = new ArrayList
();
for (PluginWrapper w : pluginManager.getPlugins(clazz)) {
result.add((P) w.getPlugin());
}
return Collections.unmodifiableList(result);
}
/**
* Synonym to {@link #getNodeDescription()}.
*/
public String getSystemMessage() {
return systemMessage;
}
// Here for backward compatibility 2.x
public MarkupFormatter getMarkupFormatter() {
return getSecurityManager().getMarkupFormatter();
}
// Here for backward compatibility to 2.x
public void setMarkupFormatter(MarkupFormatter markupFormatter) {
getSecurityManager().setMarkupFormatter(markupFormatter);
}
/**
* Sets the system message.
*/
public void setSystemMessage(String message) throws IOException {
this.systemMessage = message;
save();
}
/**
* Get the Privacy Message
*/
public String getPrivacyMessage() {
return privacyMessage;
}
/**
* Sets the privacy message.
*/
public void setPrivacyMessage(String message) throws IOException {
this.privacyMessage = message;
save();
}
/**
* Get the Instance identifier
*/
public String getInstanceTag() {
return instanceTag;
}
/**
* Sets the Instance Identifier.
*/
public void setInstanceTag(String name) throws IOException {
this.instanceTag = name;
save();
}
public FederatedLoginService getFederatedLoginService(String name) {
for (FederatedLoginService fls : FederatedLoginService.all()) {
if (fls.getUrlName().equals(name)) {
return fls;
}
}
return null;
}
public List getFederatedLoginServices() {
return FederatedLoginService.all();
}
public Launcher createLauncher(TaskListener listener) {
return new LocalLauncher(listener).decorateFor(this);
}
private final transient Object updateComputerLock = new Object();
/**
* 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() throws IOException {
// just so that we don't have two code updating computer list at the same time
synchronized (updateComputerLock) {
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 (Node s : getNodes()) {
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();
for (ComputerListener cl : ComputerListener.all()) {
cl.onConfigurationChange();
}
}
private void updateComputer(Node n, Map byNameMap, Set used) {
Computer c;
c = byNameMap.get(n.getNodeName());
if (c != null) {
c.setNode(n); // reuse
} else {
if (n.getNumExecutors() > 0) {
computers.put(n, c = n.createComputer());
if (!n.holdOffLaunchUntilSave && AUTOMATIC_SLAVE_LAUNCH) {
RetentionStrategy retentionStrategy = c.getRetentionStrategy();
if (retentionStrategy != null) {
// if there is a retention strategy, it is responsible for deciding to start the computer
retentionStrategy.start(c);
} else {
// we should never get here, but just in case, we'll fall back to the legacy behaviour
c.connect(true);
}
}
}
}
used.add(c);
}
/*package*/ void removeComputer(Computer computer) {
for (Entry e : computers.entrySet()) {
if (e.getValue() == computer) {
computers.remove(e.getKey());
return;
}
}
throw new IllegalStateException("Trying to remove unknown computer");
}
public String getFullName() {
return "";
}
public String getFullDisplayName() {
return "";
}
/**
* Returns the transient {@link Action}s associated with the top page.
*
*
* Adding {@link Action} is primarily useful for plugins to contribute an
* item to the navigation bar of the top page. See existing {@link Action}
* implementation for it affects the GUI.
*
*
* To register an {@link Action}, implement {@link RootAction} extension
* point, or write code like
* {@code Hudson.getInstance().getActions().add(...)}.
*
* @return Live list where the changes can be made. Can be empty but never
* null.
* @since 1.172
*/
public List getActions() {
return actions;
}
/**
* Gets just the immediate children of {@link Hudson}.
*
* @see #getAllItems(Class)
*/
@Exported(name = "jobs")
public List getItems() {
List viewableItems = new ArrayList();
for (TopLevelItem item : items.values()) {
if (item.hasPermission(Item.READ)) {
TopLevelItem instance = LazyTopLevelItem.getIfInstanceOf(item, TopLevelItem.class);
if (instance != null) {
viewableItems.add(instance);
}
}
}
return viewableItems;
}
// Bug HUDSON/api/xml and HUDSON/api/json return names of jobs user not entitled to see
//@Exported(name = "securedJobs")
public List getSecuredItems() {
List viewableItems = new ArrayList();
for (TopLevelItem item : items.values()) {
if (!item.hasPermission(Item.READ)) {
TopLevelItem instance = LazyTopLevelItem.getIfInstanceOf(item, TopLevelItem.class);
if (instance != null) {
viewableItems.add(instance);
}
}
}
return viewableItems;
}
/**
* Returns the read-only view of all the {@link TopLevelItem}s keyed by
* their names.
*
* This method is efficient, as it doesn't involve any copying.
*
* @since 1.296
*/
public Map getItemMap() {
// Is this circumventing permissions?
return Collections.unmodifiableMap(items);
}
/**
* Gets just the immediate children of {@link Hudson} but of the given type.
*/
public List getItems(Class type) {
List r = new ArrayList();
for (TopLevelItem i : getItems()) {
T t = LazyTopLevelItem.getIfInstanceOf(i, type);
if (t != null) {
r.add(t);
}
}
return r;
}
/**
* Gets all the {@link Item}s recursively in the {@link ItemGroup} tree and
* filter them by the given type.
*/
public List getAllItems(Class type) {
List r = new ArrayList();
Stack q = new Stack();
q.push(this);
while (!q.isEmpty()) {
ItemGroup> parent = q.pop();
for (Item i : parent.getItems()) {
T t = LazyTopLevelItem.getIfInstanceOf(i, type);
if (t != null) {
if (t.hasPermission(Item.READ)) {
r.add(t);
}
}
ItemGroup ig = LazyTopLevelItem.getIfInstanceOf(i, ItemGroup.class);
if (ig != null) {
q.push(ig);
}
}
}
return r;
}
/**
* Gets the list of all the projects.
*
*
* Since {@link Project} can only show up under {@link Hudson}, no need to
* search recursively.
*/
public List getProjects() {
return getItems(Project.class);
// This line seems to circumvent the check for Permission.
// It also won't work with LazyTopLevelItem, so replacing it with
// line above.
//
// return Util.createSubList(items.values(), Project.class);
}
/**
* Gets the names of all the {@link Job}s.
*/
public Collection getJobNames() {
List names = new ArrayList();
for (Job j : getAllItems(Job.class)) {
names.add(j.getFullName());
}
return names;
}
/**
* Gets the names of all the {@link TopLevelItem}s.
*/
public Collection getTopLevelItemNames() {
List names = new ArrayList();
for (TopLevelItem j : items.values()) {
names.add(j.getName());
}
return names;
}
public synchronized View getView(String name) {
for (View v : views) {
if (v.getViewName().equals(name)) {
//return v;
if (isTeamManagementEnabled()) {
return v.hasPermission(View.READ) ? v : null;
} else {
return v;
}
}
}
if (name != null && !name.equals(primaryView)) {
// Fallback to subview of primary view if it is a ViewGroup
View pv = getPrimaryView();
if (pv instanceof ViewGroup) {
View view = ((ViewGroup) pv).getView(name);
if (isTeamManagementEnabled()) {
return view.hasPermission(View.READ) ? view : null;
} else {
return view;
}
}
}
return null;
}
/**
* Gets the read-only list of all {@link View}s.
*/
@Exported
@Override
public synchronized Collection getViews() {
List copy = new ArrayList();
if (this.isTeamManagementEnabled()) {
for (View view : views) {
if (view.hasPermission(View.READ)) {
copy.add(view);
}
}
} else {
copy.addAll(views);
}
Collections.sort(copy, View.SORTER);
return copy;
}
public synchronized Collection getAllViews() {
List copy = new ArrayList(views);
Collections.sort(copy, View.SORTER);
return copy;
}
public void addView(View v) throws IOException {
v.owner = this;
views.add(v);
save();
}
public boolean canDelete(View view) {
return !view.isDefault(); // Cannot delete primary view
}
public synchronized void deleteView(View view) throws IOException {
if (views.size() <= 1) {
throw new IllegalStateException("Cannot delete last view");
}
views.remove(view);
save();
}
public ViewsTabBar getViewsTabBar() {
return viewsTabBar;
}
public MyViewsTabBar getMyViewsTabBar() {
return myViewsTabBar;
}
public ScriptSupport getScriptSupport() {
return scriptSupport;
}
/**
* Returns true if the current running Hudson is upgraded from a version
* earlier than the specified version.
*
*
* This method continues to return true until the system configuration is
* saved, at which point {@link #version} will be overwritten and Hudson
* forgets the upgrade history.
*
*
* To handle SNAPSHOTS correctly, pass in "1.N.*" to test if it's upgrading
* from the version equal or younger than N. So say if you implement a
* feature in 1.301 and you want to check if the installation upgraded from
* pre-1.301, pass in "1.300.*"
*
* @since 1.301
*/
public boolean isUpgradedFromBefore(VersionNumber v) {
try {
return new VersionNumber(version).isOlderThan(v);
} catch (IllegalArgumentException e) {
// fail to parse this version number
return false;
}
}
/**
* Gets the read-only list of all {@link Computer}s.
*/
public Computer[] getComputers() {
Computer[] allComputers = getAllComputers();
List copy = new ArrayList();
if (this.isTeamManagementEnabled()) {
for (Computer computer : allComputers) {
if (computer.hasPermission(Computer.READ)) {
copy.add(computer);
}
}
return copy.toArray(new Computer[copy.size()]);
} else {
return allComputers;
}
}
public Computer[] getAllComputers() {
Computer[] r = computers.values().toArray(new Computer[computers.size()]);
Arrays.sort(r, new Comparator() {
final Collator collator = Collator.getInstance();
public int compare(Computer lhs, Computer rhs) {
if (lhs.getNode() == Hudson.this) {
return -1;
}
if (rhs.getNode() == Hudson.this) {
return 1;
}
return collator.compare(lhs.getDisplayName(), rhs.getDisplayName());
}
});
return r;
}
/*package*/ Computer getComputer(Node n) {
return computers.get(n);
}
@CLIResolver
public Computer getComputer(@Argument(required = true, metaVar = "NAME", usage = "Node name") String name) {
return getComputer(name, false);
}
public Computer getComputer(String name, boolean system) {
if (name.equals("(master)")) {
name = "";
}
for (Computer c : computers.values()) {
if (c.getName().equals(name)) {
if (isTeamManagementEnabled() && !system) {
return c.hasPermission(Computer.READ) ? c : null;
} else {
return c;
}
}
}
return null;
}
/**
* @deprecated UI method. Not meant to be used programmatically.
*/
public ComputerSet getComputer() {
return new ComputerSet();
}
/**
* Gets the label that exists on this system by the name.
*
* @return null if name is null.
* @see Label#parseExpression(String) (String)
*/
public Label getLabel(String expr) {
if (expr == null) {
return null;
}
while (true) {
Label l = labels.get(expr);
if (l != null) {
return l;
}
// non-existent
try {
labels.putIfAbsent(expr, Label.parseExpression(expr));
} catch (RecognitionException e) {
// laxly accept it as a single label atom for backward compatibility
return getLabelAtom(expr);
}
}
}
/**
* Returns the label atom of the given name.
*/
public LabelAtom getLabelAtom(String name) {
if (name == null) {
return null;
}
while (true) {
Label l = labels.get(name);
if (l != null) {
return (LabelAtom) l;
}
// non-existent
LabelAtom la = new LabelAtom(name);
if (labels.putIfAbsent(name, la) == null) {
la.load();
}
}
}
/**
* Gets all the active labels in the current system.
*/
public Set