]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.history/src/org/simantics/history/util/ValueBand.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.history / src / org / simantics / history / util / ValueBand.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.history.util;\r
13 \r
14 import org.simantics.databoard.Bindings;\r
15 import org.simantics.databoard.adapter.AdaptException;\r
16 import org.simantics.databoard.adapter.Adapter;\r
17 import org.simantics.databoard.adapter.AdapterConstructionException;\r
18 import org.simantics.databoard.binding.Binding;\r
19 import org.simantics.databoard.binding.BooleanBinding;\r
20 import org.simantics.databoard.binding.ByteBinding;\r
21 import org.simantics.databoard.binding.DoubleBinding;\r
22 import org.simantics.databoard.binding.FloatBinding;\r
23 import org.simantics.databoard.binding.NumberBinding;\r
24 import org.simantics.databoard.binding.RecordBinding;\r
25 import org.simantics.databoard.binding.error.BindingException;\r
26 import org.simantics.databoard.binding.error.RuntimeBindingException;\r
27 import org.simantics.databoard.type.RecordType;\r
28 import org.simantics.history.HistoryException;\r
29 \r
30 /**\r
31  * Value band is an utility class intended for reading and writing to samples.\r
32  * There are many different formats of samples, their fields, order and datatypes vary.\r
33  *\r
34  * @author toni.kalajainen\r
35  */\r
36 public class ValueBand {\r
37         \r
38         public static final Byte QUALITY_GOOD = Byte.valueOf( (byte) 0 ); \r
39         public static final Byte QUALITY_NOVALUE = Byte.valueOf( (byte) -1 ); \r
40         \r
41         protected RecordBinding binding;\r
42         protected RecordType type;\r
43         protected Object sample;\r
44         \r
45         /** Field value cloners */\r
46         FieldAdapter timeField, endTimeField, valueField, lastValueField, avgField, medianField, minField, maxField, countField, qualityField;\r
47         /** Default value*/\r
48         Object defaultValue;\r
49         \r
50         public ValueBand(Binding sampleBinding)\r
51         {\r
52                 if ( sampleBinding instanceof RecordBinding == false ) {\r
53                         throw new IllegalArgumentException();\r
54                 }\r
55                 \r
56                 this.binding = (RecordBinding) sampleBinding;           \r
57                 type = this.binding.type();\r
58                 \r
59                 timeField = new FieldAdapter("time");\r
60                 endTimeField = new FieldAdapter("endTime");\r
61                 valueField = new FieldAdapter("value");\r
62                 lastValueField = new FieldAdapter("lastValue");\r
63                 avgField = new FieldAdapter("avg");\r
64                 medianField = new FieldAdapter("median");\r
65                 minField = new FieldAdapter("min");\r
66                 maxField = new FieldAdapter("max");\r
67                 countField = new FieldAdapter("count");\r
68                 qualityField = new FieldAdapter("quality");\r
69                                 \r
70                 try {\r
71                         defaultValue = binding.createDefault();\r
72                 } catch (BindingException e) {\r
73                         throw new RuntimeBindingException( e );\r
74                 }\r
75         }\r
76         \r
77         public ValueBand(Binding sampleBinding, Object sample)\r
78         {\r
79                 this( sampleBinding );\r
80                 this.sample = sample;\r
81         }\r
82         \r
83         \r
84         public void reset()\r
85         {\r
86                 try {\r
87                         binding.readFrom(binding, defaultValue, sample);\r
88                 } catch (BindingException e) {\r
89                         throw new RuntimeBindingException( e );\r
90                 }\r
91         }\r
92         \r
93         public Binding getBinding()\r
94         {\r
95                 return binding;\r
96         }\r
97 \r
98         /**\r
99          * Get the internal sample instance\r
100          * \r
101          * @return the internal sample instance\r
102          */\r
103         public Object getSample() {\r
104                 return sample;\r
105         }\r
106 \r
107         /**\r
108          * Change the internal sample instance\r
109          * \r
110          * @param sample\r
111          */\r
112         public void setSample(Object sample) {\r
113                 this.sample = sample;\r
114         }\r
115 \r
116         /**\r
117          * Write to the internal sample instance \r
118          * \r
119          * @param sample\r
120          */\r
121         public void writeSample(Object sample) {\r
122                 try {\r
123                         binding.readFrom(binding, sample, this.sample);\r
124                 } catch (BindingException e) {\r
125                         throw new RuntimeBindingException(e);\r
126                 }\r
127         }\r
128         \r
129         /**\r
130          * Write to the internal sample instance \r
131          * \r
132          * @param binding\r
133          * @param sample\r
134          */\r
135         public void writeSample(Binding binding, Object sample) {\r
136                 try {\r
137                         binding.readFrom(binding, sample, this.sample);\r
138                 } catch (BindingException e) {\r
139                         throw new RuntimeBindingException(e);\r
140                 }\r
141         }\r
142                 \r
143         \r
144         /// Time ///\r
145         public boolean hasTime() {\r
146                 return timeField.isEnabled();\r
147         }\r
148         \r
149         public Binding getTimeBinding() {\r
150                 return timeField.binding;\r
151         }\r
152         \r
153         public Object getTime() throws HistoryException {\r
154                 return timeField.getValue();\r
155         }\r
156 \r
157         public Object getTime(Binding b) throws HistoryException {\r
158                 return timeField.getValue(b);\r
159         }\r
160         \r
161         public double getTimeDouble() throws HistoryException {\r
162                 return timeField.getDoubleValue();\r
163         }\r
164         \r
165         public void setTime(Object v) throws HistoryException {\r
166                 timeField.setValue(v);\r
167         }\r
168         \r
169         public void setTime(Binding binding, Object v) throws HistoryException\r
170         {\r
171                 timeField.setValue(binding, v);\r
172         }\r
173 \r
174         /// EndTime ///\r
175         public boolean hasEndTime() {\r
176                 return endTimeField.isEnabled();\r
177         }\r
178         \r
179         public Binding getEndTimeBinding() {\r
180                 return endTimeField.binding;\r
181         }\r
182         \r
183         public Object getEndTime() throws HistoryException {\r
184                 return endTimeField.getValue();\r
185         }\r
186 \r
187         public Object getEndTime(Binding b) throws HistoryException {\r
188                 return endTimeField.getValue(b);\r
189         }\r
190         \r
191         public double getEndTimeDouble() throws HistoryException {\r
192                 return endTimeField.getDoubleValue();\r
193         }\r
194         \r
195         \r
196         public void setEndTime(Object v) throws HistoryException {\r
197                 endTimeField.setValue(v);\r
198         }\r
199 \r
200         public void setEndTime(Binding binding, Object v) throws HistoryException\r
201         {\r
202                 endTimeField.setValue(binding, v);\r
203         }\r
204         \r
205         /// Value ///\r
206         public boolean hasValue() {\r
207                 return valueField.isEnabled();\r
208         }\r
209         \r
210         public Binding getValueBinding() {\r
211                 return valueField.binding;\r
212         }\r
213         \r
214         public Object getValue() throws HistoryException {\r
215                 return valueField.getValue();\r
216         }\r
217 \r
218         public Object getValue(Binding b) throws HistoryException {\r
219                 return valueField.getValue(b);\r
220         }\r
221 \r
222         public double getValueDouble() throws HistoryException {\r
223                 return valueField.getDoubleValue();\r
224         }\r
225         \r
226         public Object getPossibleValue() throws HistoryException {\r
227                 if ( isNullValue() ) return null;\r
228                 return valueField.getValue();\r
229         }\r
230 \r
231         public Object getPossibleValue(Binding b) throws HistoryException {\r
232                 if ( isNullValue() ) return null;\r
233                 return valueField.getValue(b);\r
234         }\r
235 \r
236         public Double getPossibleValueDouble() throws HistoryException {\r
237                 if ( isNullValue() ) return null;\r
238                 return valueField.getDoubleValue();\r
239         }\r
240         \r
241         \r
242         public boolean getValueBoolean() throws HistoryException {\r
243                 return valueField.getBooleanValue();\r
244         }\r
245         \r
246         public void setValue(Object v) throws HistoryException {\r
247                 valueField.setValue(v);\r
248         }\r
249 \r
250         public void setValue(Binding binding, Object v) throws HistoryException\r
251         {\r
252                 valueField.setValue(binding, v);\r
253         }\r
254         \r
255         /// LastValue ///\r
256         public boolean hasLastValue() {\r
257                 return lastValueField.isEnabled();\r
258         }\r
259         \r
260         public Binding getLastValueBinding() {\r
261                 return lastValueField.binding;\r
262         }\r
263         \r
264         public Object getLastValue() throws HistoryException {\r
265                 return lastValueField.getValue();\r
266         }\r
267 \r
268         public Object getLastValue(Binding b) throws HistoryException {\r
269                 return lastValueField.getValue(b);\r
270         }\r
271 \r
272         public void setLastValue(Object v) throws HistoryException {\r
273                 lastValueField.setValue(v);\r
274         }\r
275         \r
276         public void setLastValue(Binding binding, Object v) throws HistoryException {\r
277                 lastValueField.setValue(binding, v);\r
278         }\r
279         \r
280         /// Avg ///\r
281         public boolean hasAvg() {\r
282                 return avgField.isEnabled();\r
283         }\r
284         \r
285         public Binding getAvgBinding() {\r
286                 return avgField.binding;\r
287         }\r
288         \r
289         public Object getAvg() throws HistoryException {\r
290                 return avgField.getValue();\r
291         }\r
292 \r
293         public Object getAvg(Binding b) throws HistoryException {\r
294                 return avgField.getValue(b);\r
295         }\r
296         \r
297         public double getAvgDouble() throws HistoryException {\r
298                 return avgField.getDoubleValue();\r
299         }       \r
300         \r
301         public void setAvg(Object v) throws HistoryException {\r
302                 avgField.setValue(v);\r
303         }\r
304 \r
305         public void setAvg(Binding binding, Object v) throws HistoryException\r
306         {\r
307                 avgField.setValue(binding, v);\r
308         }\r
309         \r
310         /// Median ///\r
311         public boolean hasMedian() {\r
312                 return medianField.isEnabled();\r
313         }\r
314         \r
315         public Binding getMedianBinding() {\r
316                 return medianField.binding;\r
317         }\r
318         \r
319         public Object getMedian() throws HistoryException {\r
320                 return medianField.getValue();\r
321         }\r
322 \r
323         public Object getMedian(Binding b) throws HistoryException {\r
324                 return medianField.getValue(b);\r
325         }\r
326         \r
327         public double getMedianDouble() throws HistoryException {\r
328                 return medianField.getDoubleValue();\r
329         }\r
330         \r
331         public void setMedian(Object v) throws HistoryException {\r
332                 medianField.setValue(v);\r
333         }\r
334 \r
335         public void setMedian(Binding binding, Object v) throws HistoryException\r
336         {\r
337                 medianField.setValue(binding, v);\r
338         }\r
339         \r
340         /// Min ///\r
341         public boolean hasMin() {\r
342                 return minField.isEnabled();\r
343         }\r
344         \r
345         public Binding getMinBinding() {\r
346                 return minField.binding;\r
347         }\r
348         \r
349         public Object getMin() throws HistoryException {\r
350                 return minField.getValue();\r
351         }\r
352 \r
353         public Object getMin(Binding b) throws HistoryException {\r
354                 return minField.getValue(b);\r
355         }\r
356         \r
357         public double getMinDouble() throws HistoryException {\r
358                 return minField.getDoubleValue();\r
359         }\r
360         \r
361         public void setMin(Object v) throws HistoryException {\r
362                 minField.setValue(v);\r
363         }       \r
364 \r
365         public void setMin(Binding binding, Object v) throws HistoryException\r
366         {\r
367                 minField.setValue(binding, v);\r
368         }\r
369         \r
370         /// Max ///\r
371         public boolean hasMax() {\r
372                 return maxField.isEnabled();\r
373         }\r
374         \r
375         public Binding getMaxBinding() {\r
376                 return maxField.binding;\r
377         }\r
378         \r
379         public Object getMax() throws HistoryException {\r
380                 return maxField.getValue();\r
381         }\r
382 \r
383         public Object getMax(Binding b) throws HistoryException {\r
384                 return maxField.getValue(b);\r
385         }\r
386         \r
387         public double getMaxDouble() throws HistoryException {\r
388                 return maxField.getDoubleValue();\r
389         }\r
390         \r
391         public void setMax(Object v) throws HistoryException {\r
392                 maxField.setValue(v);\r
393         }       \r
394         \r
395         public void setMax(Binding binding, Object v) throws HistoryException\r
396         {\r
397                 maxField.setValue(binding, v);\r
398         }\r
399         \r
400         \r
401         /// Count ///\r
402         public boolean hasCount() {\r
403                 return countField.isEnabled();\r
404         }\r
405         \r
406         public NumberBinding getCountBinding() {\r
407                 return (NumberBinding) countField.binding;\r
408         }\r
409         \r
410         public int getCount() throws HistoryException {\r
411                 Integer i = (Integer) countField.getValue( Bindings.INTEGER );\r
412                 return i == null ? 0 : i;\r
413         }\r
414 \r
415         public Object getCount(Binding b) throws HistoryException {\r
416                 return countField.getValue(b);\r
417         }\r
418         \r
419         public void setCount(int v) throws HistoryException {\r
420                 countField.setValue(Bindings.INTEGER, v);\r
421         }       \r
422 \r
423         /// Quality ///\r
424         public boolean hasQuality() {\r
425                 return qualityField.isEnabled();\r
426         }\r
427         \r
428         public Binding getQualityBinding() {\r
429                 return qualityField.binding;\r
430         }\r
431         \r
432         public Object getQuality() throws HistoryException {\r
433                 return qualityField.getValue();\r
434         }\r
435 \r
436         public Object getQuality(Binding b) throws HistoryException {\r
437                 return qualityField.getValue(b);\r
438         }\r
439         \r
440         public void setQuality(Object v) throws HistoryException {\r
441                 qualityField.setValue(v);\r
442         }       \r
443 \r
444         public void setQuality(Binding binding, Object v) throws HistoryException\r
445         {\r
446                 qualityField.setValue(binding, v);\r
447         }\r
448         \r
449         \r
450         /**\r
451          * Value band is a region of one or more samples.\r
452          * This method returns true, if value band is expressed with a single sample.\r
453          * \r
454          * If value band is expressed with two samples, there is start and end\r
455          * sample. The format is typicaly simple (time, value).  \r
456          * \r
457          * @return true if it can represent more than one sample\r
458          */\r
459         public boolean isRanged()\r
460         {\r
461                 return endTimeField.isEnabled();\r
462         }\r
463         \r
464         public boolean isValidValue() throws HistoryException {\r
465                 return !isNanSample() && !isNullValue();\r
466         }\r
467 \r
468         /**\r
469          * Return true, if this sample \r
470          * \r
471          * @return true if the value is Not-a-number\r
472          */\r
473         public boolean isNanSample() {\r
474                 try {\r
475                         if (valueField.binding instanceof DoubleBinding) {\r
476                                 DoubleBinding db = (DoubleBinding) valueField.binding;\r
477                                 double d = db.getValue_( binding.getComponent(sample, valueField.index) );\r
478                                 return Double.isNaN( d );\r
479                         }\r
480                         if (valueField.binding instanceof FloatBinding) {\r
481                                 FloatBinding db = (FloatBinding) valueField.binding;\r
482                                 float d = db.getValue_( binding.getComponent(sample, valueField.index) );\r
483                                 return Float.isNaN( d );\r
484                         }\r
485                         return false;\r
486                 } catch (BindingException e) {\r
487                         return false;\r
488                 }\r
489         }\r
490         \r
491         /**\r
492          * Returns true, if this sample format supports a way to express \r
493          * discontinuation regions. \r
494          * \r
495          * @return true if can support discontinuation\r
496          */\r
497         public boolean supportsNullValue() {\r
498                 return qualityField.isEnabled();\r
499         }\r
500         \r
501         /**\r
502          * Marks this sample as discontinuation sample\r
503          * @throws HistoryException \r
504          */\r
505         public void setValueNull() throws HistoryException {\r
506                 qualityField.setValue(Bindings.BYTE, QUALITY_NOVALUE);\r
507         }\r
508         \r
509         /**\r
510          * Returns true, if the sample is discontinuation sample\r
511          * \r
512          * @return true, if the sample is discontinuation sample\r
513          * @throws HistoryException \r
514          */\r
515         public boolean isNullValue() throws HistoryException {\r
516                 Byte b = (Byte) qualityField.getValue(Bindings.BYTE);\r
517                 return b == null ? false : b.equals( QUALITY_NOVALUE );\r
518         }\r
519         \r
520         public boolean isNumericValue() {\r
521                 return valueField.isNumeric();\r
522         }\r
523         \r
524         @Override\r
525         public String toString() {\r
526                 try {\r
527                         return binding.toString(sample);\r
528                 } catch (BindingException e) {\r
529                         return e.toString();\r
530                 }\r
531         }\r
532         \r
533         class FieldAdapter {\r
534                 /** Binding of the field, with possible optionalbinding stripped */\r
535                 Binding binding;\r
536                 \r
537                 /// Adapter1 is cached adapter for setValue  \r
538                 Binding adapter1binding;\r
539                 Adapter adapter1;\r
540                 \r
541                 /// Adapter2 is cached adapter for getValue\r
542                 Binding adapter2binding;\r
543                 Adapter adapter2;\r
544                 \r
545                 /** Field index in sample record */\r
546                 int index;\r
547                 \r
548                 /** Field name */\r
549                 String fieldName;\r
550                 \r
551                 public FieldAdapter(String fieldName) {\r
552                         this.fieldName = fieldName;\r
553                         index = ValueBand.this.binding.type().getComponentIndex2( fieldName );\r
554                         if (index<0) return;\r
555                         \r
556                         this.binding = ValueBand.this.binding.getComponentBinding(index);\r
557                 }\r
558                 \r
559                 public boolean getBooleanValue() throws HistoryException {\r
560                         if (sample == null || index==-1) return false;\r
561                         try {\r
562                                 Object value = ValueBand.this.binding.getComponent(sample, index);\r
563                                 if (binding instanceof BooleanBinding) {\r
564                                         return ValueBand.this.binding.getBoolean(sample, index);\r
565 //                                      BooleanBinding bb = (BooleanBinding) binding;\r
566 //                                      return bb.getValue_( value );\r
567                                 }\r
568                                 if (binding instanceof ByteBinding) {\r
569                                         ByteBinding nb = (ByteBinding) binding;\r
570                                         return nb.getValue_( value ) != 0;\r
571                                 }\r
572                                 if (binding instanceof DoubleBinding) {\r
573                                         DoubleBinding nb = (DoubleBinding) binding;\r
574                                         return nb.getValue_( value ) != 0.;\r
575                                 }\r
576                                 if (binding instanceof NumberBinding) {\r
577                                         NumberBinding nb = (NumberBinding) binding;\r
578                                         return nb.getValue( value ).doubleValue() != 0.;\r
579                                 }\r
580                                 return false;\r
581                         } catch (BindingException e) {\r
582                                 throw new HistoryException( e );\r
583                         }                       \r
584                 }\r
585 \r
586                 public double getDoubleValue() throws HistoryException {\r
587                         if (sample == null || index==-1) return Double.NaN;\r
588                         try {\r
589                                 // Read field from record\r
590                                 if (binding != Bindings.DOUBLE) {\r
591                                         Object result = ValueBand.this.binding.getComponent(sample, index);\r
592                                         result = Bindings.adapt(result, binding, Bindings.DOUBLE);\r
593                                         return (Double) result;\r
594                                 } else {\r
595                                         return ValueBand.this.binding.getDouble(sample, index);\r
596                                 }\r
597                         } catch (BindingException e) {\r
598                                 throw new HistoryException( e );\r
599                         } catch (AdaptException e) {\r
600                                 throw new HistoryException( e );\r
601                         }                       \r
602                 }\r
603 \r
604                 public boolean isEnabled() {\r
605                         return index>=0;\r
606                 }\r
607                 \r
608                 /**\r
609                  * Get the value\r
610                  *  \r
611                  * @return value or null, if value is not available\r
612                  * @throws HistoryException\r
613                  */\r
614                 public Object getValue() throws HistoryException {\r
615                         if (sample == null || index==-1) return null;\r
616                         try {\r
617                                 // Read field from record\r
618                                 Object result = ValueBand.this.binding.getComponent(sample, index);\r
619 \r
620                                 return result;\r
621                         } catch (BindingException e) {\r
622                                 throw new HistoryException( e );\r
623                         }\r
624                 }\r
625 \r
626                 /**\r
627                  * Get the value\r
628                  * @param binding\r
629                  * @return value in given binding or null, if value is not available\r
630                  * @throws HistoryException\r
631                  */\r
632                 public Object getValue(Binding binding) throws HistoryException {\r
633                         if (sample == null || index==-1) return null;\r
634                         try {\r
635                                 // Read field from record\r
636                                 Object result = ValueBand.this.binding.getComponent(sample, index);\r
637                                 \r
638                                 // Adapt value\r
639                                 if ( binding != this.binding ) {\r
640                                         if ( binding != adapter2binding ) {\r
641                                                 adapter2 = Bindings.adapterFactory.getAdapter(this.binding, binding, true, false);\r
642                                                 adapter2binding = binding;\r
643                                         }\r
644                                         result = adapter2.adapt( result );\r
645                                 }\r
646 \r
647                                 return result;\r
648                         } catch (BindingException e) {\r
649                                 throw new HistoryException( e );\r
650                         } catch (AdaptException e) {\r
651                                 throw new HistoryException( e );\r
652                         } catch (AdapterConstructionException e) {\r
653                                 throw new HistoryException( e );\r
654                         }\r
655                 }\r
656                 \r
657                 public void setValue(Object object) throws HistoryException {\r
658                         if (sample == null || index==-1) return;\r
659                         setValue(binding, object);\r
660                 }               \r
661                                         \r
662                 public void setValue(Binding binding, Object object) throws HistoryException {\r
663                         if (sample == null || index==-1) return;\r
664                         \r
665                         try {\r
666                                 // Adapt value                  \r
667                                 if (this.binding != binding) {                                  \r
668                                         // Create new adapter\r
669                                         if (binding != adapter1binding) {\r
670                                                 adapter1 = Bindings.adapterFactory.getAdapter(binding, this.binding, true, !binding.isImmutable());     \r
671                                                 adapter1binding = binding;\r
672                                         }\r
673                                         \r
674                                         // Adapt\r
675                                         object = adapter1.adapt(object);        \r
676                                 }\r
677                         \r
678                                 // Write value\r
679                                 ValueBand.this.binding.setComponent(sample, index, object);\r
680                                 \r
681                         } catch (AdaptException e) {\r
682                                 throw new HistoryException( e ); \r
683                         } catch (BindingException e) {\r
684                                 throw new HistoryException( e ); \r
685                         } catch (AdapterConstructionException e) {\r
686                                 throw new HistoryException( e ); \r
687                         }\r
688                 }               \r
689         \r
690                 public boolean isNumeric() {\r
691                         return binding instanceof NumberBinding;\r
692                 }       \r
693         \r
694         }\r
695         \r
696 }\r