File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\widgets\HistoryWidget.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.widgets;
25
26 import hudson.Functions;
27 import hudson.model.ModelObject;
28 import hudson.model.Run;
29 import hudson.util.Iterators;
30
31 import org.kohsuke.stapler.Header;
32 import org.kohsuke.stapler.HttpResponses;
33 import org.kohsuke.stapler.Stapler;
34 import org.kohsuke.stapler.StaplerRequest;
35 import org.kohsuke.stapler.StaplerResponse;
36
37 import javax.servlet.ServletException;
38 import java.io.IOException;
39 import java.util.ArrayList;
40 import java.util.Iterator;
41 import java.util.List;
42
43 import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
44
45 /**
46 * Displays the history of records (normally {@link Run}s) on the side panel.
47 *
48 * @param <O>
49 * Owner of the widget.
50 * @param <T>
51 * Type individual record.
52 * @author Kohsuke Kawaguchi
53 */
54 public class HistoryWidget<O extends ModelObject,T> extends Widget {
55 /**
56 * The given data model of records. Newer ones first.
57 */
58 public Iterable<T> baseList;
59
60 /**
61 * Indicates the next build number that client ajax should fetch.
62 */
63 private String nextBuildNumberToFetch;
64
65 /**
66 * URL of the {@link #owner}.
67 */
68 public final String baseUrl;
69
70 public final O owner;
71
72 private boolean trimmed;
73
74 public final Adapter<? super T> adapter;
75
76 /**
77 * First transient build record. Everything >= this will be discarded when AJAX call is made.
78 */
79 private String firstTransientBuildKey;
80
81 /**
82 * @param owner
83 * The parent model object that owns this widget.
84 */
85 public HistoryWidget(O owner, Iterable<T> baseList, Adapter<? super T> adapter) {
86 this.adapter = adapter;
87 this.baseList = baseList;
88 this.baseUrl = Functions.getNearestAncestorUrl(Stapler.getCurrentRequest(),owner);
89 this.owner = owner;
90 }
91
92 /**
93 * Title of the widget.
94 */
95 public String getDisplayName() {
96 return Messages.BuildHistoryWidget_DisplayName();
97 }
98
99 @Override
100 public String getUrlName() {
101 return "buildHistory";
102 }
103
104 public String getFirstTransientBuildKey() {
105 return firstTransientBuildKey;
106 }
107
108 private Iterable<T> updateFirstTransientBuildKey(Iterable<T> source) {
109 String key=null;
110 for (T t : source)
111 if(adapter.isBuilding(t))
112 key = adapter.getKey(t);
113 firstTransientBuildKey = key;
114 return source;
115 }
116
117 /**
118 * The records to be rendered this time.
119 */
120 public Iterable<T> getRenderList() {
121 if(trimmed) {
122 List<T> lst;
123 if (baseList instanceof List) {
124 lst = (List<T>) baseList;
125 if(lst.size()>THRESHOLD)
126 return updateFirstTransientBuildKey(lst.subList(0,THRESHOLD));
127 trimmed=false;
128 return updateFirstTransientBuildKey(lst);
129 } else {
130 lst = new ArrayList<T>(THRESHOLD);
131 Iterator<T> itr = baseList.iterator();
132 while(lst.size()<=THRESHOLD && itr.hasNext())
133 lst.add(itr.next());
134 trimmed = itr.hasNext(); // if we don't have enough items in the base list, setting this to false will optimize the next getRenderList() invocation.
135 return updateFirstTransientBuildKey(lst);
136 }
137 } else {
138 // to prevent baseList's concrete type from getting picked up by <j:forEach> in view
139 return updateFirstTransientBuildKey(Iterators.wrap(baseList));
140 }
141 }
142
143 public boolean isTrimmed() {
144 return trimmed;
145 }
146
147 public void setTrimmed(boolean trimmed) {
148 this.trimmed = trimmed;
149 }
150
151 /**
152 * Handles AJAX requests from browsers to update build history.
153 *
154 * @param n
155 * The build 'number' to fetch. This is string because various variants
156 * uses non-numbers as the build key.
157 */
158 public void doAjax( StaplerRequest req, StaplerResponse rsp,
159 @Header("n") String n ) throws IOException, ServletException {
160
161 if (n==null) throw HttpResponses.error(SC_BAD_REQUEST,new Exception("Missing the 'n' HTTP header"));
162
163 rsp.setContentType("text/html;charset=UTF-8");
164
165 // pick up builds to send back
166 List<T> items = new ArrayList<T>();
167
168 String nn=null; // we'll compute next n here
169
170 // list up all builds >=n.
171 for (T t : baseList) {
172 if(adapter.compare(t,n)>=0) {
173 items.add(t);
174 if(adapter.isBuilding(t))
175 nn = adapter.getKey(t); // the next fetch should start from youngest build in progress
176 } else
177 break;
178 }
179
180 if (nn==null) {
181 if (items.isEmpty()) {
182 // nothing to report back. next fetch should retry the same 'n'
183 nn=n;
184 } else {
185 // every record fetched this time is frozen. next fetch should start from the next build
186 nn=adapter.getNextKey(adapter.getKey(items.get(0)));
187 }
188 }
189
190 baseList = items;
191
192 rsp.setHeader("n",nn);
193 firstTransientBuildKey = nn; // all builds >= nn should be marked transient
194
195 req.getView(this,"ajaxBuildHistory.jelly").forward(req,rsp);
196 }
197
198 private static final int THRESHOLD = Integer.getInteger(HistoryWidget.class.getName()+".threshold",30);
199
200 public String getNextBuildNumberToFetch() {
201 return nextBuildNumberToFetch;
202 }
203
204 public void setNextBuildNumberToFetch(String nextBuildNumberToFetch) {
205 this.nextBuildNumberToFetch = nextBuildNumberToFetch;
206 }
207
208 public interface Adapter<T> {
209 /**
210 * If record is newer than the key, return a positive number.
211 */
212 int compare(T record, String key);
213 String getKey(T record);
214 boolean isBuilding(T record);
215 String getNextKey(String key);
216 }
217 }
218