mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-13 20:12:14 +00:00
Added a mechanism to filter extension points as they are discovered.
I couldn't quite find one place to do this, so it's spread apart somewhat.
This commit is contained in:
1 parent
4e7a43c586
commit
9a178aa8cc
9 files changed
+174
-6
No files matched your search
@@ -55,6 +55,8 @@ Upcoming changes</a>
|
||||
<!-- Record your changes in the trunk here. -->
|
||||
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
|
||||
<ul class=image>
|
||||
<li class=rfe>
|
||||
Added a mechanism to filter extension points as they are discovered.
|
||||
<li class=rfe>
|
||||
Exposed the master's own node properties to be configured in <tt>/computer/(master)/configure</tt>
|
||||
(whereas <tt>/configure</tt> controls global node properties that apply to all nodes.)
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
*/
|
||||
package hudson;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import hudson.Plugin.DummyImpl;
|
||||
import hudson.PluginWrapper.Dependency;
|
||||
import hudson.model.Hudson;
|
||||
@@ -33,6 +35,7 @@ import hudson.util.IOUtils;
|
||||
import hudson.util.MaskingClassLoader;
|
||||
import hudson.util.VersionNumber;
|
||||
import jenkins.ClassLoaderReflectionToolkit;
|
||||
import jenkins.ExtensionFilter;
|
||||
import org.apache.tools.ant.AntClassLoader;
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.Project;
|
||||
@@ -54,6 +57,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
import java.util.jar.Attributes;
|
||||
@@ -286,7 +290,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
|
||||
finder.scout(type, hudson);
|
||||
}
|
||||
|
||||
List<ExtensionComponent<T>> r = new ArrayList<ExtensionComponent<T>>();
|
||||
List<ExtensionComponent<T>> r = Lists.newArrayList();
|
||||
for (ExtensionFinder finder : finders) {
|
||||
try {
|
||||
r.addAll(finder._find(type, hudson));
|
||||
@@ -296,7 +300,14 @@ public class ClassicPluginStrategy implements PluginStrategy {
|
||||
r.add(new ExtensionComponent<T>(t));
|
||||
}
|
||||
}
|
||||
return r;
|
||||
|
||||
List<ExtensionComponent<T>> filtered = Lists.newArrayList();
|
||||
for (ExtensionComponent<T> e : r) {
|
||||
if (ExtensionFilter.isAllowed(type,e))
|
||||
filtered.add(e);
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
public void load(PluginWrapper wrapper) throws IOException {
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
|
||||
package hudson;
|
||||
|
||||
import hudson.model.Describable;
|
||||
import hudson.model.Descriptor;
|
||||
import jenkins.ExtensionFilter;
|
||||
|
||||
/**
|
||||
* Discovered {@link Extension} object with a bit of metadata for Hudson.
|
||||
@@ -32,6 +34,8 @@ import hudson.model.Descriptor;
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @since 1.356
|
||||
* @see ExtensionFinder
|
||||
* @see ExtensionFilter
|
||||
*/
|
||||
public class ExtensionComponent<T> implements Comparable<ExtensionComponent<T>> {
|
||||
private final T instance;
|
||||
@@ -66,6 +70,15 @@ public class ExtensionComponent<T> implements Comparable<ExtensionComponent<T>>
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this component is a {@link Descriptor} describing the given type
|
||||
*
|
||||
* For example, {@code component.isDescriptorOf(Builder.class)}
|
||||
*/
|
||||
public boolean isDescriptorOf(Class<? extends Describable> c) {
|
||||
return instance instanceof Descriptor && ((Descriptor)instance).isSubTypeOf(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort {@link ExtensionComponent}s in the descending order of {@link #ordinal()}.
|
||||
*/
|
||||
|
||||
@@ -41,6 +41,7 @@ import hudson.init.InitMilestone;
|
||||
import hudson.model.Descriptor;
|
||||
import hudson.model.Hudson;
|
||||
import jenkins.ExtensionComponentSet;
|
||||
import jenkins.ExtensionFilter;
|
||||
import jenkins.ExtensionRefreshException;
|
||||
import jenkins.ProxyInjector;
|
||||
import jenkins.model.Jenkins;
|
||||
@@ -72,10 +73,11 @@ import java.lang.reflect.Method;
|
||||
*
|
||||
* <p>
|
||||
* {@link ExtensionFinder} itself is an extension point, but to avoid infinite recursion,
|
||||
* Hudson discovers {@link ExtensionFinder}s through {@link Sezpoz} and that alone.
|
||||
* Jenkins discovers {@link ExtensionFinder}s through {@link Sezpoz} and that alone.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @since 1.286
|
||||
* @see ExtensionFilter
|
||||
*/
|
||||
public abstract class ExtensionFinder implements ExtensionPoint {
|
||||
/**
|
||||
@@ -126,7 +128,7 @@ public abstract class ExtensionFinder implements ExtensionPoint {
|
||||
* <p>
|
||||
* This method should return all the known components at the time of the call, including
|
||||
* those that are discovered later via {@link #refresh()}, even though those components
|
||||
* are separately retruend in {@link ExtensionComponentSet}.
|
||||
* are separately returned in {@link ExtensionComponentSet}.
|
||||
*
|
||||
* @param <T>
|
||||
* The type of the extension points. This is not bound to {@link ExtensionPoint} because
|
||||
|
||||
@@ -3,6 +3,7 @@ package hudson.model;
|
||||
import hudson.ExtensionList;
|
||||
import hudson.ExtensionPoint;
|
||||
import hudson.scm.SCMDescriptor;
|
||||
import jenkins.ExtensionFilter;
|
||||
import jenkins.model.Jenkins;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -13,6 +14,7 @@ import java.util.List;
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @since 1.393
|
||||
* @see ExtensionFilter
|
||||
*/
|
||||
public abstract class DescriptorVisibilityFilter implements ExtensionPoint {
|
||||
|
||||
|
||||
@@ -59,6 +59,24 @@ public abstract class ExtensionComponentSet {
|
||||
*/
|
||||
public abstract <T> Collection<ExtensionComponent<T>> find(Class<T> type);
|
||||
|
||||
/**
|
||||
* Apply {@link ExtensionFilter}s and returns a filtered set.
|
||||
*/
|
||||
public final ExtensionComponentSet filtered() {
|
||||
final ExtensionComponentSet base = this;
|
||||
return new ExtensionComponentSet() {
|
||||
@Override
|
||||
public <T> Collection<ExtensionComponent<T>> find(Class<T> type) {
|
||||
List<ExtensionComponent<T>> a = Lists.newArrayList();
|
||||
for (ExtensionComponent<T> c : base.find(type)) {
|
||||
if (ExtensionFilter.isAllowed(type,c))
|
||||
a.add(c);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constant that has zero component in it.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2012, CloudBees, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package jenkins;
|
||||
|
||||
import hudson.ExtensionComponent;
|
||||
import hudson.ExtensionFinder;
|
||||
import hudson.ExtensionList;
|
||||
import hudson.ExtensionPoint;
|
||||
import hudson.model.AdministrativeMonitor;
|
||||
import hudson.model.Describable;
|
||||
import hudson.model.Descriptor;
|
||||
import hudson.model.DescriptorVisibilityFilter;
|
||||
import jenkins.model.Jenkins;
|
||||
|
||||
/**
|
||||
* Filters out {@link ExtensionComponent}s discovered by {@link ExtensionFinder}s,
|
||||
* as if they were never discovered.
|
||||
*
|
||||
* <p>
|
||||
* This is useful for those who are deploying restricted/simplified version of Jenkins
|
||||
* by reducing the functionality.
|
||||
*
|
||||
* <p>
|
||||
* Because of the way {@link ExtensionFinder} works, even when an extension component
|
||||
* is rejected by a filter, its instance still gets created first.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @since 1.472
|
||||
* @see DescriptorVisibilityFilter
|
||||
* @see ExtensionComponentSet#filtered()
|
||||
*/
|
||||
public abstract class ExtensionFilter implements ExtensionPoint {
|
||||
/**
|
||||
* Checks if a newly discovered extension is allowed to participate into Jenkins.
|
||||
*
|
||||
* <p>
|
||||
* To filter {@link Descriptor}s based on the {@link Describable} subtypes, do as follows:
|
||||
*
|
||||
* <pre>
|
||||
* return !component.isDescriptorOf(Builder.class);
|
||||
* </pre>
|
||||
*
|
||||
* @param type
|
||||
* The type of the extension that we are discovering. This is not the actual instance
|
||||
* type, but the contract type, such as {@link Descriptor}, {@link AdministrativeMonitor}, etc.
|
||||
* @return
|
||||
* true to let the component into Jenkins. false to drop it and pretend
|
||||
* as if it didn't exist. When any one of {@link ExtensionFilter}s veto
|
||||
* a component, it gets dropped.
|
||||
*/
|
||||
public abstract <T> boolean allows(Class<T> type, ExtensionComponent<T> component);
|
||||
|
||||
public static <T> boolean isAllowed(Class<T> type, ExtensionComponent<T> component) {
|
||||
// to avoid infinite recursion, those extension points are handled differently.
|
||||
if (type==ExtensionFilter.class || type==ExtensionFinder.class)
|
||||
return true;
|
||||
|
||||
for (ExtensionFilter f : all())
|
||||
if (!f.allows(type, component))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* All registered {@link ExtensionFilter} instances.
|
||||
*/
|
||||
public static ExtensionList<ExtensionFilter> all() {
|
||||
return Jenkins.getInstance().getExtensionList(ExtensionFilter.class);
|
||||
}
|
||||
}
|
||||
@@ -2055,14 +2055,14 @@ public class Jenkins extends AbstractCIBase implements ModifiableItemGroup<TopLe
|
||||
for (ExtensionFinder ef : finders) {
|
||||
fragments.add(ef.refresh());
|
||||
}
|
||||
ExtensionComponentSet delta = ExtensionComponentSet.union(fragments);
|
||||
ExtensionComponentSet delta = ExtensionComponentSet.union(fragments).filtered();
|
||||
|
||||
// if we find a new ExtensionFinder, we need it to list up all the extension points as well
|
||||
List<ExtensionComponent<ExtensionFinder>> newFinders = Lists.newArrayList(delta.find(ExtensionFinder.class));
|
||||
while (!newFinders.isEmpty()) {
|
||||
ExtensionFinder f = newFinders.remove(newFinders.size()-1).getInstance();
|
||||
|
||||
ExtensionComponentSet ecs = ExtensionComponentSet.allOf(f);
|
||||
ExtensionComponentSet ecs = ExtensionComponentSet.allOf(f).filtered();
|
||||
newFinders.addAll(ecs.find(ExtensionFinder.class));
|
||||
delta = ExtensionComponentSet.union(delta, ecs);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package jenkins;
|
||||
|
||||
import hudson.ExtensionComponent;
|
||||
import hudson.console.ConsoleAnnotatorFactory;
|
||||
import hudson.model.PageDecorator;
|
||||
import org.jvnet.hudson.test.HudsonTestCase;
|
||||
import org.jvnet.hudson.test.TestExtension;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class ExtensionFilterTest extends HudsonTestCase {
|
||||
public void testFilter() {
|
||||
assertTrue(PageDecorator.all().isEmpty());
|
||||
assertTrue(ConsoleAnnotatorFactory.all().isEmpty());
|
||||
}
|
||||
|
||||
@TestExtension("testFilter")
|
||||
public static class Impl extends ExtensionFilter {
|
||||
@Override
|
||||
public <T> boolean allows(Class<T> type, ExtensionComponent<T> component) {
|
||||
if (type==ConsoleAnnotatorFactory.class)
|
||||
return false;
|
||||
if (component.isDescriptorOf(PageDecorator.class))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user