1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.history.util.subscription;
\r
14 import java.util.Arrays;
\r
15 import java.util.Comparator;
\r
17 import org.simantics.databoard.Bindings;
\r
18 import org.simantics.databoard.Datatypes;
\r
19 import org.simantics.databoard.adapter.AdaptException;
\r
20 import org.simantics.databoard.type.ArrayType;
\r
21 import org.simantics.databoard.type.Component;
\r
22 import org.simantics.databoard.type.Datatype;
\r
23 import org.simantics.databoard.type.NumberType;
\r
24 import org.simantics.databoard.type.RecordType;
\r
25 import org.simantics.databoard.util.Bean;
\r
26 import org.simantics.databoard.util.Limit;
\r
27 import org.simantics.databoard.util.Range;
\r
30 * This is an utility class for SubscriptionItem.
\r
32 * The Simantics Charts samples history data in a specified way.
\r
33 * One data source item is recorded into multiple history item, each identified
\r
34 * with a named SamplingFormat. This class describes a named sampling format.
\r
36 * @author toni.kalajainen@semantum.fi
\r
38 public class SamplingFormat extends Bean {
\r
40 public static final SamplingFormat[] EMPTY = new SamplingFormat[0];
\r
42 public final static Comparator<Bean> INTERVAL_COMPARATOR = new Comparator<Bean>() {
\r
44 public int compare(Bean o1, Bean o2) {
\r
45 double i1 = (Double) o1.getFieldUnchecked("interval");
\r
46 double i2 = (Double) o2.getFieldUnchecked("interval");
\r
47 boolean nan1 = Double.isNaN( i1 );
\r
48 boolean nan2 = Double.isNaN( i2 );
\r
50 if ( nan1 && nan2 ) return 0;
\r
51 if ( nan1 && !nan2) return -1;
\r
52 if ( !nan1 && nan2) return 1;
\r
53 return i1 == i2 ? 0 : ( i1 < i2 ? -1 : 1 );
\r
57 public final static Comparator<SamplingFormat> DEADBAND_COMPARATOR = new Comparator<SamplingFormat>() {
\r
59 public int compare(SamplingFormat o1, SamplingFormat o2) {
\r
60 boolean nan1 = Double.isNaN( o1.deadband );
\r
61 boolean nan2 = Double.isNaN( o2.deadband );
\r
63 if ( nan1 && nan2 ) return 0;
\r
64 if ( nan1 && !nan2) return -1;
\r
65 if ( !nan1 && nan2) return 1;
\r
66 return o1.deadband == o2.deadband ? 0 : ( o1.deadband < o2.deadband ? -1 : 1 );
\r
70 /** Identifier, this value is used for separating the time series files */
\r
71 public String formatId;
\r
74 * Describes the format of the packed sample. The sample must be a record.
\r
75 * The record must have any combination of the following named fields.
\r
76 * The field types must one of: byte, integer, long, float, double.
\r
78 * time, endTime, value - are mandatory fields.
\r
80 * time - Region start time, the time of the 1st included sample
\r
81 * endTime - Region end time, the time of the last included sample
\r
83 * value - First value in the region
\r
84 * lastValue - Last value in the region
\r
85 * avg - Average value of all included samples
\r
86 * median - Median value of all samples in the region
\r
87 * min - Lowest value in the region
\r
88 * max - Highest value in the region
\r
90 * quality - 0 = Good, -1 = No value
\r
91 * count - The number of included samples in the region
\r
93 public Datatype format;
\r
95 /** Interval sets the minimum time for a packed sample */
\r
96 public double interval = Double.NaN;
\r
98 /** Deadband determines the minimum value change for a packed sample when collecting data */
\r
99 public double deadband = Double.NaN;
\r
101 public SamplingFormat()
\r
105 public SamplingFormat(String id, RecordType sampleType, double interval, double deadband)
\r
107 this.formatId = id;
\r
108 this.format = sampleType;
\r
109 this.interval = interval;
\r
110 this.deadband = deadband;
\r
113 // Sampling format templates
\r
114 public static SamplingFormat simple, allfields, vector;
\r
116 public RecordType record() { return (RecordType) format; }
\r
119 simple = new SamplingFormat();
\r
120 simple.formatId = "Simple";
\r
121 RecordType format = (RecordType) (simple.format = new RecordType());
\r
122 format.addComponent("time", Datatypes.DOUBLE);
\r
123 format.addComponent("endTime", Datatypes.DOUBLE);
\r
124 format.addComponent("value", Datatypes.DOUBLE);
\r
125 format.addComponent("quality", Datatypes.BYTE);
\r
126 simple.interval = Double.NaN;
\r
127 simple.deadband = Double.NaN;
\r
129 allfields = new SamplingFormat();
\r
130 allfields.formatId = "Allfields";
\r
131 allfields.format = new RecordType();
\r
132 format = (RecordType) (allfields.format = new RecordType());
\r
133 format.addComponent("time", Datatypes.DOUBLE);
\r
134 format.addComponent("endTime", Datatypes.DOUBLE);
\r
136 format.addComponent("value", Datatypes.DOUBLE);
\r
137 format.addComponent("lastValue", Datatypes.DOUBLE);
\r
138 format.addComponent("min", Datatypes.DOUBLE);
\r
139 format.addComponent("max", Datatypes.DOUBLE);
\r
140 format.addComponent("avg", Datatypes.DOUBLE);
\r
141 format.addComponent("median", Datatypes.DOUBLE);
\r
143 format.addComponent("quality", Datatypes.BYTE);
\r
144 format.addComponent("count", Datatypes.INTEGER);
\r
145 allfields.interval = Double.NaN;
\r
146 allfields.deadband = Double.NaN;
\r
148 vector = new SamplingFormat();
\r
149 vector.formatId = "Vector";
\r
150 vector.format = new RecordType();
\r
151 format = (RecordType) (vector.format = new RecordType());
\r
152 format.addComponent("time", Datatypes.FLOAT);
\r
153 format.addComponent("endTime", Datatypes.FLOAT);
\r
154 format.addComponent("value", new ArrayType( Datatypes.DOUBLE, Range.between(Limit.inclusive(3), Limit.inclusive(3)) ));
\r
155 format.addComponent("count", Datatypes.INTEGER);
\r
156 vector.interval = Double.NaN;
\r
157 vector.deadband = Double.NaN;
\r
162 public boolean equals(Object obj) {
\r
163 if ( obj == null ) return false;
\r
164 if ( obj == this ) return true;
\r
165 if ( obj instanceof SamplingFormat == false ) return false;
\r
166 SamplingFormat other = (SamplingFormat) obj;
\r
167 // if ( !doubleEquals(interval, other.interval) || !doubleEquals(deadband, other.deadband) ) return false;
\r
168 // return RecordTypeBinding.equals( other.sampleType, sampleType );
\r
169 return formatId.equals(other.formatId);
\r
173 public String toString() {
\r
174 return "id="+formatId+", "+format +", interval="+interval+", deadband="+deadband;
\r
178 public SamplingFormat clone() {
\r
180 SamplingFormat result = new SamplingFormat();
\r
181 result.formatId = formatId;
\r
182 result.interval = interval;
\r
183 result.deadband = deadband;
\r
184 result.format = (Datatype) Bindings.getBindingUnchecked( Datatype.class ).clone( format );
\r
186 } catch (AdaptException e) {
\r
187 throw new RuntimeException( e );
\r
191 public SamplingFormat clone(double interval, double deadband) {
\r
193 SamplingFormat result = new SamplingFormat();
\r
194 result.formatId = formatId;
\r
195 result.interval = interval;
\r
196 result.deadband = deadband;
\r
197 result.format = (Datatype) Bindings.getBindingUnchecked( Datatype.class ).clone( format );
\r
199 } catch (AdaptException e) {
\r
200 throw new RuntimeException( e );
\r
204 public SamplingFormat cloneTo(String id, double interval, double deadband) {
\r
206 SamplingFormat result = new SamplingFormat();
\r
207 result.formatId = id;
\r
208 result.interval = interval;
\r
209 result.deadband = deadband;
\r
210 result.format = (Datatype) Bindings.getBindingUnchecked( Datatype.class ).clone( format );
\r
212 } catch (AdaptException e) {
\r
213 throw new RuntimeException( e );
\r
217 public SamplingFormat setUnit(String unit) {
\r
218 for ( int i = 0; i<format.getComponentCount(); i++ ) {
\r
219 Component c = ((RecordType)format).getComponent(i);
\r
220 if ( c.name.equals( "value" ) ||
\r
221 c.name.equals( "min" ) ||
\r
222 c.name.equals( "max" ) ||
\r
223 c.name.equals( "avg" ) ||
\r
224 c.name.equals( "median" )
\r
226 if ( c.type instanceof NumberType ) {
\r
227 NumberType nt = (NumberType) c.type;
\r
228 nt.setUnit( unit );
\r
235 public static void sortByInterval( SamplingFormat[] formats ) {
\r
236 Arrays.sort(formats, INTERVAL_COMPARATOR);
\r
239 public static void sortByDeadband( SamplingFormat[] formats ) {
\r
240 Arrays.sort(formats, DEADBAND_COMPARATOR);
\r