mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-03 23:25:52 +00:00
[JENKINS-34681] Allow custom plugin managers when using war (#2323)
* [JENKINS-34681] Allow custom default plugin managers * [JENKINS-34681] Convert remaining properties to SystemProperties.
This commit is contained in:
1 parent
dbe04b3522
commit
454642dafe
4 files changed
+259
-12
No files matched your search
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
package hudson;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.NonNull;
|
||||
import jenkins.util.SystemProperties;
|
||||
import hudson.PluginWrapper.Dependency;
|
||||
import hudson.init.InitMilestone;
|
||||
@@ -136,6 +137,7 @@ import static hudson.init.InitMilestone.*;
|
||||
import hudson.model.DownloadService;
|
||||
import hudson.util.FormValidation;
|
||||
|
||||
import static java.util.logging.Level.FINE;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.SEVERE;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
@@ -145,10 +147,101 @@ import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
/**
|
||||
* Manages {@link PluginWrapper}s.
|
||||
*
|
||||
* <p>
|
||||
* <b>Setting default Plugin Managers</b>. The default plugin manager in {@code Jenkins} can be replaced by defining a
|
||||
* System Property (<code>hudson.PluginManager.className</code>). See {@link #createDefault(Jenkins)}.
|
||||
* This className should be available on early startup, so it cannot come only from a library
|
||||
* (e.g. Jenkins module or Extra library dependency in the WAR file project).
|
||||
* Plugins cannot be used for such purpose.
|
||||
* In order to be correctly instantiated, the class definition must have at least one constructor with the same
|
||||
* signature as the following ones:
|
||||
* <ol>
|
||||
* <li>{@link LocalPluginManager#LocalPluginManager(Jenkins)} </li>
|
||||
* <li>{@link LocalPluginManager#LocalPluginManager(ServletContext, File)} </li>
|
||||
* <li>{@link LocalPluginManager#LocalPluginManager(File)} </li>
|
||||
* </ol>
|
||||
* Constructors are searched in the order provided above and only the first found suitable constructor is
|
||||
* tried to build an instance. In the last two cases the {@link File} argument refers to the <i>Jenkins home directory</i>.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@ExportedBean
|
||||
public abstract class PluginManager extends AbstractModelObject implements OnMaster, StaplerOverridable {
|
||||
/** Custom plugin manager system property or context param. */
|
||||
public static final String CUSTOM_PLUGIN_MANAGER = PluginManager.class.getName() + ".className";
|
||||
|
||||
/** Accepted constructors for custom plugin manager, in the order they are tried. */
|
||||
private enum PMConstructor {
|
||||
JENKINS {
|
||||
@Override
|
||||
@NonNull PluginManager doCreate(@NonNull Class<? extends PluginManager> klass,
|
||||
@NonNull Jenkins jenkins) throws ReflectiveOperationException {
|
||||
return klass.getConstructor(Jenkins.class).newInstance(jenkins);
|
||||
}
|
||||
},
|
||||
SC_FILE {
|
||||
@Override
|
||||
@NonNull PluginManager doCreate(@NonNull Class<? extends PluginManager> klass,
|
||||
@NonNull Jenkins jenkins) throws ReflectiveOperationException {
|
||||
return klass.getConstructor(ServletContext.class, File.class).newInstance(jenkins.servletContext, jenkins.getRootDir());
|
||||
}
|
||||
},
|
||||
FILE {
|
||||
@Override
|
||||
@NonNull PluginManager doCreate(@NonNull Class<? extends PluginManager> klass,
|
||||
@NonNull Jenkins jenkins) throws ReflectiveOperationException {
|
||||
return klass.getConstructor(File.class).newInstance(jenkins.getRootDir());
|
||||
}
|
||||
};
|
||||
|
||||
final @CheckForNull PluginManager create(@NonNull Class<? extends PluginManager> klass,
|
||||
@NonNull Jenkins jenkins) throws ReflectiveOperationException {
|
||||
try {
|
||||
return doCreate(klass, jenkins);
|
||||
} catch(NoSuchMethodException e) {
|
||||
// Constructor not found. Will try the remaining ones.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
abstract @NonNull PluginManager doCreate(@NonNull Class<? extends PluginManager> klass,
|
||||
@NonNull Jenkins jenkins) throws ReflectiveOperationException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link PluginManager} to use if no one is provided to a {@link Jenkins} object.
|
||||
* This method will be called after creation of {@link Jenkins} object, but before it is fully initialized.
|
||||
* @param jenkins Jenkins Instance.
|
||||
* @return Plugin manager to use. If no custom class is configured or in case of any error, the default
|
||||
* {@link LocalPluginManager} is returned.
|
||||
*/
|
||||
public static @NonNull PluginManager createDefault(@NonNull Jenkins jenkins) {
|
||||
String pmClassName = SystemProperties.getString(CUSTOM_PLUGIN_MANAGER);
|
||||
if (!StringUtils.isBlank(pmClassName)) {
|
||||
LOGGER.log(FINE, String.format("Use of custom plugin manager [%s] requested.", pmClassName));
|
||||
try {
|
||||
final Class<? extends PluginManager> klass = Class.forName(pmClassName).asSubclass(PluginManager.class);
|
||||
// Iteration is in declaration order
|
||||
for (PMConstructor c : PMConstructor.values()) {
|
||||
PluginManager pm = c.create(klass, jenkins);
|
||||
if (pm != null) {
|
||||
return pm;
|
||||
}
|
||||
}
|
||||
LOGGER.log(WARNING, String.format("Provided custom plugin manager [%s] does not provide any of the suitable constructors. Using default.", pmClassName));
|
||||
} catch(NullPointerException e) {
|
||||
// Class.forName and Class.getConstructor are supposed to never return null though a broken ClassLoader
|
||||
// could break the contract. Just in case we introduce this specific catch to avoid polluting the logs with NPEs.
|
||||
LOGGER.log(WARNING, String.format("Unable to instantiate custom plugin manager [%s]. Using default.", pmClassName));
|
||||
} catch(ClassCastException e) {
|
||||
LOGGER.log(WARNING, String.format("Provided class [%s] does not extend PluginManager. Using default.", pmClassName));
|
||||
} catch(Exception e) {
|
||||
LOGGER.log(WARNING, String.format("Unable to instantiate custom plugin manager [%s]. Using default.", pmClassName), e);
|
||||
}
|
||||
}
|
||||
return new LocalPluginManager(jenkins);
|
||||
}
|
||||
|
||||
/**
|
||||
* All discovered plugins.
|
||||
*/
|
||||
@@ -218,11 +311,8 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
|
||||
this.rootDir = rootDir;
|
||||
if(!rootDir.exists())
|
||||
rootDir.mkdirs();
|
||||
String workDir = System.getProperty(PluginManager.class.getName()+".workDir");
|
||||
if (workDir == null && context != null) {
|
||||
workDir = context.getInitParameter(PluginManager.class.getName() + ".workDir");
|
||||
}
|
||||
this.workDir = workDir == null ? null : new File(workDir);
|
||||
String workDir = SystemProperties.getString(PluginManager.class.getName()+".workDir");
|
||||
this.workDir = StringUtils.isBlank(workDir) ? null : new File(workDir);
|
||||
|
||||
strategy = createPluginStrategy();
|
||||
|
||||
@@ -561,7 +651,7 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
|
||||
if (dependencyURL != null) {
|
||||
// And transitive deps...
|
||||
addDependencies(dependencyURL, fromPath, dependencySet);
|
||||
// And then add the current plugin
|
||||
// And then add the current plugin
|
||||
dependencySet.add(dependencyURL);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user