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