/hudson-core/src/main/java/hudson/model/ListView.java

http://github.com/hudson/hudson · Java · 282 lines · 167 code · 37 blank · 78 comment · 34 complexity · a24b5b53154c26635315a6e0c5c84f57 MD5 · raw file

  1. /*
  2. * The MIT License
  3. *
  4. * Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi,
  5. * Erik Ramfelt, Seiji Sogabe, Martin Eigenbrodt, Alan Harder
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. */
  25. package hudson.model;
  26. import hudson.Extension;
  27. import hudson.Util;
  28. import hudson.model.Descriptor.FormException;
  29. import hudson.util.CaseInsensitiveComparator;
  30. import hudson.util.DescribableList;
  31. import hudson.util.FormValidation;
  32. import hudson.views.ListViewColumn;
  33. import hudson.views.ViewJobFilter;
  34. import org.kohsuke.stapler.DataBoundConstructor;
  35. import org.kohsuke.stapler.QueryParameter;
  36. import org.kohsuke.stapler.StaplerRequest;
  37. import org.kohsuke.stapler.StaplerResponse;
  38. import javax.servlet.ServletException;
  39. import java.io.IOException;
  40. import java.util.ArrayList;
  41. import java.util.LinkedHashSet;
  42. import java.util.List;
  43. import java.util.SortedSet;
  44. import java.util.TreeSet;
  45. import java.util.regex.Pattern;
  46. import java.util.regex.PatternSyntaxException;
  47. /**
  48. * Displays {@link Job}s in a flat list view.
  49. *
  50. * @author Kohsuke Kawaguchi
  51. */
  52. public class ListView extends View implements Saveable {
  53. /**
  54. * List of job names. This is what gets serialized.
  55. */
  56. /*package*/ final SortedSet<String> jobNames = new TreeSet<String>(CaseInsensitiveComparator.INSTANCE);
  57. private DescribableList<ViewJobFilter, Descriptor<ViewJobFilter>> jobFilters;
  58. private DescribableList<ListViewColumn, Descriptor<ListViewColumn>> columns;
  59. /**
  60. * Include regex string.
  61. */
  62. private String includeRegex;
  63. /**
  64. * Compiled include pattern from the includeRegex string.
  65. */
  66. private transient Pattern includePattern;
  67. /**
  68. * Filter by enabled/disabled status of jobs.
  69. * Null for no filter, true for enabled-only, false for disabled-only.
  70. */
  71. private Boolean statusFilter;
  72. @DataBoundConstructor
  73. public ListView(String name) {
  74. super(name);
  75. initColumns();
  76. initJobFilters();
  77. }
  78. public ListView(String name, ViewGroup owner) {
  79. this(name);
  80. this.owner = owner;
  81. }
  82. public void save() throws IOException {
  83. // persistence is a part of the owner.
  84. // due to the initialization timing issue, it can be null when this method is called.
  85. if (owner!=null)
  86. owner.save();
  87. }
  88. private Object readResolve() {
  89. if(includeRegex!=null)
  90. includePattern = Pattern.compile(includeRegex);
  91. initColumns();
  92. initJobFilters();
  93. return this;
  94. }
  95. protected void initColumns() {
  96. if (columns == null)
  97. columns = new DescribableList<ListViewColumn, Descriptor<ListViewColumn>>(this,ListViewColumn.createDefaultInitialColumnList());
  98. }
  99. protected void initJobFilters() {
  100. if (jobFilters == null)
  101. jobFilters = new DescribableList<ViewJobFilter, Descriptor<ViewJobFilter>>(this);
  102. }
  103. /**
  104. * Used to determine if we want to display the Add button.
  105. */
  106. public boolean hasJobFilterExtensions() {
  107. return !ViewJobFilter.all().isEmpty();
  108. }
  109. public DescribableList<ViewJobFilter, Descriptor<ViewJobFilter>> getJobFilters() {
  110. return jobFilters;
  111. }
  112. public Iterable<ListViewColumn> getColumns() {
  113. return columns;
  114. }
  115. /**
  116. * Returns a read-only view of all {@link Job}s in this view.
  117. *
  118. * <p>
  119. * This method returns a separate copy each time to avoid
  120. * concurrent modification issue.
  121. */
  122. public synchronized List<TopLevelItem> getItems() {
  123. SortedSet<String> names = new TreeSet<String>(jobNames);
  124. if (includePattern != null) {
  125. for (TopLevelItem item : Hudson.getInstance().getItems()) {
  126. String itemName = item.getName();
  127. if (includePattern.matcher(itemName).matches()) {
  128. names.add(itemName);
  129. }
  130. }
  131. }
  132. List<TopLevelItem> items = new ArrayList<TopLevelItem>(names.size());
  133. for (String n : names) {
  134. TopLevelItem item = Hudson.getInstance().getItem(n);
  135. // Add if no status filter or filter matches enabled/disabled status:
  136. if(item!=null && (statusFilter == null || !(item instanceof AbstractProject)
  137. || ((AbstractProject)item).isDisabled() ^ statusFilter))
  138. items.add(item);
  139. }
  140. // check the filters
  141. Iterable<ViewJobFilter> jobFilters = getJobFilters();
  142. List<TopLevelItem> allItems = Hudson.getInstance().getItems();
  143. for (ViewJobFilter jobFilter: jobFilters) {
  144. items = jobFilter.filter(items, allItems, this);
  145. }
  146. // for sanity, trim off duplicates
  147. items = new ArrayList<TopLevelItem>(new LinkedHashSet<TopLevelItem>(items));
  148. return items;
  149. }
  150. public boolean contains(TopLevelItem item) {
  151. return jobNames.contains(item.getName());
  152. }
  153. /**
  154. * Adds the given item to this view.
  155. *
  156. * @since 1.389
  157. */
  158. public void add(TopLevelItem item) throws IOException {
  159. jobNames.add(item.getName());
  160. save();
  161. }
  162. public String getIncludeRegex() {
  163. return includeRegex;
  164. }
  165. /**
  166. * Filter by enabled/disabled status of jobs.
  167. * Null for no filter, true for enabled-only, false for disabled-only.
  168. */
  169. public Boolean getStatusFilter() {
  170. return statusFilter;
  171. }
  172. public synchronized Item doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
  173. Item item = Hudson.getInstance().doCreateItem(req, rsp);
  174. if(item!=null) {
  175. jobNames.add(item.getName());
  176. owner.save();
  177. }
  178. return item;
  179. }
  180. @Override
  181. public synchronized void onJobRenamed(Item item, String oldName, String newName) {
  182. if(jobNames.remove(oldName) && newName!=null)
  183. jobNames.add(newName);
  184. }
  185. /**
  186. * Handles the configuration submission.
  187. *
  188. * Load view-specific properties here.
  189. */
  190. @Override
  191. protected void submit(StaplerRequest req) throws ServletException, FormException, IOException {
  192. jobNames.clear();
  193. for (TopLevelItem item : Hudson.getInstance().getItems()) {
  194. if(req.getParameter(item.getName())!=null)
  195. jobNames.add(item.getName());
  196. }
  197. if (req.getParameter("useincluderegex") != null) {
  198. includeRegex = Util.nullify(req.getParameter("includeRegex"));
  199. if (includeRegex == null)
  200. includePattern = null;
  201. else
  202. includePattern = Pattern.compile(includeRegex);
  203. } else {
  204. includeRegex = null;
  205. includePattern = null;
  206. }
  207. if (columns == null) {
  208. columns = new DescribableList<ListViewColumn,Descriptor<ListViewColumn>>(this);
  209. }
  210. columns.rebuildHetero(req, req.getSubmittedForm(), ListViewColumn.all(), "columns");
  211. if (jobFilters == null) {
  212. jobFilters = new DescribableList<ViewJobFilter,Descriptor<ViewJobFilter>>(this);
  213. }
  214. jobFilters.rebuildHetero(req, req.getSubmittedForm(), ViewJobFilter.all(), "jobFilters");
  215. String filter = Util.fixEmpty(req.getParameter("statusFilter"));
  216. statusFilter = filter != null ? "1".equals(filter) : null;
  217. }
  218. @Extension
  219. public static final class DescriptorImpl extends ViewDescriptor {
  220. public String getDisplayName() {
  221. return Messages.ListView_DisplayName();
  222. }
  223. /**
  224. * Checks if the include regular expression is valid.
  225. */
  226. public FormValidation doCheckIncludeRegex( @QueryParameter String value ) throws IOException, ServletException, InterruptedException {
  227. String v = Util.fixEmpty(value);
  228. if (v != null) {
  229. try {
  230. Pattern.compile(v);
  231. } catch (PatternSyntaxException pse) {
  232. return FormValidation.error(pse.getMessage());
  233. }
  234. }
  235. return FormValidation.ok();
  236. }
  237. }
  238. /**
  239. * @deprecated as of 1.391
  240. * Use {@link ListViewColumn#createDefaultInitialColumnList()}
  241. */
  242. public static List<ListViewColumn> getDefaultColumns() {
  243. return ListViewColumn.createDefaultInitialColumnList();
  244. }
  245. }