]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.history/src/org/simantics/history/util/Stream.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.history / src / org / simantics / history / util / Stream.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
3  * Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.history.util;
13
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;
28
29 /**
30  * This utility adds random access (time) to array accessor.
31  * 
32  * @author toni.kalajainen
33  */
34 public class Stream {
35         
36         public ArrayAccessor accessor;
37         public RecordType sampleType;
38         public RecordBinding sampleBinding;
39         
40         public int timeIndex;
41         public Datatype timeType;
42         public Binding timeBinding;
43         
44         public int endTimeIndex;
45         public Datatype endTimeType;
46         public Binding endTimeBinding;
47         
48         public int valueIndex;
49         public Datatype valueType;
50         public Binding valueBinding;
51
52         public int qualityIndex=-1;
53         public NumberType qualityType;
54         public NumberBinding qualityBinding;
55         
56         /**
57          * Construct stream 
58          * 
59          * @param accessor 
60          */
61         public Stream(ArrayAccessor accessor)
62         {
63                 this.accessor = accessor;
64                 this.sampleType = (RecordType) accessor.type().componentType();
65                 this.sampleBinding = (RecordBinding) Bindings.getBeanBinding( sampleType );
66                 
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);         
71                 
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);
76                 
77                 this.endTimeIndex = sampleType.getComponentIndex2("endTime");
78                 
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;               
82         }
83
84         /**
85          * Construct stream 
86          * 
87          * @param accessor 
88          */
89         public Stream(ArrayAccessor accessor, RecordBinding recordBinding)
90         {
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;
95
96                 this.valueIndex = sampleType.getComponentIndex2("value");
97                 this.timeIndex = sampleType.getComponentIndex2("time");
98                 this.endTimeIndex = sampleType.getComponentIndex2("endTime");
99
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");
103                 
104                 this.valueType = sampleType.getComponentType(valueIndex);
105                 this.timeType = sampleType.getComponentType(timeIndex);
106                 this.endTimeType = endTimeIndex>=0 ? sampleType.getComponentType(endTimeIndex) : null;
107                 
108                 this.valueBinding = this.sampleBinding.getComponentBinding("value");            
109                 this.timeBinding = this.sampleBinding.getComponentBinding("time");
110                 this.endTimeBinding = endTimeIndex>=0 ? this.sampleBinding.getComponentBinding("endTime") : null;
111         }
112
113         public void close() {
114                 if (accessor instanceof CloseableAccessor) {
115                         CloseableAccessor ca = (CloseableAccessor) accessor;
116                         try {
117                                 ca.close();
118                         } catch (AccessorException e) {
119                         }
120                 }
121         }
122         
123         public void reset() {
124                 if (accessor instanceof StreamAccessor) {
125                         StreamAccessor sa = (StreamAccessor) accessor;
126                         try {
127                                 sa.reset();
128                         } catch (AccessorException e) {
129                         }
130                 }
131         }
132         
133         /**
134          * Make a binary search to stream data 
135          * 
136          * @param array
137          * @param timeBinding
138          * @param time 
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 &gt;= 0 if
148      *         and only if the key is found.
149          * @throws HistoryException 
150          */
151         public int binarySearch(Binding timeBinding, Object time) throws HistoryException 
152         {               
153                 try {
154                         Object time_ = Bindings.adapt(time, timeBinding, this.timeBinding);
155                         
156                         int fromIndex = 0;
157                         int toIndex = accessor.size();
158                         
159                         int ix = binarySearch0(fromIndex, toIndex, time_);
160                         return ix;
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);
167                 }
168         }
169         
170     // Like public version, but without range checks.
171     private int binarySearch0(int fromIndex, int toIndex, Object key) throws AccessorException, BindingException {
172                 int low = fromIndex;
173                 int high = toIndex - 1;
174                 Binding timeBinding = sampleBinding.getComponentBinding(timeIndex);
175         
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);
181                     if (cmp < 0)
182                         low = mid + 1;
183                     else if (cmp > 0)
184                         high = mid - 1;
185                     else
186                         return mid; // key found
187                 }
188                 return -(low + 1);  // key not found.
189     }
190         
191     public Object getLowerSample(Binding timeBinding, Object time) throws HistoryException
192     {
193                 try {
194                         int index = binarySearch(timeBinding, time);
195                         // Exact match
196                         if (index==0) return null;
197                         if (index>0) {
198                                 return accessor.get(index-1, sampleBinding);
199                         }
200                         index = -index-2;
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 );
206                 }
207     }
208
209     
210         public Object getFloorSample(Binding timeBinding, Object time) throws HistoryException
211         {
212                 try {
213                         int index = binarySearch(timeBinding, time);
214                         // Exact match
215                         if (index>=0) {
216                                 return accessor.get(index, sampleBinding);
217                         }
218                         // The position where the sample would be inserted
219                         index = -index-2;
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 );
225                 }
226         }
227     
228     public Object getSample(Binding timeBinding, Object time) throws HistoryException
229     {
230                 try {
231                 int pos = binarySearch(timeBinding, time);
232                 if (pos>=0) {
233                                 return accessor.get(pos, sampleBinding);
234                 }
235                 return null;
236                 } catch (AccessorException e) {
237                         throw new HistoryException(e);
238                 }
239     }
240     
241     public boolean getSample(Binding timeBinding, Object time, Object sample) throws HistoryException
242     {
243                 try {
244                 int pos = binarySearch(timeBinding, time);
245                 if (pos>=0) {
246                         accessor.get(pos, sampleBinding, sample);
247                                 return true;
248                 }
249                 return false;
250                 } catch (AccessorException e) {
251                         throw new HistoryException(e);
252                 }
253     }
254     
255     public Object getCeilingSample(Binding timeBinding, Object time) throws HistoryException
256     {
257                 try {
258                         int index = binarySearch(timeBinding, time);
259                         // Exact match
260                         if (index>=0) {
261                                 return accessor.get(index, sampleBinding);
262                         }
263                         // The position where the sample would be inserted
264                         index = -index-1;
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 );
270                 }
271     }
272     
273     public Object getHigherSample(Binding timeBinding, Object time) throws HistoryException
274     {
275                 try {
276                         int index = binarySearch(timeBinding, time);
277                         // Exact match
278                         int count = accessor.size();
279                         if (index>=0) {
280                                 index++; // exact match, -> next
281                         } else {
282                                 // The position where the sample would be inserted
283                                 index = -index-1;
284                         }
285                         if (index<0 || index>=count) return null;
286                         return accessor.get(index, sampleBinding);
287                 } catch (AccessorException e) {
288                         throw new HistoryException( e );
289                 }
290     }
291
292     private Object _getTime(Object sample, Binding timeBinding) throws HistoryException
293     {
294         try {
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);
301                 }
302     }
303     
304     public Object getLowerTime(Binding timeBinding, Object time) throws HistoryException
305     {
306                 try {
307                         int index = binarySearch(timeBinding, time);
308                         // Exact match
309                         if (index==0) return null;
310                         if (index>0) {
311                                 return time;
312                         }
313                         index = -index-2;
314                         if (index<0) return null;
315                         if (index>=accessor.size()) return null;
316                         return _getTime(accessor.get(index, sampleBinding), timeBinding);
317                 } catch (AccessorException e) {
318                         throw new HistoryException( e );
319                 }
320     }
321
322     
323         public Object getFloorTime(Binding timeBinding, Object time) throws HistoryException
324         {
325                 try {
326                         int index = binarySearch(timeBinding, time);
327                         // Exact match
328                         if (index>=0) {
329                                 return time;
330                         }
331                         // The position where the sample would be inserted
332                         index = -index-2;
333                         if (index<0) return null;
334                         if (index>=accessor.size()) return null;
335                         return _getTime( accessor.get(index, sampleBinding), timeBinding );
336                 } catch (AccessorException e) {
337                         throw new HistoryException( e );
338                 }
339         }
340     
341     public Object getCeilingTime(Binding timeBinding, Object time) throws HistoryException
342     {
343                 try {
344                         int index = binarySearch(timeBinding, time);
345                         // Exact match
346                         if (index>=0) {
347                                 return time;
348                         }
349                         // The position where the sample would be inserted
350                         index = -index-1;
351                         if (index<0) return null;
352                         if (index>=accessor.size()) return null;
353                         return _getTime( accessor.get(index, sampleBinding), timeBinding );
354                 } catch (AccessorException e) {
355                         throw new HistoryException( e );
356                 }
357     }
358     
359     public Object getHigherTime(Binding timeBinding, Object time) throws HistoryException
360     {
361                 try {
362                         int index = binarySearch(timeBinding, time);
363                         
364                         // Exact match
365                         int count = accessor.size();
366                         if (index>=0) {
367                                 index++; // exact match, -> next
368                         } else {
369                                 // The position where the sample would be inserted
370                                 index = -index-1;
371                         }
372                         if (index<0 || index>=count) return null;
373                         return _getTime( accessor.get(index, sampleBinding), timeBinding );
374                 } catch (AccessorException e) {
375                         throw new HistoryException( e );
376                 }
377     }
378     
379     
380     public Object getValue(Binding timeBinding, Object time, Binding valueBinding) throws HistoryException
381     {
382                 try {
383                 int pos = binarySearch(timeBinding, time);
384                 if (pos>=0) {
385                                 Object sample = accessor.get(pos, sampleBinding);
386                                 Object value = sampleBinding.getComponent(sample, valueIndex);
387                                 
388                                 if (valueBinding != this.valueBinding) {
389                                         value = Bindings.adapt(value, this.valueBinding, valueBinding);
390                                 } 
391                                 return value;
392                 }
393                 return null;
394                 } catch (AccessorException e) {
395                         throw new HistoryException(e);
396                 } catch (BindingException e) {
397                         throw new HistoryException(e);
398                 } catch (AdaptException e) {
399                         throw new HistoryException(e);
400                 }
401     }
402         
403     public Object getValue(Binding timeBinding, Object time) throws HistoryException
404     {
405                 try {
406                 int pos = binarySearch(timeBinding, time);
407                 if (pos>=0) {
408                                 Object sample = accessor.get(pos, sampleBinding);
409                                 Object value = sampleBinding.getComponent(sample, valueIndex);
410                                 return value;
411                 }
412                 return null;
413                 } catch (AccessorException e) {
414                         throw new HistoryException(e);
415                 } catch (BindingException e) {
416                         throw new HistoryException(e);
417                 }
418     }
419     
420     public Object getQuality(Binding timeBinding, Object time) throws HistoryException
421     {
422                 try {
423                 int pos = binarySearch(timeBinding, time);
424                 if (pos>=0) {
425                                 Object sample = accessor.get(pos, sampleBinding);
426                                 Object value = sampleBinding.getComponent(sample, qualityIndex);
427                                 return value;
428                 }
429                 return null;
430                 } catch (AccessorException e) {
431                         throw new HistoryException(e);
432                 } catch (BindingException e) {
433                         throw new HistoryException(e);
434                 }
435     }
436     
437     /**
438      * Get value if exists, otherwise null
439      * @param timeBinding
440      * @param time
441      * @return value or null
442      * @throws HistoryException
443      */
444     public Object getPossibleValue(Binding timeBinding, Object time) throws HistoryException
445     {
446                 try {
447                 int pos = binarySearch(timeBinding, time);
448                 if (pos>=0) {
449                                 Object sample = accessor.get(pos, sampleBinding);
450                                 if (qualityBinding != null) {                                   
451                                         Object quality = sampleBinding.getComponent(sample, qualityIndex);                                      
452                                         if ( !qualityBinding.getValue(quality).equals( ValueBand.QUALITY_GOOD ) ) return null;                                  
453                                 }
454                                 Object value = sampleBinding.getComponent(sample, valueIndex);
455                                 return value;
456                 }
457                 return null;
458                 } catch (AccessorException e) {
459                         throw new HistoryException(e);
460                 } catch (BindingException e) {
461                         throw new HistoryException(e);
462                 }
463     }
464     
465     public int count() throws HistoryException {
466         try {
467                         return accessor.size();
468                 } catch (AccessorException e) {
469                         throw new HistoryException(e);
470                 }
471     }
472         
473     public Object getFirstTime(Binding binding) throws HistoryException {
474         try {
475                 if (accessor.size()==0) {
476                         return null;
477                 }
478                 Object sample = accessor.get(0, sampleBinding);
479                 Object time = sampleBinding.getComponent(sample, timeIndex);
480                 if (timeBinding!=binding) time = Bindings.adapt(time, timeBinding, binding);
481                 return time;
482         } catch (BindingException e) {
483                 throw new HistoryException(e);
484         } catch (AccessorException e) {
485                 throw new HistoryException(e);
486                 } catch (AdaptException e) {
487                 throw new HistoryException(e);
488                 }
489     }
490     
491     public Object getEndTime(Binding binding) throws HistoryException {
492         try {
493                 if (accessor.size()==0) {
494                         return null;
495                 }
496                 Object sample = accessor.get(0, sampleBinding);
497                 
498                 if (endTimeIndex>=0) {
499                         Object endtime = sampleBinding.getComponent(sample, endTimeIndex);
500                         if (endTimeBinding!=binding) endtime = Bindings.adapt(endtime, endTimeBinding, binding);
501                         return endtime;
502                 } else {
503                         Object time = sampleBinding.getComponent(sample, timeIndex);
504                         if (timeBinding!=binding) time = Bindings.adapt(time, timeBinding, binding);
505                         return time;                    
506                 }
507         } catch (BindingException e) {
508                 throw new HistoryException(e);
509         } catch (AccessorException e) {
510                 throw new HistoryException(e);
511                 } catch (AdaptException e) {
512                 throw new HistoryException(e);
513                 }
514     }
515
516         public boolean isEmpty() throws HistoryException {
517                 try {
518                         return accessor.size() == 0;
519                 } catch (AccessorException e) {
520                 throw new HistoryException(e);
521                 }
522         }
523     
524 }