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;
14 import org.simantics.databoard.Bindings;
15 import org.simantics.databoard.accessor.ArrayAccessor;
16 import org.simantics.databoard.accessor.CloseableAccessor;
17 import org.simantics.databoard.accessor.StreamAccessor;
18 import org.simantics.databoard.accessor.error.AccessorException;
19 import org.simantics.databoard.adapter.AdaptException;
20 import org.simantics.databoard.binding.Binding;
21 import org.simantics.databoard.binding.NumberBinding;
22 import org.simantics.databoard.binding.RecordBinding;
23 import org.simantics.databoard.binding.error.BindingException;
24 import org.simantics.databoard.type.Datatype;
25 import org.simantics.databoard.type.NumberType;
26 import org.simantics.databoard.type.RecordType;
27 import org.simantics.history.HistoryException;
30 * This utility adds random access (time) to array accessor.
32 * @author toni.kalajainen
36 public ArrayAccessor accessor;
37 public RecordType sampleType;
38 public RecordBinding sampleBinding;
41 public Datatype timeType;
42 public Binding timeBinding;
44 public int endTimeIndex;
45 public Datatype endTimeType;
46 public Binding endTimeBinding;
48 public int valueIndex;
49 public Datatype valueType;
50 public Binding valueBinding;
52 public int qualityIndex=-1;
53 public NumberType qualityType;
54 public NumberBinding qualityBinding;
61 public Stream(ArrayAccessor accessor)
63 this.accessor = accessor;
64 this.sampleType = (RecordType) accessor.type().componentType();
65 this.sampleBinding = (RecordBinding) Bindings.getBeanBinding( sampleType );
67 this.valueIndex = sampleType.getComponentIndex2("value");
68 if (valueIndex<0) throw new IllegalArgumentException("Array is not a sample array, value field is missing");
69 this.valueType = sampleType.getComponentType(valueIndex);
70 this.valueBinding = this.sampleBinding.getComponentBinding(valueIndex);
72 this.timeIndex = sampleType.getComponentIndex2("time");
73 if (timeIndex<0) throw new IllegalArgumentException("Array is not a sample array, time field is missing");
74 this.timeType = sampleType.getComponentType(timeIndex);
75 this.timeBinding = this.sampleBinding.getComponentBinding(timeIndex);
77 this.endTimeIndex = sampleType.getComponentIndex2("endTime");
79 this.qualityIndex = sampleType.getComponentIndex2("quality");
80 this.qualityType = qualityIndex>=0?(NumberType)sampleType.getComponentType(qualityIndex):null;
81 this.qualityBinding = qualityType!=null?(NumberBinding)this.sampleBinding.getComponentBinding(qualityIndex):null;
89 public Stream(ArrayAccessor accessor, RecordBinding recordBinding)
91 this.accessor = accessor;
92 this.sampleType = (RecordType) accessor.type().componentType();
93 if (!this.sampleType.equals(recordBinding.type())) throw new IllegalArgumentException("Wrong binding. Got " + recordBinding.type() + ", expected " + this.sampleType);
94 this.sampleBinding = recordBinding;
96 this.valueIndex = sampleType.getComponentIndex2("value");
97 this.timeIndex = sampleType.getComponentIndex2("time");
98 this.endTimeIndex = sampleType.getComponentIndex2("endTime");
100 if (valueIndex<0) throw new IllegalArgumentException("Array is not a sample array, value field is missing");
101 if (timeIndex<0) throw new IllegalArgumentException("Array is not a sample array, time field is missing");
102 //if (endTimeIndex<0) throw new IllegalArgumentException("Array is not a sample array, time field is missing");
104 this.valueType = sampleType.getComponentType(valueIndex);
105 this.timeType = sampleType.getComponentType(timeIndex);
106 this.endTimeType = endTimeIndex>=0 ? sampleType.getComponentType(endTimeIndex) : null;
108 this.valueBinding = this.sampleBinding.getComponentBinding("value");
109 this.timeBinding = this.sampleBinding.getComponentBinding("time");
110 this.endTimeBinding = endTimeIndex>=0 ? this.sampleBinding.getComponentBinding("endTime") : null;
113 public void close() {
114 if (accessor instanceof CloseableAccessor) {
115 CloseableAccessor ca = (CloseableAccessor) accessor;
118 } catch (AccessorException e) {
123 public void reset() {
124 if (accessor instanceof StreamAccessor) {
125 StreamAccessor sa = (StreamAccessor) accessor;
128 } catch (AccessorException e) {
134 * Make a binary search to stream data
139 * @return index of the search key, if it is contained in the array
140 * within the specified range;
141 * otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
142 * <i>insertion point</i> is defined as the point at which the
143 * key would be inserted into the array: the index of the first
144 * element in the range greater than the key,
145 * or <tt>toIndex</tt> if all
146 * elements in the range are less than the specified key. Note
147 * that this guarantees that the return value will be >= 0 if
148 * and only if the key is found.
149 * @throws HistoryException
151 public int binarySearch(Binding timeBinding, Object time) throws HistoryException
154 Object time_ = Bindings.adapt(time, timeBinding, this.timeBinding);
157 int toIndex = accessor.size();
159 int ix = binarySearch0(fromIndex, toIndex, time_);
161 } catch (AccessorException e) {
162 throw new HistoryException(e);
163 } catch (BindingException e) {
164 throw new HistoryException(e);
165 } catch (AdaptException e) {
166 throw new HistoryException(e);
170 // Like public version, but without range checks.
171 private int binarySearch0(int fromIndex, int toIndex, Object key) throws AccessorException, BindingException {
173 int high = toIndex - 1;
174 Binding timeBinding = sampleBinding.getComponentBinding(timeIndex);
176 while (low <= high) {
177 int mid = (low + high) >>> 1;
178 Object midSam = accessor.get(mid, sampleBinding);
179 Object midVal = sampleBinding.getComponent(midSam, timeIndex);
180 int cmp = timeBinding.compare(midVal, key);
186 return mid; // key found
188 return -(low + 1); // key not found.
191 public Object getLowerSample(Binding timeBinding, Object time) throws HistoryException
194 int index = binarySearch(timeBinding, time);
196 if (index==0) return null;
198 return accessor.get(index-1, sampleBinding);
201 if (index<0) return null;
202 if (index>=accessor.size()) return null;
203 return accessor.get(index, sampleBinding);
204 } catch (AccessorException e) {
205 throw new HistoryException( e );
210 public Object getFloorSample(Binding timeBinding, Object time) throws HistoryException
213 int index = binarySearch(timeBinding, time);
216 return accessor.get(index, sampleBinding);
218 // The position where the sample would be inserted
220 if (index<0) return null;
221 if (index>=accessor.size()) return null;
222 return accessor.get(index, sampleBinding);
223 } catch (AccessorException e) {
224 throw new HistoryException( e );
228 public Object getSample(Binding timeBinding, Object time) throws HistoryException
231 int pos = binarySearch(timeBinding, time);
233 return accessor.get(pos, sampleBinding);
236 } catch (AccessorException e) {
237 throw new HistoryException(e);
241 public boolean getSample(Binding timeBinding, Object time, Object sample) throws HistoryException
244 int pos = binarySearch(timeBinding, time);
246 accessor.get(pos, sampleBinding, sample);
250 } catch (AccessorException e) {
251 throw new HistoryException(e);
255 public Object getCeilingSample(Binding timeBinding, Object time) throws HistoryException
258 int index = binarySearch(timeBinding, time);
261 return accessor.get(index, sampleBinding);
263 // The position where the sample would be inserted
265 if (index<0) return null;
266 if (index>=accessor.size()) return null;
267 return accessor.get(index, sampleBinding);
268 } catch (AccessorException e) {
269 throw new HistoryException( e );
273 public Object getHigherSample(Binding timeBinding, Object time) throws HistoryException
276 int index = binarySearch(timeBinding, time);
278 int count = accessor.size();
280 index++; // exact match, -> next
282 // The position where the sample would be inserted
285 if (index<0 || index>=count) return null;
286 return accessor.get(index, sampleBinding);
287 } catch (AccessorException e) {
288 throw new HistoryException( e );
292 private Object _getTime(Object sample, Binding timeBinding) throws HistoryException
295 Object time__ = sampleBinding.getComponent( sample, timeIndex );
296 return Bindings.adapt(time__, this.timeBinding, timeBinding);
297 } catch (AdaptException e) {
298 throw new HistoryException(e);
299 } catch (BindingException e) {
300 throw new HistoryException(e);
304 public Object getItemTime(Binding timeBinding, int index) throws HistoryException
307 return _getTime( accessor.get(index, sampleBinding), timeBinding );
308 } catch (AccessorException e) {
309 throw new HistoryException( e );
313 public Object getLowerTime(Binding timeBinding, Object time) throws HistoryException
316 int index = binarySearch(timeBinding, time);
318 if (index==0) return null;
323 if (index<0) return null;
324 if (index>=accessor.size()) return null;
325 return _getTime(accessor.get(index, sampleBinding), timeBinding);
326 } catch (AccessorException e) {
327 throw new HistoryException( e );
332 public Object getFloorTime(Binding timeBinding, Object time) throws HistoryException
335 int index = binarySearch(timeBinding, time);
340 // The position where the sample would be inserted
342 if (index<0) return null;
343 if (index>=accessor.size()) return null;
344 return _getTime( accessor.get(index, sampleBinding), timeBinding );
345 } catch (AccessorException e) {
346 throw new HistoryException( e );
350 public Object getCeilingTime(Binding timeBinding, Object time) throws HistoryException
353 int index = binarySearch(timeBinding, time);
358 // The position where the sample would be inserted
360 if (index<0) return null;
361 if (index>=accessor.size()) return null;
362 return _getTime( accessor.get(index, sampleBinding), timeBinding );
363 } catch (AccessorException e) {
364 throw new HistoryException( e );
368 public Object getHigherTime(Binding timeBinding, Object time) throws HistoryException
371 int index = binarySearch(timeBinding, time);
374 int count = accessor.size();
376 index++; // exact match, -> next
378 // The position where the sample would be inserted
381 if (index<0 || index>=count) return null;
382 return _getTime( accessor.get(index, sampleBinding), timeBinding );
383 } catch (AccessorException e) {
384 throw new HistoryException( e );
389 public Object getValue(Binding timeBinding, Object time, Binding valueBinding) throws HistoryException
392 int pos = binarySearch(timeBinding, time);
394 Object sample = accessor.get(pos, sampleBinding);
395 Object value = sampleBinding.getComponent(sample, valueIndex);
397 if (valueBinding != this.valueBinding) {
398 value = Bindings.adapt(value, this.valueBinding, valueBinding);
403 } catch (AccessorException e) {
404 throw new HistoryException(e);
405 } catch (BindingException e) {
406 throw new HistoryException(e);
407 } catch (AdaptException e) {
408 throw new HistoryException(e);
412 public Object getValue(Binding timeBinding, Object time) throws HistoryException
415 int pos = binarySearch(timeBinding, time);
417 Object sample = accessor.get(pos, sampleBinding);
418 Object value = sampleBinding.getComponent(sample, valueIndex);
422 } catch (AccessorException e) {
423 throw new HistoryException(e);
424 } catch (BindingException e) {
425 throw new HistoryException(e);
429 public Object getQuality(Binding timeBinding, Object time) throws HistoryException
432 int pos = binarySearch(timeBinding, time);
434 Object sample = accessor.get(pos, sampleBinding);
435 Object value = sampleBinding.getComponent(sample, qualityIndex);
439 } catch (AccessorException e) {
440 throw new HistoryException(e);
441 } catch (BindingException e) {
442 throw new HistoryException(e);
447 * Get value if exists, otherwise null
450 * @return value or null
451 * @throws HistoryException
453 public Object getPossibleValue(Binding timeBinding, Object time) throws HistoryException
456 int pos = binarySearch(timeBinding, time);
458 Object sample = accessor.get(pos, sampleBinding);
459 if (qualityBinding != null) {
460 Object quality = sampleBinding.getComponent(sample, qualityIndex);
461 if ( !qualityBinding.getValue(quality).equals( ValueBand.QUALITY_GOOD ) ) return null;
463 Object value = sampleBinding.getComponent(sample, valueIndex);
467 } catch (AccessorException e) {
468 throw new HistoryException(e);
469 } catch (BindingException e) {
470 throw new HistoryException(e);
474 public int count() throws HistoryException {
476 return accessor.size();
477 } catch (AccessorException e) {
478 throw new HistoryException(e);
482 public Object getFirstTime(Binding binding) throws HistoryException {
484 if (accessor.size()==0) {
487 Object sample = accessor.get(0, sampleBinding);
488 Object time = sampleBinding.getComponent(sample, timeIndex);
489 if (timeBinding!=binding) time = Bindings.adapt(time, timeBinding, binding);
491 } catch (BindingException e) {
492 throw new HistoryException(e);
493 } catch (AccessorException e) {
494 throw new HistoryException(e);
495 } catch (AdaptException e) {
496 throw new HistoryException(e);
500 public Object getEndTime(Binding binding) throws HistoryException {
502 if (accessor.size()==0) {
505 Object sample = accessor.get(0, sampleBinding);
507 if (endTimeIndex>=0) {
508 Object endtime = sampleBinding.getComponent(sample, endTimeIndex);
509 if (endTimeBinding!=binding) endtime = Bindings.adapt(endtime, endTimeBinding, binding);
512 Object time = sampleBinding.getComponent(sample, timeIndex);
513 if (timeBinding!=binding) time = Bindings.adapt(time, timeBinding, binding);
516 } catch (BindingException e) {
517 throw new HistoryException(e);
518 } catch (AccessorException e) {
519 throw new HistoryException(e);
520 } catch (AdaptException e) {
521 throw new HistoryException(e);
525 public boolean isEmpty() throws HistoryException {
527 return accessor.size() == 0;
528 } catch (AccessorException e) {
529 throw new HistoryException(e);