]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.history/src/org/simantics/history/util/ValueBand.java b/bundles/org.simantics.history/src/org/simantics/history/util/ValueBand.java
new file mode 100644 (file)
index 0000000..3189e8a
--- /dev/null
@@ -0,0 +1,696 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.history.util;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.adapter.AdaptException;\r
+import org.simantics.databoard.adapter.Adapter;\r
+import org.simantics.databoard.adapter.AdapterConstructionException;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.BooleanBinding;\r
+import org.simantics.databoard.binding.ByteBinding;\r
+import org.simantics.databoard.binding.DoubleBinding;\r
+import org.simantics.databoard.binding.FloatBinding;\r
+import org.simantics.databoard.binding.NumberBinding;\r
+import org.simantics.databoard.binding.RecordBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.error.RuntimeBindingException;\r
+import org.simantics.databoard.type.RecordType;\r
+import org.simantics.history.HistoryException;\r
+\r
+/**\r
+ * Value band is an utility class intended for reading and writing to samples.\r
+ * There are many different formats of samples, their fields, order and datatypes vary.\r
+ *\r
+ * @author toni.kalajainen\r
+ */\r
+public class ValueBand {\r
+       \r
+       public static final Byte QUALITY_GOOD = Byte.valueOf( (byte) 0 ); \r
+       public static final Byte QUALITY_NOVALUE = Byte.valueOf( (byte) -1 ); \r
+       \r
+       protected RecordBinding binding;\r
+       protected RecordType type;\r
+       protected Object sample;\r
+       \r
+       /** Field value cloners */\r
+       FieldAdapter timeField, endTimeField, valueField, lastValueField, avgField, medianField, minField, maxField, countField, qualityField;\r
+       /** Default value*/\r
+       Object defaultValue;\r
+       \r
+       public ValueBand(Binding sampleBinding)\r
+       {\r
+               if ( sampleBinding instanceof RecordBinding == false ) {\r
+                       throw new IllegalArgumentException();\r
+               }\r
+               \r
+               this.binding = (RecordBinding) sampleBinding;           \r
+               type = this.binding.type();\r
+               \r
+               timeField = new FieldAdapter("time");\r
+               endTimeField = new FieldAdapter("endTime");\r
+               valueField = new FieldAdapter("value");\r
+               lastValueField = new FieldAdapter("lastValue");\r
+               avgField = new FieldAdapter("avg");\r
+               medianField = new FieldAdapter("median");\r
+               minField = new FieldAdapter("min");\r
+               maxField = new FieldAdapter("max");\r
+               countField = new FieldAdapter("count");\r
+               qualityField = new FieldAdapter("quality");\r
+                               \r
+               try {\r
+                       defaultValue = binding.createDefault();\r
+               } catch (BindingException e) {\r
+                       throw new RuntimeBindingException( e );\r
+               }\r
+       }\r
+       \r
+       public ValueBand(Binding sampleBinding, Object sample)\r
+       {\r
+               this( sampleBinding );\r
+               this.sample = sample;\r
+       }\r
+       \r
+       \r
+       public void reset()\r
+       {\r
+               try {\r
+                       binding.readFrom(binding, defaultValue, sample);\r
+               } catch (BindingException e) {\r
+                       throw new RuntimeBindingException( e );\r
+               }\r
+       }\r
+       \r
+       public Binding getBinding()\r
+       {\r
+               return binding;\r
+       }\r
+\r
+       /**\r
+        * Get the internal sample instance\r
+        * \r
+        * @return the internal sample instance\r
+        */\r
+       public Object getSample() {\r
+               return sample;\r
+       }\r
+\r
+       /**\r
+        * Change the internal sample instance\r
+        * \r
+        * @param sample\r
+        */\r
+       public void setSample(Object sample) {\r
+               this.sample = sample;\r
+       }\r
+\r
+       /**\r
+        * Write to the internal sample instance \r
+        * \r
+        * @param sample\r
+        */\r
+       public void writeSample(Object sample) {\r
+               try {\r
+                       binding.readFrom(binding, sample, this.sample);\r
+               } catch (BindingException e) {\r
+                       throw new RuntimeBindingException(e);\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Write to the internal sample instance \r
+        * \r
+        * @param binding\r
+        * @param sample\r
+        */\r
+       public void writeSample(Binding binding, Object sample) {\r
+               try {\r
+                       binding.readFrom(binding, sample, this.sample);\r
+               } catch (BindingException e) {\r
+                       throw new RuntimeBindingException(e);\r
+               }\r
+       }\r
+               \r
+       \r
+       /// Time ///\r
+       public boolean hasTime() {\r
+               return timeField.isEnabled();\r
+       }\r
+       \r
+       public Binding getTimeBinding() {\r
+               return timeField.binding;\r
+       }\r
+       \r
+       public Object getTime() throws HistoryException {\r
+               return timeField.getValue();\r
+       }\r
+\r
+       public Object getTime(Binding b) throws HistoryException {\r
+               return timeField.getValue(b);\r
+       }\r
+       \r
+       public double getTimeDouble() throws HistoryException {\r
+               return timeField.getDoubleValue();\r
+       }\r
+       \r
+       public void setTime(Object v) throws HistoryException {\r
+               timeField.setValue(v);\r
+       }\r
+       \r
+       public void setTime(Binding binding, Object v) throws HistoryException\r
+       {\r
+               timeField.setValue(binding, v);\r
+       }\r
+\r
+       /// EndTime ///\r
+       public boolean hasEndTime() {\r
+               return endTimeField.isEnabled();\r
+       }\r
+       \r
+       public Binding getEndTimeBinding() {\r
+               return endTimeField.binding;\r
+       }\r
+       \r
+       public Object getEndTime() throws HistoryException {\r
+               return endTimeField.getValue();\r
+       }\r
+\r
+       public Object getEndTime(Binding b) throws HistoryException {\r
+               return endTimeField.getValue(b);\r
+       }\r
+       \r
+       public double getEndTimeDouble() throws HistoryException {\r
+               return endTimeField.getDoubleValue();\r
+       }\r
+       \r
+       \r
+       public void setEndTime(Object v) throws HistoryException {\r
+               endTimeField.setValue(v);\r
+       }\r
+\r
+       public void setEndTime(Binding binding, Object v) throws HistoryException\r
+       {\r
+               endTimeField.setValue(binding, v);\r
+       }\r
+       \r
+       /// Value ///\r
+       public boolean hasValue() {\r
+               return valueField.isEnabled();\r
+       }\r
+       \r
+       public Binding getValueBinding() {\r
+               return valueField.binding;\r
+       }\r
+       \r
+       public Object getValue() throws HistoryException {\r
+               return valueField.getValue();\r
+       }\r
+\r
+       public Object getValue(Binding b) throws HistoryException {\r
+               return valueField.getValue(b);\r
+       }\r
+\r
+       public double getValueDouble() throws HistoryException {\r
+               return valueField.getDoubleValue();\r
+       }\r
+       \r
+       public Object getPossibleValue() throws HistoryException {\r
+               if ( isNullValue() ) return null;\r
+               return valueField.getValue();\r
+       }\r
+\r
+       public Object getPossibleValue(Binding b) throws HistoryException {\r
+               if ( isNullValue() ) return null;\r
+               return valueField.getValue(b);\r
+       }\r
+\r
+       public Double getPossibleValueDouble() throws HistoryException {\r
+               if ( isNullValue() ) return null;\r
+               return valueField.getDoubleValue();\r
+       }\r
+       \r
+       \r
+       public boolean getValueBoolean() throws HistoryException {\r
+               return valueField.getBooleanValue();\r
+       }\r
+       \r
+       public void setValue(Object v) throws HistoryException {\r
+               valueField.setValue(v);\r
+       }\r
+\r
+       public void setValue(Binding binding, Object v) throws HistoryException\r
+       {\r
+               valueField.setValue(binding, v);\r
+       }\r
+       \r
+       /// LastValue ///\r
+       public boolean hasLastValue() {\r
+               return lastValueField.isEnabled();\r
+       }\r
+       \r
+       public Binding getLastValueBinding() {\r
+               return lastValueField.binding;\r
+       }\r
+       \r
+       public Object getLastValue() throws HistoryException {\r
+               return lastValueField.getValue();\r
+       }\r
+\r
+       public Object getLastValue(Binding b) throws HistoryException {\r
+               return lastValueField.getValue(b);\r
+       }\r
+\r
+       public void setLastValue(Object v) throws HistoryException {\r
+               lastValueField.setValue(v);\r
+       }\r
+       \r
+       public void setLastValue(Binding binding, Object v) throws HistoryException {\r
+               lastValueField.setValue(binding, v);\r
+       }\r
+       \r
+       /// Avg ///\r
+       public boolean hasAvg() {\r
+               return avgField.isEnabled();\r
+       }\r
+       \r
+       public Binding getAvgBinding() {\r
+               return avgField.binding;\r
+       }\r
+       \r
+       public Object getAvg() throws HistoryException {\r
+               return avgField.getValue();\r
+       }\r
+\r
+       public Object getAvg(Binding b) throws HistoryException {\r
+               return avgField.getValue(b);\r
+       }\r
+       \r
+       public double getAvgDouble() throws HistoryException {\r
+               return avgField.getDoubleValue();\r
+       }       \r
+       \r
+       public void setAvg(Object v) throws HistoryException {\r
+               avgField.setValue(v);\r
+       }\r
+\r
+       public void setAvg(Binding binding, Object v) throws HistoryException\r
+       {\r
+               avgField.setValue(binding, v);\r
+       }\r
+       \r
+       /// Median ///\r
+       public boolean hasMedian() {\r
+               return medianField.isEnabled();\r
+       }\r
+       \r
+       public Binding getMedianBinding() {\r
+               return medianField.binding;\r
+       }\r
+       \r
+       public Object getMedian() throws HistoryException {\r
+               return medianField.getValue();\r
+       }\r
+\r
+       public Object getMedian(Binding b) throws HistoryException {\r
+               return medianField.getValue(b);\r
+       }\r
+       \r
+       public double getMedianDouble() throws HistoryException {\r
+               return medianField.getDoubleValue();\r
+       }\r
+       \r
+       public void setMedian(Object v) throws HistoryException {\r
+               medianField.setValue(v);\r
+       }\r
+\r
+       public void setMedian(Binding binding, Object v) throws HistoryException\r
+       {\r
+               medianField.setValue(binding, v);\r
+       }\r
+       \r
+       /// Min ///\r
+       public boolean hasMin() {\r
+               return minField.isEnabled();\r
+       }\r
+       \r
+       public Binding getMinBinding() {\r
+               return minField.binding;\r
+       }\r
+       \r
+       public Object getMin() throws HistoryException {\r
+               return minField.getValue();\r
+       }\r
+\r
+       public Object getMin(Binding b) throws HistoryException {\r
+               return minField.getValue(b);\r
+       }\r
+       \r
+       public double getMinDouble() throws HistoryException {\r
+               return minField.getDoubleValue();\r
+       }\r
+       \r
+       public void setMin(Object v) throws HistoryException {\r
+               minField.setValue(v);\r
+       }       \r
+\r
+       public void setMin(Binding binding, Object v) throws HistoryException\r
+       {\r
+               minField.setValue(binding, v);\r
+       }\r
+       \r
+       /// Max ///\r
+       public boolean hasMax() {\r
+               return maxField.isEnabled();\r
+       }\r
+       \r
+       public Binding getMaxBinding() {\r
+               return maxField.binding;\r
+       }\r
+       \r
+       public Object getMax() throws HistoryException {\r
+               return maxField.getValue();\r
+       }\r
+\r
+       public Object getMax(Binding b) throws HistoryException {\r
+               return maxField.getValue(b);\r
+       }\r
+       \r
+       public double getMaxDouble() throws HistoryException {\r
+               return maxField.getDoubleValue();\r
+       }\r
+       \r
+       public void setMax(Object v) throws HistoryException {\r
+               maxField.setValue(v);\r
+       }       \r
+       \r
+       public void setMax(Binding binding, Object v) throws HistoryException\r
+       {\r
+               maxField.setValue(binding, v);\r
+       }\r
+       \r
+       \r
+       /// Count ///\r
+       public boolean hasCount() {\r
+               return countField.isEnabled();\r
+       }\r
+       \r
+       public NumberBinding getCountBinding() {\r
+               return (NumberBinding) countField.binding;\r
+       }\r
+       \r
+       public int getCount() throws HistoryException {\r
+               Integer i = (Integer) countField.getValue( Bindings.INTEGER );\r
+               return i == null ? 0 : i;\r
+       }\r
+\r
+       public Object getCount(Binding b) throws HistoryException {\r
+               return countField.getValue(b);\r
+       }\r
+       \r
+       public void setCount(int v) throws HistoryException {\r
+               countField.setValue(Bindings.INTEGER, v);\r
+       }       \r
+\r
+       /// Quality ///\r
+       public boolean hasQuality() {\r
+               return qualityField.isEnabled();\r
+       }\r
+       \r
+       public Binding getQualityBinding() {\r
+               return qualityField.binding;\r
+       }\r
+       \r
+       public Object getQuality() throws HistoryException {\r
+               return qualityField.getValue();\r
+       }\r
+\r
+       public Object getQuality(Binding b) throws HistoryException {\r
+               return qualityField.getValue(b);\r
+       }\r
+       \r
+       public void setQuality(Object v) throws HistoryException {\r
+               qualityField.setValue(v);\r
+       }       \r
+\r
+       public void setQuality(Binding binding, Object v) throws HistoryException\r
+       {\r
+               qualityField.setValue(binding, v);\r
+       }\r
+       \r
+       \r
+       /**\r
+        * Value band is a region of one or more samples.\r
+        * This method returns true, if value band is expressed with a single sample.\r
+        * \r
+        * If value band is expressed with two samples, there is start and end\r
+        * sample. The format is typicaly simple (time, value).  \r
+        * \r
+        * @return true if it can represent more than one sample\r
+        */\r
+       public boolean isRanged()\r
+       {\r
+               return endTimeField.isEnabled();\r
+       }\r
+       \r
+       public boolean isValidValue() throws HistoryException {\r
+               return !isNanSample() && !isNullValue();\r
+       }\r
+\r
+       /**\r
+        * Return true, if this sample \r
+        * \r
+        * @return true if the value is Not-a-number\r
+        */\r
+       public boolean isNanSample() {\r
+               try {\r
+                       if (valueField.binding instanceof DoubleBinding) {\r
+                               DoubleBinding db = (DoubleBinding) valueField.binding;\r
+                               double d = db.getValue_( binding.getComponent(sample, valueField.index) );\r
+                               return Double.isNaN( d );\r
+                       }\r
+                       if (valueField.binding instanceof FloatBinding) {\r
+                               FloatBinding db = (FloatBinding) valueField.binding;\r
+                               float d = db.getValue_( binding.getComponent(sample, valueField.index) );\r
+                               return Float.isNaN( d );\r
+                       }\r
+                       return false;\r
+               } catch (BindingException e) {\r
+                       return false;\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Returns true, if this sample format supports a way to express \r
+        * discontinuation regions. \r
+        * \r
+        * @return true if can support discontinuation\r
+        */\r
+       public boolean supportsNullValue() {\r
+               return qualityField.isEnabled();\r
+       }\r
+       \r
+       /**\r
+        * Marks this sample as discontinuation sample\r
+        * @throws HistoryException \r
+        */\r
+       public void setValueNull() throws HistoryException {\r
+               qualityField.setValue(Bindings.BYTE, QUALITY_NOVALUE);\r
+       }\r
+       \r
+       /**\r
+        * Returns true, if the sample is discontinuation sample\r
+        * \r
+        * @return true, if the sample is discontinuation sample\r
+        * @throws HistoryException \r
+        */\r
+       public boolean isNullValue() throws HistoryException {\r
+               Byte b = (Byte) qualityField.getValue(Bindings.BYTE);\r
+               return b == null ? false : b.equals( QUALITY_NOVALUE );\r
+       }\r
+       \r
+       public boolean isNumericValue() {\r
+               return valueField.isNumeric();\r
+       }\r
+       \r
+       @Override\r
+       public String toString() {\r
+               try {\r
+                       return binding.toString(sample);\r
+               } catch (BindingException e) {\r
+                       return e.toString();\r
+               }\r
+       }\r
+       \r
+       class FieldAdapter {\r
+               /** Binding of the field, with possible optionalbinding stripped */\r
+               Binding binding;\r
+               \r
+               /// Adapter1 is cached adapter for setValue  \r
+               Binding adapter1binding;\r
+               Adapter adapter1;\r
+               \r
+               /// Adapter2 is cached adapter for getValue\r
+               Binding adapter2binding;\r
+               Adapter adapter2;\r
+               \r
+               /** Field index in sample record */\r
+               int index;\r
+               \r
+               /** Field name */\r
+               String fieldName;\r
+               \r
+               public FieldAdapter(String fieldName) {\r
+                       this.fieldName = fieldName;\r
+                       index = ValueBand.this.binding.type().getComponentIndex2( fieldName );\r
+                       if (index<0) return;\r
+                       \r
+                       this.binding = ValueBand.this.binding.getComponentBinding(index);\r
+               }\r
+               \r
+               public boolean getBooleanValue() throws HistoryException {\r
+                       if (sample == null || index==-1) return false;\r
+                       try {\r
+                               Object value = ValueBand.this.binding.getComponent(sample, index);\r
+                               if (binding instanceof BooleanBinding) {\r
+                                       return ValueBand.this.binding.getBoolean(sample, index);\r
+//                                     BooleanBinding bb = (BooleanBinding) binding;\r
+//                                     return bb.getValue_( value );\r
+                               }\r
+                               if (binding instanceof ByteBinding) {\r
+                                       ByteBinding nb = (ByteBinding) binding;\r
+                                       return nb.getValue_( value ) != 0;\r
+                               }\r
+                               if (binding instanceof DoubleBinding) {\r
+                                       DoubleBinding nb = (DoubleBinding) binding;\r
+                                       return nb.getValue_( value ) != 0.;\r
+                               }\r
+                               if (binding instanceof NumberBinding) {\r
+                                       NumberBinding nb = (NumberBinding) binding;\r
+                                       return nb.getValue( value ).doubleValue() != 0.;\r
+                               }\r
+                               return false;\r
+                       } catch (BindingException e) {\r
+                               throw new HistoryException( e );\r
+                       }                       \r
+               }\r
+\r
+               public double getDoubleValue() throws HistoryException {\r
+                       if (sample == null || index==-1) return Double.NaN;\r
+                       try {\r
+                               // Read field from record\r
+                               if (binding != Bindings.DOUBLE) {\r
+                                       Object result = ValueBand.this.binding.getComponent(sample, index);\r
+                                       result = Bindings.adapt(result, binding, Bindings.DOUBLE);\r
+                                       return (Double) result;\r
+                               } else {\r
+                                       return ValueBand.this.binding.getDouble(sample, index);\r
+                               }\r
+                       } catch (BindingException e) {\r
+                               throw new HistoryException( e );\r
+                       } catch (AdaptException e) {\r
+                               throw new HistoryException( e );\r
+                       }                       \r
+               }\r
+\r
+               public boolean isEnabled() {\r
+                       return index>=0;\r
+               }\r
+               \r
+               /**\r
+                * Get the value\r
+                *  \r
+                * @return value or null, if value is not available\r
+                * @throws HistoryException\r
+                */\r
+               public Object getValue() throws HistoryException {\r
+                       if (sample == null || index==-1) return null;\r
+                       try {\r
+                               // Read field from record\r
+                               Object result = ValueBand.this.binding.getComponent(sample, index);\r
+\r
+                               return result;\r
+                       } catch (BindingException e) {\r
+                               throw new HistoryException( e );\r
+                       }\r
+               }\r
+\r
+               /**\r
+                * Get the value\r
+                * @param binding\r
+                * @return value in given binding or null, if value is not available\r
+                * @throws HistoryException\r
+                */\r
+               public Object getValue(Binding binding) throws HistoryException {\r
+                       if (sample == null || index==-1) return null;\r
+                       try {\r
+                               // Read field from record\r
+                               Object result = ValueBand.this.binding.getComponent(sample, index);\r
+                               \r
+                               // Adapt value\r
+                               if ( binding != this.binding ) {\r
+                                       if ( binding != adapter2binding ) {\r
+                                               adapter2 = Bindings.adapterFactory.getAdapter(this.binding, binding, true, false);\r
+                                               adapter2binding = binding;\r
+                                       }\r
+                                       result = adapter2.adapt( result );\r
+                               }\r
+\r
+                               return result;\r
+                       } catch (BindingException e) {\r
+                               throw new HistoryException( e );\r
+                       } catch (AdaptException e) {\r
+                               throw new HistoryException( e );\r
+                       } catch (AdapterConstructionException e) {\r
+                               throw new HistoryException( e );\r
+                       }\r
+               }\r
+               \r
+               public void setValue(Object object) throws HistoryException {\r
+                       if (sample == null || index==-1) return;\r
+                       setValue(binding, object);\r
+               }               \r
+                                       \r
+               public void setValue(Binding binding, Object object) throws HistoryException {\r
+                       if (sample == null || index==-1) return;\r
+                       \r
+                       try {\r
+                               // Adapt value                  \r
+                               if (this.binding != binding) {                                  \r
+                                       // Create new adapter\r
+                                       if (binding != adapter1binding) {\r
+                                               adapter1 = Bindings.adapterFactory.getAdapter(binding, this.binding, true, !binding.isImmutable());     \r
+                                               adapter1binding = binding;\r
+                                       }\r
+                                       \r
+                                       // Adapt\r
+                                       object = adapter1.adapt(object);        \r
+                               }\r
+                       \r
+                               // Write value\r
+                               ValueBand.this.binding.setComponent(sample, index, object);\r
+                               \r
+                       } catch (AdaptException e) {\r
+                               throw new HistoryException( e ); \r
+                       } catch (BindingException e) {\r
+                               throw new HistoryException( e ); \r
+                       } catch (AdapterConstructionException e) {\r
+                               throw new HistoryException( e ); \r
+                       }\r
+               }               \r
+       \r
+               public boolean isNumeric() {\r
+                       return binding instanceof NumberBinding;\r
+               }       \r
+       \r
+       }\r
+       \r
+}\r