提交 94faaf3f 编写于 作者: K Kohsuke Kawaguchi

adding a method to experiment with the dynamic loading of a plugin

上级 64f2b3d3
......@@ -23,19 +23,12 @@
*/
package hudson;
import static hudson.init.InitMilestone.PLUGINS_PREPARED;
import static hudson.init.InitMilestone.PLUGINS_STARTED;
import static hudson.init.InitMilestone.PLUGINS_LISTED;
import com.google.inject.Guice;
import com.google.inject.Injector;
import hudson.PluginWrapper.Dependency;
import hudson.init.InitMilestone;
import hudson.init.InitStrategy;
import hudson.init.InitializerFinder;
import hudson.model.AbstractModelObject;
import hudson.model.Failure;
import jenkins.ClassLoaderReflectionToolkit;
import jenkins.model.Jenkins;
import hudson.model.UpdateCenter;
import hudson.model.UpdateSite;
import hudson.util.CyclicGraphDetector;
......@@ -43,6 +36,9 @@ import hudson.util.CyclicGraphDetector.CycleDetectedException;
import hudson.util.FormValidation;
import hudson.util.PersistedList;
import hudson.util.Service;
import jenkins.ClassLoaderReflectionToolkit;
import jenkins.InitReactorRunner;
import jenkins.model.Jenkins;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
......@@ -66,25 +62,26 @@ import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import static hudson.init.InitMilestone.*;
/**
* Manages {@link PluginWrapper}s.
*
......@@ -329,6 +326,37 @@ public abstract class PluginManager extends AbstractModelObject {
}});
}
/**
* TODO: revisit where/how to expose this. This is an experiment.
*/
public void dynamicLoad(File arc) throws Exception {
PluginWrapper p = strategy.createPluginWrapper(arc);
if (getPlugin(p.getShortName())!=null)
throw new IllegalArgumentException("Dynamic reloading isn't possible");
// TODO: check cyclic dependency
activePlugins.add(p);
try {
p.resolvePluginDependencies();
strategy.load(p);
p.getPlugin().postInitialize();
} catch (Exception e) {
failedPlugins.add(new FailedPlugin(p.getShortName(), e));
activePlugins.remove(p);
plugins.remove(p);
throw e;
}
// run initializers
// TODO: need to ignore base types
Reactor r = new Reactor(InitMilestone.ordering());
r.addAll(new InitializerFinder(p.classLoader).discoverTasks(r));
new InitReactorRunner().run(r);
}
/**
* If the war file has any "/WEB-INF/plugins/*.hpi", extract them into the plugin directory.
*
......
package jenkins;
import hudson.init.InitMilestone;
import hudson.init.InitReactorListener;
import hudson.util.DaemonThreadFactory;
import hudson.util.Service;
import jenkins.model.Configuration;
import jenkins.model.Jenkins;
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 java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.logging.Level.SEVERE;
/**
* Executes the {@link Reactor} for the purpose of bootup.
*
* @author Kohsuke Kawaguchi
*/
public class InitReactorRunner {
public void run(Reactor reactor) throws InterruptedException, ReactorException, IOException {
reactor.addAll(InitMilestone.ordering().discoverTasks(reactor));
ExecutorService es;
if (Jenkins.PARALLEL_LOAD)
es = new ThreadPoolExecutor(
TWICE_CPU_NUM, TWICE_CPU_NUM, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), 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.
*
* <p>
* 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<ReactorListener> r = (List) Service.loadInstances(Thread.currentThread().getContextClassLoader(), InitReactorListener.class);
r.add(new ReactorListener() {
final Level level = Level.parse( Configuration.getStringConfigParameter("initLogLevel", "FINE") );
public void onTaskStarted(Task t) {
LOGGER.log(level,"Started "+t.getDisplayName());
}
public void onTaskCompleted(Task t) {
LOGGER.log(level,"Completed "+t.getDisplayName());
}
public void onTaskFailed(Task t, Throwable err, boolean fatal) {
LOGGER.log(SEVERE, "Failed "+t.getDisplayName(),err);
}
public void onAttained(Milestone milestone) {
Level lv = level;
String s = "Attained "+milestone.toString();
if (milestone instanceof InitMilestone) {
lv = Level.INFO; // noteworthy milestones --- at least while we debug problems further
onInitMilestoneAttained((InitMilestone) milestone);
s = milestone.toString();
}
LOGGER.log(lv,s);
}
});
return new ReactorListener.Aggregator(r);
}
/**
* Called when the init milestone is attained.
*/
protected void onInitMilestoneAttained(InitMilestone milestone) {
}
private static final int TWICE_CPU_NUM = Runtime.getRuntime().availableProcessors() * 2;
private static final Logger LOGGER = Logger.getLogger(InitReactorRunner.class.getName());
}
......@@ -188,6 +188,7 @@ import hudson.views.ViewsTabBar;
import hudson.widgets.Widget;
import jenkins.ExtensionComponentSet;
import jenkins.ExtensionRefreshException;
import jenkins.InitReactorRunner;
import net.sf.json.JSONObject;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.AcegiSecurityException;
......@@ -810,56 +811,15 @@ public class Jenkins extends AbstractCIBase implements ModifiableItemGroup<TopLe
}
};
ExecutorService es;
if (PARALLEL_LOAD)
es = new ThreadPoolExecutor(
TWICE_CPU_NUM, TWICE_CPU_NUM, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), 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.
*
* <p>
* 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<ReactorListener> r = (List) Service.loadInstances(Thread.currentThread().getContextClassLoader(), InitReactorListener.class);
r.add(new ReactorListener() {
final Level level = Level.parse( Configuration.getStringConfigParameter("initLogLevel", "FINE") );
public void onTaskStarted(Task t) {
LOGGER.log(level,"Started "+t.getDisplayName());
}
public void onTaskCompleted(Task t) {
LOGGER.log(level,"Completed "+t.getDisplayName());
}
public void onTaskFailed(Task t, Throwable err, boolean fatal) {
LOGGER.log(SEVERE, "Failed "+t.getDisplayName(),err);
}
public void onAttained(Milestone milestone) {
Level lv = level;
String s = "Attained "+milestone.toString();
if (milestone instanceof InitMilestone) {
lv = Level.INFO; // noteworthy milestones --- at least while we debug problems further
initLevel = (InitMilestone)milestone;
s = initLevel.toString();
}
LOGGER.log(lv,s);
new InitReactorRunner() {
@Override
protected void onInitMilestoneAttained(InitMilestone milestone) {
initLevel = milestone;
}
});
return new ReactorListener.Aggregator(r);
}.run(reactor);
}
public TcpSlaveAgentListener getTcpSlaveAgentListener() {
return tcpSlaveAgentListener;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册