1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package de.desy.acop.displayers;
24
25 import java.beans.PropertyVetoException;
26 import java.util.ArrayList;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.ThreadPoolExecutor;
29 import java.util.concurrent.TimeUnit;
30
31 import com.cosylab.gui.displayers.DataConsumer;
32 import com.cosylab.gui.displayers.DataSource;
33 import com.cosylab.util.CommonException;
34
35 import de.desy.acop.chart.AcopGraphStyleEnum;
36 import de.desy.acop.displayers.chart.AcopChartConsumer;
37 import de.desy.acop.displayers.chart.AcopTrendChartConsumer;
38 import de.desy.acop.displayers.chart.HistoryParameters;
39 import de.desy.acop.displayers.chart.THistoryConnector;
40 import de.desy.acop.displayers.tools.AcopTrendChartEvent;
41 import de.desy.acop.displayers.tools.AcopTrendChartListener;
42 import de.desy.acop.displayers.tools.AcopGraphParameters;
43 import de.desy.acop.displayers.tools.AcopGraphHistoryParameters;
44 import de.desy.acop.displayers.tools.DismissableBlockingQueue;
45 import de.desy.acop.transport.ConnectionParameters;
46
47
48
49
50
51
52
53
54
55 public class AcopTrendChart extends AcopChartReorg {
56
57 private static final long serialVersionUID = 1L;
58
59 public static final String TIME_SPAN = "timeSpan";
60 public static final String AUTOSCALE_TO_LIVE_DATA = "autoScaleToLiveData";
61 public static final String CHECK_FOR_BAD_DATA = "checkForBadData";
62 public static final String TIMEOUT = "timeout";
63
64 private boolean scaleInitialized = false;
65 private boolean autoScaleToLiveData = true;
66 private double loadedHistoryStart;
67 private double loadedHistoryStop;
68
69 private boolean normalized = false;
70 private THistoryConnector tHistoryConnector;
71 private ExecutorService executorService;
72 private ArrayList<AcopTrendChartListener> acopTrendChartListeners = new ArrayList<AcopTrendChartListener>();
73
74
75
76
77
78 public AcopTrendChart() {
79 super();
80 getAcop().setGraphStyle(AcopGraphStyleEnum.TimeLin.ordinal());
81 }
82
83
84
85
86
87
88 public THistoryConnector getTHistoryConnector() {
89 if (tHistoryConnector == null) {
90 tHistoryConnector = new THistoryConnector();
91 }
92 return tHistoryConnector;
93 }
94
95
96
97
98
99 public ExecutorService getExecutorService() {
100 if (executorService == null) {
101 executorService = new ThreadPoolExecutor(1, 1, 0, TimeUnit.NANOSECONDS,
102 new DismissableBlockingQueue<Runnable>(1)){
103 @Override
104 protected void afterExecute(Runnable r, Throwable t) {
105 super.afterExecute(r, t);
106 if (t != null) {
107 reportProgress(new AcopTrendChartEvent(AcopTrendChart.this, AcopTrendChartEvent.EventType.ERROR, t));
108 }
109 }
110 };
111 }
112 return executorService;
113 }
114
115 private void loadHistory() {
116
117
118
119
120
121
122
123
124
125
126
127
128 obtainHistory();
129 }
130
131 private void obtainHistory() {
132 loadedHistoryStart = getLastTimestamp()-getTimeSpan();
133 loadedHistoryStop = getLastTimestamp();
134
135 getExecutorService().execute(new Runnable() {
136
137 public void run() {
138 double start = loadedHistoryStart;
139 double stop = loadedHistoryStop;
140 boolean reload;
141 double[][] hd;
142 reportProgress(new AcopTrendChartEvent(
143 AcopTrendChart.this,
144 AcopTrendChartEvent.EventType.MULTIPLE_OPERATION_STARTED,
145 "Started loading histories."));
146 for (AcopChartConsumer c : consumersList) {
147 reload = true;
148 if (c instanceof AcopTrendChartConsumer) {
149 HistoryParameters hp = ((AcopTrendChartConsumer) c).getHistoryParameters();
150 if (hp == null) continue;
151 reportProgress(new AcopTrendChartEvent(
152 AcopTrendChart.this,
153 AcopTrendChartEvent.EventType.OPERATION_STARTED,
154 "Started loading history for "+hp,
155 (AcopGraphHistoryParameters) c.getDisplayerParameters()));
156 while (reload) {
157 hd = getTHistoryConnector().loadHistory(hp, start, stop);
158 if (hd == null) {
159 reload = reportError(new AcopTrendChartEvent(
160 AcopTrendChart.this,
161 AcopTrendChartEvent.EventType.ERROR,
162 AcopTrendChartEvent.TIMEOUT,
163 (AcopGraphHistoryParameters) c.getDisplayerParameters()));
164 }
165 else if (hd.length == 0) {
166 reload = reportError(new AcopTrendChartEvent(
167 AcopTrendChart.this,
168 AcopTrendChartEvent.EventType.ERROR,
169 AcopTrendChartEvent.NO_DATA,
170 (AcopGraphHistoryParameters) c.getDisplayerParameters()));
171 }
172 else {
173 reload = false;
174 ((AcopTrendChartConsumer) c).loadHistoryData(hd);
175 }
176 }
177 reportProgress(new AcopTrendChartEvent(
178 AcopTrendChart.this,
179 AcopTrendChartEvent.EventType.OPERATION_ENDED,
180 "Finished loading history for "+hp,
181 (AcopGraphHistoryParameters) c.getDisplayerParameters()));
182 }
183 }
184
185 reportProgress(new AcopTrendChartEvent(
186 AcopTrendChart.this,
187 AcopTrendChartEvent.EventType.MULTIPLE_OPERATION_ENDED,
188 "Finished loading histories."));
189 }});
190 }
191
192 private void obtainHistory(final AcopTrendChartConsumer c) {
193 final HistoryParameters hp = c.getHistoryParameters();
194 if (hp == null) return;
195 getExecutorService().execute(new Runnable() {
196
197 public void run() {
198 double start = getLastTimestamp()-getTimeSpan();
199 double stop = getLastTimestamp();
200 boolean reload = true;
201 double[][] hd;
202 reportProgress(new AcopTrendChartEvent(
203 AcopTrendChart.this,
204 AcopTrendChartEvent.EventType.OPERATION_STARTED,
205 "Started loading history for "+hp,
206 (AcopGraphHistoryParameters) c.getDisplayerParameters()));
207 while (reload) {
208 hd = getTHistoryConnector().loadHistory(hp, start, stop);
209 if (hd == null) {
210 reload = reportError(new AcopTrendChartEvent(
211 AcopTrendChart.this,
212 AcopTrendChartEvent.EventType.ERROR,
213 AcopTrendChartEvent.TIMEOUT,
214 (AcopGraphHistoryParameters) c.getDisplayerParameters()));
215 }
216 else if (hd.length == 0) {
217 reload = reportError(new AcopTrendChartEvent(
218 AcopTrendChart.this,
219 AcopTrendChartEvent.EventType.ERROR,
220 AcopTrendChartEvent.NO_DATA,
221 (AcopGraphHistoryParameters) c.getDisplayerParameters()));
222 }
223 else {
224 reload = false;
225 c.loadHistoryData(hd);
226 }
227 }
228 reportProgress(new AcopTrendChartEvent(
229 AcopTrendChart.this,
230 AcopTrendChartEvent.EventType.OPERATION_ENDED,
231 "Finished loading history for "+hp,
232 (AcopGraphHistoryParameters) c.getDisplayerParameters()));
233 }});
234 }
235
236 protected void reportProgress(AcopTrendChartEvent event) {
237 for (AcopTrendChartListener listener : getAcopTrendChartListeners()) {
238 listener.reportProgress(event);
239 }
240 }
241
242 protected boolean reportError(AcopTrendChartEvent event) {
243 for (AcopTrendChartListener listener : getAcopTrendChartListeners()) {
244 if (listener.reportError(event)) {
245 String operation = (event.getMessage() == null) ? "" : ": "+event.getMessage();
246 AcopTrendChartEvent e = new AcopTrendChartEvent(listener, AcopTrendChartEvent.EventType.PROGRESS, "Operation "+operation+" aborted.");
247 reportProgress(e);
248 return true;
249 }
250 }
251 return false;
252 }
253
254
255
256
257
258
259
260 public void addAcopTrendChartListener(AcopTrendChartListener listener) {
261 if (acopTrendChartListeners.contains(listener)) return;
262 acopTrendChartListeners.add(listener);
263 }
264
265
266
267
268
269
270 public void removeAcopTrendChartListener(AcopTrendChartListener listener) {
271 acopTrendChartListeners.remove(listener);
272 }
273
274
275
276
277
278
279 public AcopTrendChartListener[] getAcopTrendChartListeners() {
280 return acopTrendChartListeners.toArray(new AcopTrendChartListener[acopTrendChartListeners.size()]);
281 }
282
283
284
285
286
287 @Override
288 public <D extends DataConsumer> D getConsumer(String name, Class<D> type) {
289 if (type.isAssignableFrom(AcopChartConsumer.class)) {
290 for (AcopChartConsumer c : consumersList) {
291 if (c.getName().equals(name)) return type.cast(c);
292 }
293
294 DataConsumer[] oldConumers = getConsumers();
295 AcopTrendChartConsumer c= new AcopTrendChartConsumer(this, name);
296 c.setNormalizedData(isNormalizedData());
297 c.setColor(colorManager.pickColor());
298 maxLinkIndex++;
299 consumersList.add(c);
300 firePropertyChange(CONSUMERS, oldConumers, getConsumers());
301 return type.cast(c);
302 }
303 return null;
304 }
305
306
307
308
309
310 @Override
311 public void addDisplayerParameters(AcopGraphParameters parameters) throws CommonException, PropertyVetoException {
312 super.addDisplayerParameters(parameters);
313 reloadHistory(parameters);
314 }
315
316
317
318
319
320
321 public void reloadHistory(AcopGraphParameters parameters) {
322 ConnectionParameters cp = parameters.getConnectionParameters();
323 for (AcopChartConsumer c : consumersList) {
324 if (c instanceof AcopTrendChartConsumer && c.getDisplayerParameters().getConnectionParameters().equals(cp)) {
325 obtainHistory((AcopTrendChartConsumer) c);
326 }
327 }
328 }
329
330
331
332
333
334 @Override
335 protected AcopGraphParameters synchronizeGraphParameters(AcopGraphParameters parameters) {
336 HistoryParameters hp = null;
337 if (parameters instanceof AcopGraphHistoryParameters) {
338 hp = ((AcopGraphHistoryParameters) parameters).getHistoryParameters();
339 }
340 AcopGraphHistoryParameters trendParameters = new AcopGraphHistoryParameters(super.synchronizeGraphParameters(parameters), hp);
341 return trendParameters;
342 }
343
344
345
346
347
348 @Override
349 public void updateXScale(AcopChartConsumer consumer) {
350
351 }
352
353
354
355
356
357 @Override
358 protected void updateXScaleOnRemove(AcopChartConsumer consumer) {
359
360 }
361
362
363
364
365
366 public double getTimeSpan() {
367 return getXRangeMax() - getXRangeMin();
368 }
369
370
371
372
373
374 public void setTimeSpan(double timeSpan) {
375 if (getTimeSpan() == timeSpan) return;
376 double oldSpan = getTimeSpan();
377 setXRangeMin(getLastTimestamp() - timeSpan);
378 firePropertyChange(TIME_SPAN, oldSpan, getTimeSpan());
379 loadHistory();
380 }
381
382
383
384
385
386 public double getLastTimestamp() {
387 return getXRangeMax();
388 }
389
390
391
392
393
394
395 public void setLastTimestamp(double timestamp) {
396 if (!scaleInitialized) {
397 if (isAutoScaleToLiveData()) {
398
399 setXRangeMax(timestamp+1);
400 setXRangeMin(timestamp);
401 loadedHistoryStart = timestamp;
402 }
403 scaleInitialized = true;
404 }
405 if (getXRangeMax() >= timestamp) return;
406 if (!isAutoScaleToLiveData()) {
407 setXRangeMin(timestamp - getTimeSpan());
408 }
409 setXRangeMax(timestamp);
410 }
411
412
413
414
415
416
417
418 public boolean isCheckForBadData() {
419 return getTHistoryConnector().isCheckForBadData();
420 }
421
422
423
424
425
426
427
428 public void setCheckForBadData(boolean checkForBadData) {
429 boolean oldValue = isCheckForBadData();
430 getTHistoryConnector().setCheckForBadData(checkForBadData);
431 firePropertyChange(CHECK_FOR_BAD_DATA, oldValue, checkForBadData);
432 }
433
434
435
436
437
438
439 public boolean isSimulate() {
440 return getTHistoryConnector().isSimulate();
441 }
442
443
444
445
446
447
448 public void setSimulate(boolean simulate) {
449 getTHistoryConnector().setSimulate(simulate);
450 }
451
452
453
454
455
456
457 public int getTimeout() {
458 return getTHistoryConnector().getTimeout();
459 }
460
461
462
463
464
465
466
467 public void setTimeout(int timeout) {
468 int oldValue = getTimeout();
469 getTHistoryConnector().setTimeout(timeout);
470 firePropertyChange(TIMEOUT, oldValue, timeout);
471 }
472
473
474
475
476
477
478 public boolean isAutoScaleToLiveData() {
479 return autoScaleToLiveData;
480 }
481
482
483
484
485
486
487
488
489 public void setAutoScaleToLiveData(boolean autoScaleToLiveData) {
490 boolean oldValue = isAutoScaleToLiveData();
491 this.autoScaleToLiveData = autoScaleToLiveData;
492 firePropertyChange(AUTOSCALE_TO_LIVE_DATA, oldValue, autoScaleToLiveData);
493 if (!autoScaleToLiveData) {
494 setXRangeMin(getLastTimestamp() - getTimeSpan());
495 }
496 }
497
498
499
500
501
502 @Override
503 public DataSource removeDisplayerParameters(AcopGraphParameters parameters) {
504 DataSource ds = super.removeDisplayerParameters(parameters);
505 if (getDisplayerParameters().length == 0) scaleInitialized = false;
506 return ds;
507 }
508
509
510
511
512
513
514
515 public void setNormalizedData(boolean normalized) {
516 if (this.normalized == normalized) return;
517 this.normalized = normalized;
518 DataConsumer[] consumers = getConsumers();
519 for (DataConsumer c : consumers) {
520 if (c instanceof AcopTrendChartConsumer) {
521 ((AcopTrendChartConsumer)c).setNormalizedData(normalized);
522 }
523 }
524 updateYScale(null);
525 firePropertyChange("normalizedData",!normalized, normalized);
526 }
527
528
529
530
531
532
533 public boolean isNormalizedData() {
534 return normalized;
535 }
536
537
538
539
540
541 @Override
542 public void updateYScale(AcopChartConsumer consumer) {
543 if (isNormalizedData()) {
544
545 setYRangeMax(100.);
546 setYRangeMin(0.);
547 setYRangeMax(100.);
548 setYRangeMin(0.);
549 } else {
550 DataConsumer[] consumers = getConsumers();
551 double max = -Double.MAX_VALUE;
552 double min = Double.MAX_VALUE;
553 for (DataConsumer c : consumers) {
554 if (!(c instanceof AcopChartConsumer)) continue;
555 max = Math.max(max, ((AcopChartConsumer)c).getPreferredYMax());
556 min = Math.min(min, ((AcopChartConsumer)c).getPreferredYMin());
557 }
558 setYRangeMax(max);
559 setYRangeMin(min);
560 }
561 }
562
563
564
565
566
567 @Override
568 protected void updateYScaleOnRemove(AcopChartConsumer consumer) {
569 updateYScale(consumer);
570 }
571
572 }