提交 1b766a08 编写于 作者: K kohsuke

RepositoryBrowser is updated to support auto registration.

Refactored the ConcurrentHashMap double-if putIfAbsent idiom into the Memoizer class.

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@15653 71c3de6d-444a-0410-be80-ed276b4c234a
上级 50d0fca8
......@@ -26,12 +26,12 @@ package hudson;
import hudson.model.Descriptor;
import hudson.model.Describable;
import hudson.model.Hudson;
import hudson.util.Memoizer;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Logger;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.lang.reflect.Type;
import java.lang.reflect.ParameterizedType;
......@@ -52,7 +52,7 @@ public final class DescriptorExtensionList<T extends Describable<T>> extends Ext
private final Class<T> describableType;
public DescriptorExtensionList(Hudson hudson, Class<T> describableType) {
super(hudson, (Class)Descriptor.class,allocateLegacyInstanceStore(describableType));
super(hudson, (Class)Descriptor.class, legacyDescriptors.get(describableType));
this.describableType = describableType;
}
......@@ -78,19 +78,17 @@ public final class DescriptorExtensionList<T extends Describable<T>> extends Ext
* Obtain the statically-scoped storage to store manulaly registered {@link Descriptor}s.
*/
private static List allocateLegacyInstanceStore(Class describableType) {
List r = legacyDescriptors.get(describableType);
if(r!=null) return r;
r = new CopyOnWriteArrayList();
List x = legacyDescriptors.putIfAbsent(describableType, r);
if(x==null) return r;
return x;
return legacyDescriptors.get(describableType);
}
/**
* Stores manually registered Descriptor instances.
*/
private static final ConcurrentHashMap<Class,List> legacyDescriptors = new ConcurrentHashMap<Class,List>();
private static final Memoizer<Class,List> legacyDescriptors = new Memoizer<Class,List>() {
public List compute(Class key) {
return new CopyOnWriteArrayList();
}
};
private static final Logger LOGGER = Logger.getLogger(DescriptorExtensionList.class.getName());
}
......@@ -25,6 +25,8 @@ package hudson;
import hudson.model.Hudson;
import hudson.util.DescriptorList;
import hudson.util.Memoizer;
import hudson.ExtensionPoint.LegacyInstancesAreScopedToHudson;
import java.util.AbstractList;
import java.util.ArrayList;
......@@ -33,6 +35,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentHashMap;
/**
* Retains the known extension instances for the given type 'T'.
......@@ -174,6 +177,19 @@ public class ExtensionList<T> extends AbstractList<T> {
return Collections.singleton(new ExtensionFinder.Sezpoz());
}
};
if(type.getAnnotation(LegacyInstancesAreScopedToHudson.class)!=null)
return new ExtensionList<T>(hudson,type);
else {
return new ExtensionList<T>(hudson,type,staticLegacyInstances.get(type));
}
}
/**
* Places to store static-scope legacy instances.
*/
private static final Memoizer<Class,List> staticLegacyInstances = new Memoizer<Class,List>() {
public List compute(Class key) {
return new CopyOnWriteArrayList();
}
};
}
......@@ -23,6 +23,13 @@
*/
package hudson;
import hudson.model.Hudson;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
/**
* Marker interface that designates extensible components
* in Hudson that can be implemented by plugins.
......@@ -41,4 +48,12 @@ package hudson;
* @see Extension
*/
public interface ExtensionPoint {
/**
* Used by designers of extension points (direct subtypes of {@link ExtensionPoint}) to indicate that
* the legacy instances are scoped to {@link Hudson} instance. By default, legacy instances are
* static scope.
*/
@Target(TYPE)
@Retention(RUNTIME)
public @interface LegacyInstancesAreScopedToHudson {}
}
......@@ -26,6 +26,7 @@ package hudson.model;
import hudson.ExtensionPoint;
import hudson.ExtensionList;
import hudson.Extension;
import hudson.ExtensionPoint.LegacyInstancesAreScopedToHudson;
import hudson.triggers.SCMTrigger;
import hudson.triggers.TimerTrigger;
......@@ -72,6 +73,7 @@ import org.kohsuke.stapler.StaplerResponse;
* @since 1.273
* @see Hudson#administrativeMonitors
*/
@LegacyInstancesAreScopedToHudson
public abstract class AdministrativeMonitor extends AbstractModelObject implements ExtensionPoint {
/**
* Human-readable ID of this monitor, which needs to be unique within the system.
......
......@@ -106,6 +106,7 @@ import hudson.util.XStream2;
import hudson.util.HudsonIsRestarting;
import hudson.util.DescribableList;
import hudson.util.Futures;
import hudson.util.Memoizer;
import hudson.widgets.Widget;
import net.sf.json.JSONObject;
import org.acegisecurity.*;
......@@ -281,12 +282,20 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
/**
* All {@link ExtensionList} keyed by their {@link ExtensionList#extensionType}.
*/
private transient final ConcurrentHashMap<Class,ExtensionList> extensionLists = new ConcurrentHashMap<Class,ExtensionList>();
private transient final Memoizer<Class,ExtensionList> extensionLists = new Memoizer<Class,ExtensionList>() {
public ExtensionList compute(Class key) {
return ExtensionList.create(Hudson.this,key);
}
};
/**
* All {@link DescriptorExtensionList} keyed by their {@link DescriptorExtensionList#describableType}.
*/
private transient final ConcurrentHashMap<Class, DescriptorExtensionList> descriptorLists = new ConcurrentHashMap<Class, DescriptorExtensionList>();
private transient final Memoizer<Class,DescriptorExtensionList> descriptorLists = new Memoizer<Class,DescriptorExtensionList>() {
public DescriptorExtensionList compute(Class key) {
return new DescriptorExtensionList(Hudson.this,key);
}
};
/**
* Active {@link Cloud}s.
......@@ -631,7 +640,7 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
* Gets the repository browser descriptor by name. Primarily used for making them web-visible.
*/
public Descriptor<RepositoryBrowser<?>> getRepositoryBrowser(String shortClassName) {
return findDescriptor(shortClassName,RepositoryBrowsers.LIST);
return findDescriptor(shortClassName,RepositoryBrowser.all());
}
/**
......@@ -1468,15 +1477,7 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
*/
@SuppressWarnings({"unchecked"})
public <T> ExtensionList<T> getExtensionList(Class<T> extensionType) {
// by far the common case is where we find an instance already created.
ExtensionList<T> r = extensionLists.get(extensionType);
if(r!=null) return r;
// if we have to create a new one, make sure we don't create two at the same time.
r = ExtensionList.create(this,extensionType);
ExtensionList<T> x = extensionLists.putIfAbsent(extensionType, r);
if(x==null) return r;
else return x;
return extensionLists.get(extensionType);
}
/**
......@@ -1488,15 +1489,7 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
*/
@SuppressWarnings({"unchecked"})
public <T extends Describable<T>> DescriptorExtensionList<T> getDescriptorList(Class<T> type) {
// by far the common case is where we find an instance already created.
DescriptorExtensionList r = descriptorLists.get(type);
if(r!=null) return r;
// if we have to create a new one, make sure we don't create two at the same time.
r = new DescriptorExtensionList(this,type);
DescriptorExtensionList x = descriptorLists.putIfAbsent(type, r);
if(x==null) return r;
else return x;
return descriptorLists.get(type);
}
/**
......
......@@ -24,7 +24,12 @@
package hudson.scm;
import hudson.ExtensionPoint;
import hudson.DescriptorExtensionList;
import hudson.Extension;
import hudson.tasks.BuildWrapper;
import hudson.model.Describable;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import java.io.IOException;
import java.io.Serializable;
......@@ -44,8 +49,7 @@ import java.net.MalformedURLException;
* {@link RepositoryBrowser} is persisted with {@link SCM}.
*
* <p>
* To have Hudson recognize {@link RepositoryBrowser}, add the descriptor
* to {@link RepositoryBrowsers#LIST}.
* To have Hudson recognize {@link RepositoryBrowser}, put {@link Extension} on your {@link Descriptor}.
*
* @author Kohsuke Kawaguchi
* @since 1.89
......@@ -90,5 +94,16 @@ public abstract class RepositoryBrowser<E extends ChangeLogSet.Entry> implements
}
}
public Descriptor<RepositoryBrowser<?>> getDescriptor() {
return Hudson.getInstance().getDescriptor(getClass());
}
/**
* Returns all the registered {@link RepositoryBrowser} descriptors.
*/
public static DescriptorExtensionList<RepositoryBrowser<?>> all() {
return (DescriptorExtensionList)Hudson.getInstance().getDescriptorList(RepositoryBrowser.class);
}
private static final long serialVersionUID = 1L;
}
......@@ -24,8 +24,11 @@
package hudson.scm;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.model.Descriptor.FormException;
import hudson.scm.browsers.*;
import hudson.util.DescriptorList;
import hudson.Extension;
import org.kohsuke.stapler.StaplerRequest;
import java.util.ArrayList;
......@@ -42,23 +45,18 @@ import net.sf.json.JSONArray;
public class RepositoryBrowsers {
/**
* List of all installed {@link RepositoryBrowsers}.
*
* @deprecated as of 1.286.
* Use {@link RepositoryBrowser#all()} for read access and {@link Extension} for registration.
*/
public static final List<Descriptor<RepositoryBrowser<?>>> LIST = Descriptor.toList(
ViewCVS.DESCRIPTOR,
ViewSVN.DescriptorImpl.INSTANCE,
FishEyeSVN.DESCRIPTOR,
FishEyeCVS.DESCRIPTOR,
WebSVN.DESCRIPTOR,
Sventon.DESCRIPTOR,
CollabNetSVN.DESCRIPTOR
);
public static final List<Descriptor<RepositoryBrowser<?>>> LIST = new DescriptorList<RepositoryBrowser<?>>((Class)RepositoryBrowser.class);
/**
* Only returns those {@link RepositoryBrowser} descriptors that extend from the given type.
*/
public static List<Descriptor<RepositoryBrowser<?>>> filter(Class<? extends RepositoryBrowser> t) {
List<Descriptor<RepositoryBrowser<?>>> r = new ArrayList<Descriptor<RepositoryBrowser<?>>>();
for (Descriptor<RepositoryBrowser<?>> d : LIST)
for (Descriptor<RepositoryBrowser<?>> d : RepositoryBrowser.all())
if(t.isAssignableFrom(d.clazz))
r.add(d);
return r;
......
......@@ -24,10 +24,13 @@
package hudson.scm.browsers;
import hudson.model.Descriptor;
import hudson.model.Descriptor.FormException;
import hudson.scm.EditType;
import hudson.scm.RepositoryBrowser;
import hudson.scm.SubversionChangeLogSet;
import hudson.scm.SubversionRepositoryBrowser;
import hudson.Extension;
import java.io.IOException;
import java.net.URL;
import net.sf.json.JSONObject;
......@@ -42,19 +45,17 @@ import org.kohsuke.stapler.StaplerRequest;
*/
public class CollabNetSVN extends SubversionRepositoryBrowser
{
public static final Descriptor<RepositoryBrowser<?>> DESCRIPTOR
= new Descriptor<RepositoryBrowser<?>>() {
@Extension
public static class DescriptorImpl extends Descriptor<RepositoryBrowser<?>> {
public String getDisplayName() {
return "CollabNet";
}
@Override
public RepositoryBrowser<?> newInstance(StaplerRequest req,
JSONObject formData) throws FormException {
public RepositoryBrowser<?> newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return req.bindParameters(CollabNetSVN.class, "collabnet.svn.");
}
};
}
public final URL url;
......@@ -110,12 +111,4 @@ public class CollabNetSVN extends SubversionRepositoryBrowser
query.add("view=rev");
return new URL(url, query.toString());
}
/**
* {@inheritDoc}
*/
public Descriptor<RepositoryBrowser<?>> getDescriptor() {
return DESCRIPTOR;
}
}
......@@ -24,6 +24,7 @@
package hudson.scm.browsers;
import hudson.Util;
import hudson.Extension;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.scm.CVSChangeLogSet;
......@@ -76,12 +77,7 @@ public final class FishEyeCVS extends CVSRepositoryBrowser {
return null;
}
public DescriptorImpl getDescriptor() {
return DESCRIPTOR;
}
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
@Extension
public static class DescriptorImpl extends Descriptor<RepositoryBrowser<?>> {
@Override
public String getDisplayName() {
......
......@@ -32,6 +32,7 @@ import hudson.scm.SubversionChangeLogSet.Path;
import hudson.scm.SubversionRepositoryBrowser;
import hudson.scm.EditType;
import hudson.util.FormFieldValidator;
import hudson.Extension;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.DataBoundConstructor;
......@@ -121,12 +122,7 @@ public class FishEyeSVN extends SubversionRepositoryBrowser {
return new URL(url,"../../changelog/"+getProjectName()+"/?cs="+changeSet.getRevision());
}
public Descriptor<RepositoryBrowser<?>> getDescriptor() {
return DESCRIPTOR;
}
public static final Descriptor<RepositoryBrowser<?>> DESCRIPTOR = new DescriptorImpl();
@Extension
public static class DescriptorImpl extends Descriptor<RepositoryBrowser<?>> {
public String getDisplayName() {
return "FishEye";
......
......@@ -31,6 +31,7 @@ import hudson.scm.SubversionChangeLogSet.Path;
import hudson.scm.SubversionRepositoryBrowser;
import hudson.scm.EditType;
import hudson.util.FormFieldValidator;
import hudson.Extension;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.DataBoundConstructor;
......@@ -121,12 +122,7 @@ public class Sventon extends SubversionRepositoryBrowser {
repositoryInstance,changeSet.getRevision()));
}
public Descriptor<RepositoryBrowser<?>> getDescriptor() {
return DESCRIPTOR;
}
public static final Descriptor<RepositoryBrowser<?>> DESCRIPTOR = new DescriptorImpl();
@Extension
public static class DescriptorImpl extends Descriptor<RepositoryBrowser<?>> {
public String getDisplayName() {
return "Sventon";
......
......@@ -29,6 +29,7 @@ import hudson.scm.CVSChangeLogSet.File;
import hudson.scm.CVSChangeLogSet.Revision;
import hudson.scm.CVSRepositoryBrowser;
import hudson.scm.RepositoryBrowser;
import hudson.Extension;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.DataBoundConstructor;
......@@ -79,15 +80,12 @@ public final class ViewCVS extends CVSRepositoryBrowser {
return new QueryBuilder(url.getQuery());
}
public Descriptor<RepositoryBrowser<?>> getDescriptor() {
return DESCRIPTOR;
}
public static final Descriptor<RepositoryBrowser<?>> DESCRIPTOR = new Descriptor<RepositoryBrowser<?>>() {
@Extension
public static class DescriptorImpl extends Descriptor<RepositoryBrowser<?>> {
public String getDisplayName() {
return "ViewCVS";
}
};
}
private static final long serialVersionUID = 1L;
}
......@@ -29,6 +29,7 @@ import hudson.scm.RepositoryBrowser;
import hudson.scm.SubversionChangeLogSet;
import hudson.scm.SubversionChangeLogSet.Path;
import hudson.scm.SubversionRepositoryBrowser;
import hudson.Extension;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.DataBoundConstructor;
......@@ -80,15 +81,10 @@ public class ViewSVN extends SubversionRepositoryBrowser {
return new QueryBuilder(url.getQuery());
}
public DescriptorImpl getDescriptor() {
return DescriptorImpl.INSTANCE;
}
private static final long serialVersionUID = 1L;
@Extension
public static final class DescriptorImpl extends Descriptor<RepositoryBrowser<?>> {
public static final DescriptorImpl INSTANCE = new DescriptorImpl();
public String getDisplayName() {
return "ViewSVN";
}
......
......@@ -32,6 +32,7 @@ import hudson.scm.SubversionChangeLogSet;
import hudson.scm.SubversionChangeLogSet.Path;
import hudson.scm.SubversionRepositoryBrowser;
import hudson.Extension;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.DataBoundConstructor;
......@@ -51,12 +52,12 @@ import java.net.URL;
*/
public class WebSVN extends SubversionRepositoryBrowser {
public static final Descriptor<RepositoryBrowser<?>> DESCRIPTOR =
new Descriptor<RepositoryBrowser<?>>() {
@Extension
public static class DescriptorImpl extends Descriptor<RepositoryBrowser<?>> {
public String getDisplayName() {
return "WebSVN";
}
};
}
private static final long serialVersionUID = 1L;
......@@ -135,13 +136,4 @@ public class WebSVN extends SubversionRepositoryBrowser {
private QueryBuilder param() {
return new QueryBuilder(url.getQuery());
}
/**
* Returns the descriptor value.
*
* @return the descriptor value.
*/
public Descriptor<RepositoryBrowser<?>> getDescriptor() {
return DESCRIPTOR;
}
}
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, 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 hudson.util;
import java.util.concurrent.ConcurrentHashMap;
/**
* Implements memoization semantics.
*
* <p>
* Conceputually a function from K -> V that computes values lazily and remembers the results.
* Often used to implement a data store per key.
*
* @author Kohsuke Kawaguchi
* @since 1.281
*/
public abstract class Memoizer<K,V> {
private final ConcurrentHashMap<K,V> store = new ConcurrentHashMap<K,V>();
public V get(K key) {
V v = store.get(key);
if(v!=null) return v;
// TODO: if we want to, we can avoid locking altogether by putting a sentinel value
// that represents "the value is being computed". FingerprintMap does this.
synchronized (this) {
v = store.get(key);
if(v!=null) return v;
v = compute(key);
store.put(key,v);
return v;
}
}
/**
* Creates a new instance.
*/
public abstract V compute(K key);
}
......@@ -30,7 +30,6 @@ import hudson.WebAppMain;
import hudson.Launcher.LocalLauncher;
import hudson.matrix.MatrixProject;
import hudson.maven.MavenModuleSet;
import hudson.maven.MavenReporters;
import hudson.model.Descriptor;
import hudson.model.FreeStyleProject;
import hudson.model.Hudson;
......@@ -300,7 +299,7 @@ public abstract class HudsonTestCase extends TestCase {
String home = System.getProperty("maven.home");
if(home!=null) {
MavenInstallation mavenInstallation = new MavenInstallation("default",home);
Maven.DESCRIPTOR.setInstallations(mavenInstallation);
((Maven.DescriptorImpl)hudson.getDescriptor(Maven.class)).setInstallations(mavenInstallation);
return mavenInstallation;
}
......@@ -320,7 +319,7 @@ public abstract class HudsonTestCase extends TestCase {
MavenInstallation mavenInstallation = new MavenInstallation("default",
new File(mvnHome,"maven-2.0.7").getAbsolutePath());
Maven.DESCRIPTOR.setInstallations(mavenInstallation);
((Maven.DescriptorImpl)hudson.getDescriptor(Maven.class)).setInstallations(mavenInstallation);
return mavenInstallation;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册