File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\model\MultiStageTimeSeries.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.model;
25
26 import hudson.util.TimeUnit2;
27 import hudson.util.NoOverlapCategoryAxis;
28 import hudson.util.ChartUtil;
29
30 import java.io.Serializable;
31 import java.text.DateFormat;
32 import java.text.SimpleDateFormat;
33 import java.util.Date;
34 import java.util.Arrays;
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.io.IOException;
38 import java.awt.*;
39 import java.util.Locale;
40
41 import org.jfree.data.category.DefaultCategoryDataset;
42 import org.jfree.chart.JFreeChart;
43 import org.jfree.chart.ChartFactory;
44 import org.jfree.chart.axis.CategoryAxis;
45 import org.jfree.chart.axis.CategoryLabelPositions;
46 import org.jfree.chart.axis.NumberAxis;
47 import org.jfree.chart.renderer.category.LineAndShapeRenderer;
48 import org.jfree.chart.plot.PlotOrientation;
49 import org.jfree.chart.plot.CategoryPlot;
50 import org.jfree.ui.RectangleInsets;
51 import org.jvnet.localizer.Localizable;
52 import org.kohsuke.stapler.HttpResponse;
53 import org.kohsuke.stapler.StaplerRequest;
54 import org.kohsuke.stapler.StaplerResponse;
55 import org.kohsuke.stapler.export.Exported;
56 import org.kohsuke.stapler.export.ExportedBean;
57
58 import javax.servlet.ServletException;
59
60 /**
61 * Maintains several {@link TimeSeries} with different update frequencies to satisfy three goals;
62 * (1) retain data over long timespan, (2) save memory, and (3) retain accurate data for the recent past.
63 *
64 * All in all, one instance uses about 8KB space.
65 *
66 * @author Kohsuke Kawaguchi
67 */
68 @ExportedBean
69 public class MultiStageTimeSeries implements Serializable {
70 /**
71 * Name of this data series.
72 */
73 public final Localizable title;
74
75 /**
76 * Used to render a line in the trend chart.
77 */
78 public final Color color;
79
80 /**
81 * Updated every 10 seconds. Keep data up to 1 hour.
82 */
83 @Exported
84 public final TimeSeries sec10;
85 /**
86 * Updated every 1 min. Keep data up to 1 day.
87 */
88 @Exported
89 public final TimeSeries min;
90 /**
91 * Updated every 1 hour. Keep data up to 4 weeks.
92 */
93 @Exported
94 public final TimeSeries hour;
95
96 private int counter;
97
98 public MultiStageTimeSeries(Localizable title, Color color, float initialValue, float decay) {
99 this.title = title;
100 this.color = color;
101 this.sec10 = new TimeSeries(initialValue,decay,6*60);
102 this.min = new TimeSeries(initialValue,decay,60*24);
103 this.hour = new TimeSeries(initialValue,decay,28*24);
104 }
105
106 /**
107 * @deprecated since 2009-04-05.
108 * Use {@link #MultiStageTimeSeries(Localizable, Color, float, float)}
109 */
110 public MultiStageTimeSeries(float initialValue, float decay) {
111 this(Messages._MultiStageTimeSeries_EMPTY_STRING(), Color.WHITE, initialValue,decay);
112 }
113
114 /**
115 * Call this method every 10 sec and supply a new data point.
116 */
117 public void update(float f) {
118 counter = (counter+1)%360; // 1hour/10sec = 60mins/10sec=3600secs/10sec = 360
119 sec10.update(f);
120 if(counter%6==0) min.update(f);
121 if(counter==0) hour.update(f);
122 }
123
124 /**
125 * Selects a {@link TimeSeries}.
126 */
127 public TimeSeries pick(TimeScale timeScale) {
128 switch (timeScale) {
129 case HOUR: return hour;
130 case MIN: return min;
131 case SEC10: return sec10;
132 default: throw new AssertionError();
133 }
134 }
135
136 /**
137 * Gets the most up-to-date data point value.
138 */
139 public float getLatest(TimeScale timeScale) {
140 return pick(timeScale).getLatest();
141 }
142
143 public Api getApi() {
144 return new Api(this);
145 }
146
147 /**
148 * Choose which datapoint to use.
149 */
150 public enum TimeScale {
151 SEC10(TimeUnit2.SECONDS.toMillis(10)),
152 MIN(TimeUnit2.MINUTES.toMillis(1)),
153 HOUR(TimeUnit2.HOURS.toMillis(1));
154
155 /**
156 * Number of milliseconds (10 secs, 1 min, and 1 hour)
157 * that this constant represents.
158 */
159 public final long tick;
160
161 TimeScale(long tick) {
162 this.tick = tick;
163 }
164
165 /**
166 * Creates a new {@link DateFormat} suitable for processing
167 * this {@link TimeScale}.
168 */
169 public DateFormat createDateFormat() {
170 switch (this) {
171 case HOUR: return new SimpleDateFormat("MMM/dd HH");
172 case MIN: return new SimpleDateFormat("HH:mm");
173 case SEC10: return new SimpleDateFormat("HH:mm:ss");
174 default: throw new AssertionError();
175 }
176 }
177
178 /**
179 * Parses the {@link TimeScale} from the query parameter.
180 */
181 public static TimeScale parse(String type) {
182 if(type==null) return TimeScale.MIN;
183 return Enum.valueOf(TimeScale.class, type.toUpperCase(Locale.ENGLISH));
184 }
185 }
186
187 /**
188 * Represents the trend chart that consists of several {@link MultiStageTimeSeries}.
189 *
190 * <p>
191 * This object is renderable as HTTP response.
192 */
193 public static class TrendChart implements HttpResponse {
194 public final TimeScale timeScale;
195 public final List<MultiStageTimeSeries> series;
196 public final DefaultCategoryDataset dataset;
197
198 public TrendChart(TimeScale timeScale, MultiStageTimeSeries... series) {
199 this.timeScale = timeScale;
200 this.series = new ArrayList<MultiStageTimeSeries>(Arrays.asList(series));
201 this.dataset = createDataset();
202 }
203
204 /**
205 * Creates a {@link DefaultCategoryDataset} for rendering a graph from a set of {@link MultiStageTimeSeries}.
206 */
207 protected DefaultCategoryDataset createDataset() {
208 float[][] dataPoints = new float[series.size()][];
209 for (int i = 0; i < series.size(); i++)
210 dataPoints[i] = series.get(i).pick(timeScale).getHistory();
211
212 int dataLength = dataPoints[0].length;
213 for (float[] dataPoint : dataPoints)
214 assert dataLength ==dataPoint.length;
215
216 DefaultCategoryDataset ds = new DefaultCategoryDataset();
217
218 DateFormat format = timeScale.createDateFormat();
219
220 Date dt = new Date(System.currentTimeMillis()-timeScale.tick*dataLength);
221 for (int i = dataLength-1; i>=0; i--) {
222 dt = new Date(dt.getTime()+timeScale.tick);
223 String l = format.format(dt);
224 for(int j=0; j<dataPoints.length; j++)
225 ds.addValue(dataPoints[j][i],series.get(j).title.toString(),l);
226 }
227 return ds;
228 }
229
230 /**
231 * Draws a chart into {@link JFreeChart}.
232 */
233 public JFreeChart createChart() {
234 final JFreeChart chart = ChartFactory.createLineChart(null, // chart title
235 null, // unused
236 null, // range axis label
237 dataset, // data
238 PlotOrientation.VERTICAL, // orientation
239 true, // include legend
240 true, // tooltips
241 false // urls
242 );
243
244 chart.setBackgroundPaint(Color.white);
245
246 final CategoryPlot plot = chart.getCategoryPlot();
247 configurePlot(plot);
248
249 configureRangeAxis((NumberAxis) plot.getRangeAxis());
250
251 crop(plot);
252
253 return chart;
254 }
255
256 protected void configureRangeAxis(NumberAxis rangeAxis) {
257 rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
258 }
259
260 protected void crop(CategoryPlot plot) {
261 // crop extra space around the graph
262 plot.setInsets(new RectangleInsets(0, 0, 0, 5.0));
263 }
264
265 protected CategoryAxis configureDomainAxis(CategoryPlot plot) {
266 final CategoryAxis domainAxis = new NoOverlapCategoryAxis(null);
267 plot.setDomainAxis(domainAxis);
268 domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
269 domainAxis.setLowerMargin(0.0);
270 domainAxis.setUpperMargin(0.0);
271 domainAxis.setCategoryMargin(0.0);
272 return domainAxis;
273 }
274
275 protected void configureRenderer(LineAndShapeRenderer renderer) {
276 renderer.setBaseStroke(new BasicStroke(3));
277
278 for (int i = 0; i < series.size(); i++)
279 renderer.setSeriesPaint(i, series.get(i).color);
280 }
281
282 protected void configurePlot(CategoryPlot plot) {
283 plot.setBackgroundPaint(Color.WHITE);
284 plot.setOutlinePaint(null);
285 plot.setRangeGridlinesVisible(true);
286 plot.setRangeGridlinePaint(Color.black);
287
288 configureRenderer((LineAndShapeRenderer) plot.getRenderer());
289 configureDomainAxis(plot);
290 }
291
292 /**
293 * Renders this object as an image.
294 */
295 public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
296 ChartUtil.generateGraph(req, rsp, createChart(), 500, 400);
297 }
298 }
299
300 public static TrendChart createTrendChart(TimeScale scale, MultiStageTimeSeries... data) {
301 return new TrendChart(scale,data);
302 }
303
304 private static final long serialVersionUID = 1L;
305 }
306