提交 2aadc597 编写于 作者: K kohsuke

renamed the following classes in preparation to make views extensible:

View -> ListView
JobCollection -> View


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@1802 71c3de6d-444a-0410-be80-ed276b4c234a
上级 d304d19f
......@@ -75,7 +75,7 @@ import java.util.logging.LogRecord;
*
* @author Kohsuke Kawaguchi
*/
public final class Hudson extends JobCollection implements Node {
public final class Hudson extends View implements Node {
private transient final Queue queue = new Queue();
/**
......@@ -136,9 +136,9 @@ public final class Hudson extends JobCollection implements Node {
/*package*/ Integer quietPeriod;
/**
* {@link View}s.
* {@link ListView}s.
*/
private List<View> views; // can't initialize it eagerly for backward compatibility
private List<ListView> views; // can't initialize it eagerly for backward compatibility
private transient final FingerprintMap fingerprintMap = new FingerprintMap();
......@@ -404,9 +404,9 @@ public final class Hudson extends JobCollection implements Node {
return true;
}
public synchronized JobCollection getView(String name) {
public synchronized View getView(String name) {
if(views!=null) {
for (View v : views) {
for (ListView v : views) {
if(v.getViewName().equals(name))
return v;
}
......@@ -418,21 +418,21 @@ public final class Hudson extends JobCollection implements Node {
}
/**
* Gets the read-only list of all {@link JobCollection}s.
* Gets the read-only list of all {@link View}s.
*/
public synchronized JobCollection[] getViews() {
public synchronized View[] getViews() {
if(views==null)
views = new ArrayList<View>();
JobCollection[] r = new JobCollection[views.size()+1];
views = new ArrayList<ListView>();
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,JobCollection.SORTER);
Arrays.sort(r,1,r.length, View.SORTER);
r[0] = this;
return r;
}
public synchronized void deleteView(View view) throws IOException {
public synchronized void deleteView(ListView view) throws IOException {
if(views!=null) {
views.remove(view);
save();
......@@ -632,7 +632,7 @@ public final class Hudson extends JobCollection implements Node {
jobs.remove(job.getName());
if(views!=null) {
for (View v : views) {
for (ListView v : views) {
synchronized(v) {
v.jobNames.remove(job.getName());
}
......@@ -650,7 +650,7 @@ public final class Hudson extends JobCollection implements Node {
jobs.put(newName,job);
if(views!=null) {
for (View v : views) {
for (ListView v : views) {
synchronized(v) {
if(v.jobNames.remove(oldName))
v.jobNames.add(newName);
......@@ -935,9 +935,9 @@ public final class Hudson extends JobCollection implements Node {
return;
}
View v = new View(this, name);
ListView v = new ListView(this, name);
if(views==null)
views = new Vector<View>();
views = new Vector<ListView>();
views.add(v);
save();
......@@ -1309,7 +1309,9 @@ public final class Hudson extends JobCollection implements Node {
static {
XSTREAM.alias("hudson",Hudson.class);
XSTREAM.alias("slave",Slave.class);
XSTREAM.alias("view",View.class);
XSTREAM.alias("jdk",JDK.class);
// for backward compatibility with <1.75, recognize the tag name "view" as well.
XSTREAM.alias("view", ListView.class);
XSTREAM.alias("listView", ListView.class);
}
}
package hudson.model;
import hudson.Util;
import hudson.scm.ChangeLogSet.Entry;
import hudson.util.RunList;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Collection of {@link Job}s.
*
* @author Kohsuke Kawaguchi
*/
public abstract class JobCollection extends AbstractModelObject {
/**
* Gets all the jobs in this collection.
*/
public abstract Collection<Job> getJobs();
/**
* Checks if the job is in this collection.
*/
public abstract boolean containsJob(Job job);
/**
* Gets the name of all this collection.
*/
public abstract String getViewName();
/**
* Message displayed in the top page. Can be null. Includes HTML.
*/
public abstract String getDescription();
/**
* Returns the path relative to the context root.
*/
public abstract String getUrl();
public static final class UserInfo implements Comparable<UserInfo> {
private final User user;
private Calendar lastChange;
private Project project;
UserInfo(User user, Project p, Calendar lastChange) {
this.user = user;
this.project = p;
this.lastChange = lastChange;
}
public User getUser() {
return user;
}
public Calendar getLastChange() {
return lastChange;
}
public Project getProject() {
return project;
}
/**
* Returns a human-readable string representation of when this user was last active.
*/
public String getLastChangeTimeString() {
long duration = new GregorianCalendar().getTimeInMillis()-lastChange.getTimeInMillis();
return Util.getTimeSpanString(duration);
}
public String getTimeSortKey() {
return Util.XS_DATETIME_FORMATTER.format(lastChange.getTime());
}
public int compareTo(UserInfo that) {
return that.lastChange.compareTo(this.lastChange);
}
}
/**
* Does this {@link JobCollection} has any associated user information recorded?
*/
public final boolean hasPeople() {
for (Job job : getJobs()) {
if (job instanceof Project) {
Project p = (Project) job;
for (Build build : p.getBuilds()) {
for (Entry entry : build.getChangeSet()) {
User user = entry.getAuthor();
if(user!=null)
return true;
}
}
}
}
return false;
}
/**
* Gets the users that show up in the changelog of this job collection.
*/
public final List<UserInfo> getPeople() {
Map<User,UserInfo> users = new HashMap<User,UserInfo>();
for (Job job : getJobs()) {
if (job instanceof Project) {
Project p = (Project) job;
for (Build build : p.getBuilds()) {
for (Entry entry : build.getChangeSet()) {
User user = entry.getAuthor();
UserInfo info = users.get(user);
if(info==null)
users.put(user,new UserInfo(user,p,build.getTimestamp()));
else
if(info.getLastChange().before(build.getTimestamp())) {
info.project = p;
info.lastChange = build.getTimestamp();
}
}
}
}
}
List<UserInfo> r = new ArrayList<UserInfo>(users.values());
Collections.sort(r);
return r;
}
/**
* Creates a job in this collection.
*
* @return
* null if fails.
*/
public abstract Job doCreateJob( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException;
public void doRssAll( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
rss(req, rsp, " all builds", new RunList(getJobs()));
}
public void doRssFailed( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
rss(req, rsp, " failed builds", new RunList(getJobs()).failureOnly());
}
private void rss(StaplerRequest req, StaplerResponse rsp, String suffix, RunList runs) throws IOException, ServletException {
RSS.forwardToRss(getDisplayName()+ suffix, getUrl(),
runs.newBuilds(), Run.FEED_ADAPTER, req, rsp );
}
public static final Comparator<JobCollection> SORTER = new Comparator<JobCollection>() {
public int compare(JobCollection lhs, JobCollection rhs) {
return lhs.getViewName().compareTo(rhs.getViewName());
}
};
}
package hudson.model;
import hudson.Util;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* Represents a collection of {@link Job}s.
*
* @author Kohsuke Kawaguchi
*/
public class ListView extends View {
private final Hudson owner;
/**
* List of job names. This is what gets serialized.
*/
/*package*/ final Set<String> jobNames = new TreeSet<String>();
/**
* Name of this view.
*/
private String name;
/**
* Message displayed in the view page.
*/
private String description;
public ListView(Hudson owner, String name) {
this.name = name;
this.owner = owner;
}
/**
* Returns a read-only view of all {@link Job}s in this view.
*
* <p>
* This method returns a separate copy each time to avoid
* concurrent modification issue.
*/
public synchronized List<Job> getJobs() {
Job[] jobs = new Job[jobNames.size()];
int i=0;
for (String name : jobNames)
jobs[i++] = owner.getJob(name);
return Arrays.asList(jobs);
}
public Job getJob(String name) {
return owner.getJob(name);
}
public boolean containsJob(Job job) {
return jobNames.contains(job.getName());
}
public String getViewName() {
return name;
}
public String getDescription() {
return description;
}
public String getDisplayName() {
return name;
}
public Job doCreateJob(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
if(!Hudson.adminCheck(req,rsp))
return null;
Job job = owner.doCreateJob(req, rsp);
if(job!=null) {
jobNames.add(job.getName());
owner.save();
}
return job;
}
public String getUrl() {
return "view/"+name+'/';
}
/**
* Accepts submission from the configuration page.
*/
public synchronized void doConfigSubmit( StaplerRequest req, StaplerResponse rsp ) throws IOException {
if(!Hudson.adminCheck(req,rsp))
return;
req.setCharacterEncoding("UTF-8");
jobNames.clear();
for (Job job : owner.getJobs()) {
if(req.getParameter(job.getName())!=null)
jobNames.add(job.getName());
}
description = Util.nullify(req.getParameter("description"));
owner.save();
rsp.sendRedirect(".");
}
/**
* Accepts the new description.
*/
public synchronized void doSubmitDescription( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
if(!Hudson.adminCheck(req,rsp))
return;
req.setCharacterEncoding("UTF-8");
description = req.getParameter("description");
owner.save();
rsp.sendRedirect("."); // go to the top page
}
/**
* Deletes this view.
*/
public synchronized void doDoDelete( StaplerRequest req, StaplerResponse rsp ) throws IOException {
if(!Hudson.adminCheck(req,rsp))
return;
owner.deleteView(this);
rsp.sendRedirect2(req.getContextPath()+"/");
}
}
package hudson.model;
import hudson.Util;
import hudson.scm.ChangeLogSet.Entry;
import hudson.util.RunList;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.Map;
/**
* Represents a collection of {@link Job}s.
* Collection of {@link Job}s.
*
* @author Kohsuke Kawaguchi
*/
public class View extends JobCollection {
private final Hudson owner;
public abstract class View extends AbstractModelObject {
/**
* List of job names. This is what gets serialized.
* Gets all the jobs in this collection.
*/
/*package*/ final Set<String> jobNames = new TreeSet<String>();
public abstract Collection<Job> getJobs();
/**
* Name of this view.
* Checks if the job is in this collection.
*/
private String name;
public abstract boolean containsJob(Job job);
/**
* Message displayed in the view page.
* Gets the name of all this collection.
*/
private String description;
public abstract String getViewName();
public View(Hudson owner, String name) {
this.name = name;
this.owner = owner;
}
/**
* Message displayed in the top page. Can be null. Includes HTML.
*/
public abstract String getDescription();
/**
* Returns a read-only view of all {@link Job}s in this view.
*
* <p>
* This method returns a separate copy each time to avoid
* concurrent modification issue.
* Returns the path relative to the context root.
*/
public synchronized List<Job> getJobs() {
Job[] jobs = new Job[jobNames.size()];
int i=0;
for (String name : jobNames)
jobs[i++] = owner.getJob(name);
return Arrays.asList(jobs);
}
public abstract String getUrl();
public Job getJob(String name) {
return owner.getJob(name);
}
public static final class UserInfo implements Comparable<UserInfo> {
private final User user;
private Calendar lastChange;
private Project project;
public boolean containsJob(Job job) {
return jobNames.contains(job.getName());
}
UserInfo(User user, Project p, Calendar lastChange) {
this.user = user;
this.project = p;
this.lastChange = lastChange;
}
public String getViewName() {
return name;
}
public User getUser() {
return user;
}
public String getDescription() {
return description;
}
public Calendar getLastChange() {
return lastChange;
}
public String getDisplayName() {
return name;
}
public Project getProject() {
return project;
}
public Job doCreateJob(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
if(!Hudson.adminCheck(req,rsp))
return null;
/**
* Returns a human-readable string representation of when this user was last active.
*/
public String getLastChangeTimeString() {
long duration = new GregorianCalendar().getTimeInMillis()-lastChange.getTimeInMillis();
return Util.getTimeSpanString(duration);
}
Job job = owner.doCreateJob(req, rsp);
if(job!=null) {
jobNames.add(job.getName());
owner.save();
public String getTimeSortKey() {
return Util.XS_DATETIME_FORMATTER.format(lastChange.getTime());
}
return job;
}
public String getUrl() {
return "view/"+name+'/';
public int compareTo(UserInfo that) {
return that.lastChange.compareTo(this.lastChange);
}
}
/**
* Accepts submission from the configuration page.
* Does this {@link View} has any associated user information recorded?
*/
public synchronized void doConfigSubmit( StaplerRequest req, StaplerResponse rsp ) throws IOException {
if(!Hudson.adminCheck(req,rsp))
return;
req.setCharacterEncoding("UTF-8");
jobNames.clear();
for (Job job : owner.getJobs()) {
if(req.getParameter(job.getName())!=null)
jobNames.add(job.getName());
public final boolean hasPeople() {
for (Job job : getJobs()) {
if (job instanceof Project) {
Project p = (Project) job;
for (Build build : p.getBuilds()) {
for (Entry entry : build.getChangeSet()) {
User user = entry.getAuthor();
if(user!=null)
return true;
}
}
}
}
return false;
}
description = Util.nullify(req.getParameter("description"));
/**
* Gets the users that show up in the changelog of this job collection.
*/
public final List<UserInfo> getPeople() {
Map<User,UserInfo> users = new HashMap<User,UserInfo>();
for (Job job : getJobs()) {
if (job instanceof Project) {
Project p = (Project) job;
for (Build build : p.getBuilds()) {
for (Entry entry : build.getChangeSet()) {
User user = entry.getAuthor();
UserInfo info = users.get(user);
if(info==null)
users.put(user,new UserInfo(user,p,build.getTimestamp()));
else
if(info.getLastChange().before(build.getTimestamp())) {
info.project = p;
info.lastChange = build.getTimestamp();
}
}
}
}
}
owner.save();
List<UserInfo> r = new ArrayList<UserInfo>(users.values());
Collections.sort(r);
rsp.sendRedirect(".");
return r;
}
/**
* Accepts the new description.
* Creates a job in this collection.
*
* @return
* null if fails.
*/
public synchronized void doSubmitDescription( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
if(!Hudson.adminCheck(req,rsp))
return;
req.setCharacterEncoding("UTF-8");
description = req.getParameter("description");
owner.save();
rsp.sendRedirect("."); // go to the top page
public abstract Job doCreateJob( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException;
public void doRssAll( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
rss(req, rsp, " all builds", new RunList(getJobs()));
}
/**
* Deletes this view.
*/
public synchronized void doDoDelete( StaplerRequest req, StaplerResponse rsp ) throws IOException {
if(!Hudson.adminCheck(req,rsp))
return;
public void doRssFailed( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
rss(req, rsp, " failed builds", new RunList(getJobs()).failureOnly());
}
owner.deleteView(this);
rsp.sendRedirect2(req.getContextPath()+"/");
private void rss(StaplerRequest req, StaplerResponse rsp, String suffix, RunList runs) throws IOException, ServletException {
RSS.forwardToRss(getDisplayName()+ suffix, getUrl(),
runs.newBuilds(), Run.FEED_ADAPTER, req, rsp );
}
public static final Comparator<View> SORTER = new Comparator<View>() {
public int compare(View lhs, View rhs) {
return lhs.getViewName().compareTo(rhs.getViewName());
}
};
}
<!-- derived class can put additional tasks here -->
<j:jelly xmlns:j="jelly:core" />
<!--
Edit View Page
-->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:layout norefresh="true">
<st:include page="sidepanel.jelly" />
<l:main-panel>
<f:form method="post" action="configSubmit">
<f:entry title="Description" help="/help/view-config/description.html">
<textarea class="setting-input" name="description"
rows="5" style="width:100%">${it.description}</textarea>
</f:entry>
<f:entry title="Jobs">
<j:forEach var="job" items="${app.jobs}">
<f:checkbox name="${job.name}" checked="${it.containsJob(job)}" />
${job.name}
<br/>
</j:forEach>
</f:entry>
<f:block>
<input type="submit" name="Submit" value="OK" />
</f:block>
</f:form>
</l:main-panel>
</l:layout>
</j:jelly>
<!-- Delete view -->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:layout>
<st:include page="sidepanel.jelly" />
<l:main-panel>
<form method="get" action="doDelete">
Are you sure about deleting the view?
<input type="submit" value="Yes" />
</form>
</l:main-panel>
</l:layout>
</j:jelly>
\ No newline at end of file
<div>
This view has no jobs associated with it. Please <a href="configure">add some</a>
</div>
\ No newline at end of file
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:task icon="images/24x24/gear.gif" href="configure" title="Edit View" />
<l:task icon="images/24x24/edit-delete.gif" href="delete" title="Delete View" />
</j:jelly>
\ No newline at end of file
<!-- derived class can put additional tasks here -->
<j:jelly xmlns:j="jelly:core" />
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册