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