提交 2830cae0 编写于 作者: K kohsuke

[FIXED HUDSON-234] View is now an ExtensionPoint.

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@13950 71c3de6d-444a-0410-be80-ed276b4c234a
上级 74ffde7f
......@@ -253,11 +253,9 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
/*package*/ Integer quietPeriod;
/**
* {@link ListView}s.
* {@link View}s.
*/
private List<ListView> views; // can't initialize it eagerly for backward compatibility
private transient MyView myView = new MyView(this);
private List<View> views; // can't initialize it eagerly for backward compatibility
private transient final FingerprintMap fingerprintMap = new FingerprintMap();
......@@ -521,6 +519,17 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
return (JobPropertyDescriptor) d;
}
/**
* @deprecated
* This method is really just implementing {@link View#getDescriptor()}.
* It's unlikely that your program wants to invoke this method explicitly.
* Perhaps you meant {@link #getDescriptor(String)} ?
*/
public ViewDescriptor getDescriptor() {
// TODO
throw new UnsupportedOperationException();
}
/**
* Exposes {@link Descriptor} by its name to URL.
*
......@@ -824,17 +833,14 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
public synchronized View getView(String name) {
if(views!=null) {
for (ListView v : views) {
for (View v : views) {
if(v.getViewName().equals(name))
return v;
}
}
if (this.getViewName().equals(name)) {
if (this.getViewName().equals(name))
return this;
} else if (myView.getViewName().equals(name)) {
return myView;
} else
return null;
return null;
}
/**
......@@ -843,27 +849,15 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
@Exported
public synchronized View[] getViews() {
if(views==null)
views = new ArrayList<ListView>();
if(Functions.isAnonymous()) {
View[] r = new View[views.size()+1];
views.toArray(r);
// sort Views and put "all" at the very beginning
r[r.length-1] = r[0];
Arrays.sort(r,1,r.length, View.SORTER);
r[0] = this;
return r;
} else {
// this is an authenticated user, so let's have the "my projects" view
View[] r = new View[views.size()+2];
views.toArray(r);
r[r.length-2] = r[0];
r[r.length-1] = r[1];
Arrays.sort(r,2,r.length, View.SORTER);
r[0] = myView;
r[1] = this;
return r;
}
views = new ArrayList<View>();
View[] r = new View[views.size()+1];
views.toArray(r);
// sort Views and put "all" at the very beginning
r[r.length-1] = r[0];
Arrays.sort(r,1,r.length, View.SORTER);
r[0] = this;
return r;
}
public synchronized void deleteView(ListView view) throws IOException {
......@@ -1044,7 +1038,7 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
})
.add(new CollectionSearchIndex() {// for views
protected View get(String key) { return getView(key); }
protected Collection<ListView> all() { return views; }
protected Collection<View> all() { return views; }
});
}
......@@ -1334,11 +1328,12 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
items.remove(item.getName());
if(views!=null) {
for (ListView v : views) {
synchronized(v) {
v.jobNames.remove(item.getName());
}
}
// TODO: resurrect
// for (View v : views) {
// synchronized(v) {
// v.jobNames.remove(item.getName());
// }
// }
save();
}
}
......@@ -1352,12 +1347,13 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
items.put(newName,job);
if(views!=null) {
for (ListView v : views) {
synchronized(v) {
if(v.jobNames.remove(oldName))
v.jobNames.add(newName);
}
}
// TODO: resurrect
// for (View v : views) {
// synchronized(v) {
// if(v.jobNames.remove(oldName))
// v.jobNames.add(newName);
// }
// }
save();
}
}
......@@ -1885,27 +1881,33 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
}
public synchronized void doCreateView( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
checkPermission(View.CREATE);
try {
checkPermission(View.CREATE);
req.setCharacterEncoding("UTF-8");
req.setCharacterEncoding("UTF-8");
String name = req.getParameter("name");
String name = req.getParameter("name");
String mode = req.getParameter("mode");
try {
checkGoodName(name);
} catch (ParseException e) {
sendError(e, req, rsp);
return;
}
try {
checkGoodName(name);
} catch (ParseException e) {
sendError(e, req, rsp);
return;
}
ListView v = new ListView(this, name);
if(views==null)
views = new Vector<ListView>();
views.add(v);
save();
// create a view
View v = View.LIST.findByName(mode).newInstance(req,req.getSubmittedForm());
if(views==null)
views = new Vector<View>();
views.add(v);
save();
// redirect to the config screen
rsp.sendRedirect2("./"+v.getUrl()+"configure");
// redirect to the config screen
rsp.sendRedirect2("./"+v.getUrl()+"configure");
} catch (FormException e) {
sendError(e,req,rsp);
}
}
/**
......@@ -2321,6 +2323,28 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node,
}
}.process();
}
/**
* Checks if a top-level view with the given name exists.
*/
public void doViewExistsCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
new FormFieldValidator(req,rsp,View.CREATE) {
protected void check() throws IOException, ServletException {
String view = fixEmpty(request.getParameter("value"));
if(view==null) {
ok(); // nothing is entered yet
return;
}
if(getView(view)==null)
ok();
else
error(Messages.Hudson_ViewAlreadyExists(view));
}
}.process();
}
/**
* Checks if the value for a field is set; if not an error or warning text is displayed.
* If the parameter "value" is not set then the parameter "errorText" is displayed
......
......@@ -6,6 +6,7 @@ import hudson.util.FormFieldValidator;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.DataBoundConstructor;
import javax.servlet.ServletException;
import java.io.IOException;
......@@ -51,9 +52,10 @@ public class ListView extends View {
*/
private transient Pattern includePattern;
public ListView(Hudson owner, String name) {
@DataBoundConstructor
public ListView(String name) {
this.name = name;
this.owner = owner;
this.owner = Hudson.getInstance();
}
/**
......@@ -120,10 +122,6 @@ public class ListView extends View {
return description;
}
public String getDisplayName() {
return name;
}
public String getIncludeRegex() {
return includeRegex;
}
......@@ -203,7 +201,7 @@ public class ListView extends View {
/**
* Checks if the include regular expression is valid.
*/
public synchronized void doIncludeRegexCheck( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException, InterruptedException {
public void doIncludeRegexCheck( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException, InterruptedException {
new FormFieldValidator(req, rsp, false) {
@Override
protected void check() throws IOException, ServletException {
......@@ -219,4 +217,24 @@ public class ListView extends View {
}
}.process();
}
public ViewDescriptor getDescriptor() {
return DESCRIPTOR;
}
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
static {
LIST.add(DESCRIPTOR);
}
public static final class DescriptorImpl extends ViewDescriptor {
private DescriptorImpl() {
super(ListView.class);
}
public String getDisplayName() {
return "List View";
}
}
}
......@@ -10,6 +10,7 @@ import javax.servlet.ServletException;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.DataBoundConstructor;
/**
* {@link View} that only contains projects for which the current user has access to.
......@@ -18,17 +19,19 @@ import org.kohsuke.stapler.StaplerResponse;
* @author Tom Huybrechts
*/
public class MyView extends View {
private String name;
private final Hudson owner;
private String description;
public MyView(Hudson owner) {
this.owner = owner;
@DataBoundConstructor
public MyView(String name) {
this.name = name;
this.owner = Hudson.getInstance();
}
@Override
public boolean contains(TopLevelItem item) {
return (item instanceof Job) && ((Job) item).hasPermission(Hudson.ADMINISTER);
return item.hasPermission(Hudson.ADMINISTER);
}
@Override
......@@ -60,7 +63,7 @@ public class MyView extends View {
public Collection<TopLevelItem> getItems() {
List<TopLevelItem> items = new ArrayList<TopLevelItem>();
for (TopLevelItem item : owner.getItems()) {
if ((item instanceof Job) && ((Job) item).hasPermission(Job.CONFIGURE)) {
if (item.hasPermission(Job.CONFIGURE)) {
items.add(item);
}
}
......@@ -74,11 +77,7 @@ public class MyView extends View {
@Override
public String getViewName() {
return getDisplayName();
}
public String getDisplayName() {
return "My Projects";
return name;
}
public TopLevelItem getJob(String name) {
......@@ -96,4 +95,24 @@ public class MyView extends View {
owner.save();
rsp.sendRedirect("."); // go to the top page
}
public ViewDescriptor getDescriptor() {
return DESCRIPTOR;
}
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
static {
LIST.add(DESCRIPTOR);
}
public static final class DescriptorImpl extends ViewDescriptor {
private DescriptorImpl() {
super(MyView.class);
}
public String getDisplayName() {
return "My View";
}
}
}
package hudson.model;
import hudson.Util;
import hudson.FileSystemProvisioner;
import hudson.ExtensionPoint;
import hudson.security.AccessControlled;
import hudson.security.Permission;
import hudson.security.ACL;
......@@ -9,6 +11,7 @@ import hudson.scm.ChangeLogSet.Entry;
import hudson.search.CollectionSearchIndex;
import hudson.search.SearchIndexBuilder;
import hudson.util.RunList;
import hudson.util.DescriptorList;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
......@@ -31,10 +34,20 @@ import java.util.Map;
* Encapsulates the rendering of the list of {@link TopLevelItem}s
* that {@link Hudson} owns.
*
* <p>
* This is an extension point in Hudson, allowing different kind of
* rendering to be added as plugins.
*
* <h2>Note for implementors</h2>
* <ul>
* <li>
* {@link View} subtypes need
* </ul>
*
* @author Kohsuke Kawaguchi
*/
@ExportedBean
public abstract class View extends AbstractModelObject implements AccessControlled {
public abstract class View extends AbstractModelObject implements AccessControlled, Describable<View>, ExtensionPoint {
/**
* Gets all the items in this collection in a read-only view.
......@@ -64,6 +77,12 @@ public abstract class View extends AbstractModelObject implements AccessControll
@Exported
public abstract String getDescription();
public abstract ViewDescriptor getDescriptor();
public String getDisplayName() {
return getViewName();
}
/**
* Returns the path relative to the context root.
*
......@@ -260,6 +279,10 @@ public abstract class View extends AbstractModelObject implements AccessControll
/**
* Creates a new {@link Item} in this collection.
*
* <p>
* This method should call {@link Hudson#doCreateItem(StaplerRequest, StaplerResponse)}
* and then add the newly created item to this view.
*
* @return
* null if fails.
*/
......@@ -295,6 +318,16 @@ public abstract class View extends AbstractModelObject implements AccessControll
lastBuilds, Run.FEED_ADAPTER_LATEST, req, rsp );
}
/**
* A list of available view types.
*/
public static final DescriptorList<View> LIST = new DescriptorList<View>();
static {
LIST.load(ListView.class);
LIST.load(MyView.class);
}
public static final Comparator<View> SORTER = new Comparator<View>() {
public int compare(View lhs, View rhs) {
return lhs.getViewName().compareTo(rhs.getViewName());
......
package hudson.model;
/**
* {@link Descriptor} for {@link View}.
*
* @author Kohsuke Kawaguchi
* @see View#LIST
*/
public abstract class ViewDescriptor extends Descriptor<View> {
/**
* Returns the human-readable name of this type of view. Used
* in the view creation screen. The string should look like
* "Abc Def Ghi".
*/
public abstract String getDisplayName();
/**
* Some special views are not instantiable, and for those
* this method returns false.
*/
public boolean isInstantiable() {
return true;
}
/**
* Jelly fragment included in the "new view" page.
*/
public final String getNewViewDetailPage() {
return '/'+clazz.getName().replace('.','/').replace('$','/')+"/newViewDetail.jelly";
}
protected ViewDescriptor(Class<? extends View> clazz) {
super(clazz);
}
}
......@@ -67,7 +67,6 @@ public abstract class JobListener implements ExtensionPoint {
JobListenerAdapter that = (JobListenerAdapter) o;
return this.listener.equals(that.listener);
}
public int hashCode() {
......
<div>
${%blurb}
</div>
\ No newline at end of file
blurb=\
Shows jobs in a simple list format. You can choose which jobs are to be displayed in which view.
\ No newline at end of file
......@@ -54,6 +54,7 @@ Hudson.NotAPlugin={0} is not a Hudson plugin
Hudson.NotJDKDir={0} doesn''t look like a JDK directory
Hudson.Permissions.Title=Overall
Hudson.UnsafeChar=''{0}'' is an unsafe character
Hudson.ViewAlreadyExists=A view already exists with the name "{0}"
Hudson.ViewName=All
Hudson.NotANumber=Not a number
Hudson.NotAPositiveNumber=Not a positive number
......
<div>
${%blurb}
</div>
\ No newline at end of file
blurb=\
This view automatically displays all the jobs that the current user has an access to.
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册