]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.simulation/src/org/simantics/simulation/data/DatasourceAdapter.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.simulation / src / org / simantics / simulation / data / DatasourceAdapter.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.simulation.data;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.HashSet;\r
17 import java.util.List;\r
18 import java.util.Set;\r
19 import java.util.concurrent.Executor;\r
20 import java.util.concurrent.locks.Lock;\r
21 import java.util.concurrent.locks.ReentrantLock;\r
22 import java.util.logging.Level;\r
23 import java.util.logging.Logger;\r
24 \r
25 import org.simantics.databoard.Bindings;\r
26 import org.simantics.databoard.accessor.error.AccessorException;\r
27 import org.simantics.databoard.binding.Binding;\r
28 import org.simantics.databoard.binding.NumberBinding;\r
29 import org.simantics.databoard.type.Datatype;\r
30 import org.simantics.history.Collector;\r
31 import org.simantics.history.HistoryException;\r
32 import org.simantics.history.util.subscription.SubscriptionItem;\r
33 import org.simantics.simulation.data.Datasource.DatasourceListener;\r
34 import org.simantics.utils.datastructures.Triple;\r
35 \r
36 /**\r
37  * This adapter reads data from Datasource and writes to an open Subscription.\r
38  * This class is used as a listener. \r
39  * \r
40  * @author Toni Kalajainen <toni.kalajainen@semantum.fi>\r
41  */\r
42 public class DatasourceAdapter implements DatasourceListener {\r
43 \r
44         protected Logger logger = Logger.getLogger( DatasourceAdapter.class.toString() );\r
45         protected Collector session;\r
46         protected boolean loaded = false;\r
47         protected List<VariableHandle> handles = new ArrayList<VariableHandle>();\r
48         protected List<String> ids = new ArrayList<String>();\r
49         protected List<Binding> bindings = new ArrayList<Binding>();\r
50 \r
51         /**\r
52          * Variables whose {@link VariableHandle#getValue()} has previously failed\r
53          * and has been reported to have failed through {@link #logger}. Resetting\r
54          * the adapter will also reset this set.\r
55          */\r
56         protected Set<String> failedIds = new HashSet<String>();\r
57 \r
58         protected Lock stepLock = new ReentrantLock();\r
59         \r
60         /**\r
61          * Create new adapter. Subscribed items are read from collector. \r
62          * \r
63          * @param subscription\r
64          */\r
65         public DatasourceAdapter(Collector subscription) {\r
66                 this.session = subscription;\r
67         }\r
68         \r
69         public void setSubscriptionSession(Collector session) {\r
70                 this.session = session;\r
71         }\r
72         \r
73         public Collector getSubscriptionSession() {\r
74                 return session;\r
75         }\r
76         \r
77         public void flush() throws HistoryException {\r
78                 session.flush();\r
79         }\r
80 \r
81         /**\r
82          * @return the lock that is used for synchronizing each\r
83          *         {@link #onStep(Datasource)} invocation. The lock can be used\r
84          *         elsewhere to guarantee that history collection steps are not\r
85          *         taken meanwhile. For example, while setting up history\r
86          *         collection.\r
87          */\r
88         public Lock stepLock() {\r
89                 return stepLock;\r
90         }\r
91 \r
92         /**\r
93          * Reset internal caches. Call this when subscribed items in collector\r
94          * have changed.\r
95          */\r
96         public void reset() {\r
97                 for (VariableHandle h : handles) if (h!=null) h.dispose();\r
98                 bindings.clear();\r
99                 handles.clear();\r
100                 ids.clear();\r
101                 failedIds.clear();\r
102                 loaded = false;\r
103         }\r
104 \r
105         protected void load(Datasource source) {\r
106                 reset();\r
107 \r
108                 // Read ids             \r
109                 SubscriptionItem[] items = session.getItems();\r
110                 Set<String> idSet = new HashSet<String>(items.length);\r
111                 for (SubscriptionItem bean : items) {\r
112                         String variableId = (String) bean.getFieldUnchecked("variableId");\r
113                         if (!idSet.add( variableId )) continue;\r
114                         Datatype variableType = source.getType( variableId );\r
115                         if (variableType == null) continue;\r
116                         Binding valueBinding = Bindings.getBinding( variableType );\r
117                         VariableHandle handle = source.openHandle( bean, variableId, valueBinding );\r
118                         handles.add( handle );\r
119                         ids.add( variableId );\r
120                         bindings.add( valueBinding );\r
121                 }\r
122                 loaded = true;\r
123         }\r
124 \r
125         protected void list(Collection<Triple<String,Binding,Object>> result, Collection<GraphHandle> graphHandles) {\r
126             \r
127         int c = ids.size();\r
128         for (int i=0; i<c; i++) {\r
129             String key = ids.get(i);\r
130             VariableHandle handle = handles.get(i);\r
131             Object value = null;\r
132             if (handle != null) {\r
133                 if (handle instanceof GraphHandle) {\r
134                     graphHandles.add((GraphHandle)handle);\r
135                 } else {\r
136                     try {\r
137                         value = handle.getValue();\r
138                         Binding binding = bindings.get(i);\r
139                         result.add(Triple.make(key, binding, value));\r
140                     } catch (AccessorException e) {\r
141                         if (failedIds.add(key))\r
142                             logger.log(Level.SEVERE, e.toString(), e);\r
143                         continue;\r
144                     }\r
145                 }\r
146             } else {\r
147                 Binding binding = bindings.get(i);\r
148                 result.add(Triple.make(key, binding, value));\r
149             }\r
150         }\r
151         }\r
152         \r
153         @Override\r
154     public void onStep(Datasource source) {\r
155         stepLock.lock();\r
156         try {\r
157             NumberBinding timeBinding = Bindings.DOUBLE;\r
158             Object time = source.getTime( timeBinding );\r
159             session.beginStep( timeBinding, time );\r
160 \r
161             if (!loaded) load( source );\r
162 \r
163             try {\r
164 \r
165                 int c = ids.size();\r
166                 for (int i=0; i<c; i++) {\r
167                     String key = ids.get(i);\r
168                     VariableHandle handle = handles.get(i);\r
169                     Object value = null;\r
170                     if (handle != null) {\r
171                         try {\r
172                             value = handle.getValue();\r
173                         } catch (AccessorException e) {\r
174                             if (failedIds.add(key))\r
175                                 logger.log(Level.SEVERE, e.toString(), e);\r
176                             continue;\r
177                         }\r
178                         Binding binding = handle.binding();\r
179                         try {\r
180                             session.setValue( key, binding, value );\r
181                         } catch (HistoryException e) {\r
182                             logger.log(Level.SEVERE, e.toString(), e);\r
183                         }\r
184                     } else {\r
185                         Binding binding = bindings.get(i);\r
186                         if (binding != null) { \r
187                             session.setValue( key, binding, value );\r
188                         }                       \r
189                     }\r
190                 }\r
191 \r
192             } finally {\r
193                 try {\r
194                     session.endStep();\r
195                 } catch (HistoryException e) {\r
196                     logger.log(Level.SEVERE, e.toString(), e);\r
197                 }\r
198             }\r
199         } catch (HistoryException e) {\r
200             logger.log(Level.SEVERE, e.toString(), e);\r
201         } finally {\r
202             stepLock.unlock();\r
203         }\r
204     }\r
205 \r
206         @Override\r
207         public Executor getExecutor() {\r
208                 return null;\r
209         }\r
210         \r
211 \r
212 }\r