]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/src/org/simantics/modeling/subscription/CollectSubscriptions.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / subscription / CollectSubscriptions.java
1 /*******************************************************************************\r
2  * Copyright (c) 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.modeling.subscription;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.Collections;\r
17 import java.util.Map;\r
18 import java.util.TreeMap;\r
19 \r
20 import org.eclipse.core.runtime.MultiStatus;\r
21 import org.simantics.databoard.Bindings;\r
22 import org.simantics.databoard.Databoard;\r
23 import org.simantics.databoard.binding.Binding;\r
24 import org.simantics.databoard.type.Datatype;\r
25 import org.simantics.db.ReadGraph;\r
26 import org.simantics.db.Resource;\r
27 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;\r
28 import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
29 import org.simantics.db.common.request.BinaryRead;\r
30 import org.simantics.db.common.request.ObjectsWithType;\r
31 import org.simantics.db.common.request.ResourceRead;\r
32 import org.simantics.db.common.request.TernaryRead;\r
33 import org.simantics.db.common.utils.NameUtils;\r
34 import org.simantics.db.exception.DatabaseException;\r
35 import org.simantics.db.layer0.variable.RVI;\r
36 import org.simantics.db.layer0.variable.Variable;\r
37 import org.simantics.db.layer0.variable.Variables;\r
38 import org.simantics.history.util.subscription.SubscriptionItem;\r
39 import org.simantics.layer0.Layer0;\r
40 import org.simantics.modeling.ModelingResources;\r
41 import org.simantics.scl.runtime.tuple.Tuple3;\r
42 import org.simantics.simulation.experiment.IDynamicExperiment;\r
43 import org.simantics.simulation.ontology.SimulationResource;\r
44 import org.simantics.utils.datastructures.Pair;\r
45 \r
46 import gnu.trove.map.hash.THashMap;\r
47 \r
48 /**\r
49  * @author Tuukka Lehtonen\r
50  */\r
51 public class CollectSubscriptions extends ResourceRead<SubscriptionCollectionResult> {\r
52 \r
53     private static final boolean PERF = false;\r
54     private static final boolean DEBUG = false;\r
55 \r
56     protected Resource           experiment;\r
57     protected double             defaultSamplingInterval;\r
58     protected boolean            synchronous;\r
59 \r
60     public CollectSubscriptions(IDynamicExperiment experiment, double defaultSamplingInterval) {\r
61         this(experiment.getModel(), experiment.getResource(), defaultSamplingInterval, false);\r
62     }\r
63 \r
64     public CollectSubscriptions(IDynamicExperiment experiment, double defaultSamplingInterval, boolean synchronous) {\r
65         this(experiment.getModel(), experiment.getResource(), defaultSamplingInterval, synchronous);\r
66     }\r
67 \r
68     public CollectSubscriptions(Resource model, Resource experiment, double defaultSamplingInterval) {\r
69         this(model, experiment, defaultSamplingInterval, false);\r
70     }\r
71 \r
72     public CollectSubscriptions(Resource model, Resource experiment, double defaultSamplingInterval, boolean synchronous) {\r
73         super(model);\r
74         this.experiment = experiment;\r
75         this.defaultSamplingInterval = defaultSamplingInterval;\r
76     }\r
77 \r
78     @Override\r
79     public SubscriptionCollectionResult perform(ReadGraph graph) throws DatabaseException {\r
80         MultiStatus status = new MultiStatus(ModelHistoryCollector.BUNDLE_ID, 0, "History collection subscription resolution problems:", null);\r
81         boolean oldSync = graph.setSynchronous(synchronous);\r
82         try {\r
83             Map<String, SubscriptionItem> items = gatherSubscriptions(graph, resource, status, new TreeMap<String, SubscriptionItem>());\r
84             return new SubscriptionCollectionResult(new ArrayList<>(items.values()), status);\r
85         } finally {\r
86             graph.setSynchronous(oldSync);\r
87         }\r
88     }\r
89 \r
90     /**\r
91      * Scans thru a model and writes up all the variables that are to be monitored.\r
92      * This includes:\r
93      *   Subscriptions\r
94      *   Charts\r
95      *   Spreadsheets (not in cur. impl)\r
96      *   Monitors on diagram (not in cur. impl)\r
97      * \r
98      * @param graph\r
99      * @param model\r
100      * @param status \r
101      * @param variablesToMonitor\r
102      * @throws DatabaseException\r
103      */\r
104     public Map<String, SubscriptionItem> gatherSubscriptions(ReadGraph graph, Resource model, MultiStatus status,\r
105             Map<String, SubscriptionItem> items) throws DatabaseException {\r
106         if (PERF)\r
107             System.out.println("DEBUG: CollectAprosSubscriptions.gatherSubscriptions");\r
108         long start = System.nanoTime();\r
109 \r
110         // Get active experiment context if possible to be able\r
111         // to resolve the whole model, not just the configuration.\r
112         Variable configuration = Variables.getPossibleConfigurationContext(graph, model);\r
113         if (configuration == null)\r
114             return items;\r
115         Variable experimentVariable = null;\r
116 \r
117         SimulationResource SIMU = SimulationResource.getInstance(graph);\r
118         Layer0 L0 = Layer0.getInstance(graph);\r
119         for (Resource run : graph.syncRequest(new ObjectsWithType(experiment, L0.ConsistsOf, SIMU.Run))) {\r
120             if (graph.hasStatement(run, SIMU.IsActive)) {\r
121                 try {\r
122                     experimentVariable = Variables.switchRealization(graph, configuration, run);\r
123                 } catch (DatabaseException e) {\r
124                     experimentVariable = Variables.switchPossibleContext(graph, configuration, run);\r
125                 }\r
126             }\r
127         }\r
128 \r
129         ModelingResources MOD = ModelingResources.getInstance(graph);\r
130         Param constants = new Param(configuration, experimentVariable, defaultSamplingInterval);\r
131         for (Resource subscription : graph.syncRequest(new ObjectsWithType(model, L0.ConsistsOf, MOD.Subscription))) {\r
132             Map<String, SubscriptionItem> subscriptionItems = graph.syncRequest(\r
133                     new SubscriptionRequest(subscription, constants),\r
134                     TransientCacheAsyncListener.<Map<String, SubscriptionItem>>instance());\r
135             items.putAll(subscriptionItems);\r
136         }\r
137 \r
138         if (PERF)\r
139             System.out.println("DEBUG: CollectAprosSubscriptions.gatherSubscriptions ENDS, took " + ((System.nanoTime() - start)*1e-6) + " ms with " + items.size() + " items");\r
140 \r
141         return items;\r
142     }\r
143 \r
144     static class Param extends Tuple3 {\r
145         public Param(Variable configurationContext, Variable experimentContext, Double defaultSamplingInterval) {\r
146             super(configurationContext, experimentContext, defaultSamplingInterval);\r
147         }\r
148     }\r
149 \r
150     static class SubscriptionRequest extends BinaryRead<Resource, Param, Map<String, SubscriptionItem>> {\r
151 \r
152         public SubscriptionRequest(Resource subscription, Param constants) {\r
153             super(subscription, constants);\r
154         }\r
155 \r
156         @Override\r
157         public Map<String, SubscriptionItem> perform(ReadGraph graph) throws DatabaseException {\r
158             if (PERF)\r
159                 System.out.println("DEBUG: CollectSubscriptions.SubscriptionRequest(" + NameUtils.getSafeName(graph, parameter, true) + ")");\r
160             long start = System.nanoTime();\r
161 \r
162             ModelingResources MOD = ModelingResources.getInstance(graph);\r
163             Boolean v = graph.getPossibleRelatedValue(parameter, MOD.Subscription_Enabled, Bindings.BOOLEAN);\r
164             if (!Boolean.TRUE.equals(v))\r
165                 return Collections.emptyMap();\r
166 \r
167             Layer0 L0 = Layer0.getInstance(graph);\r
168             String groupId = graph.getPossibleRelatedValue(parameter, L0.HasName, Bindings.STRING);\r
169             if (groupId == null)\r
170                 return Collections.emptyMap();\r
171 \r
172             Map<String, SubscriptionItem> items = graph.syncRequest(\r
173                     new SubscriptionItemsRequest(parameter, groupId, parameter2),\r
174                     TransientCacheAsyncListener.<Map<String, SubscriptionItem>>instance());\r
175             if (PERF)\r
176                 System.out.println("DEBUG: CollectSubscriptions.SubscriptionRequest(" + NameUtils.getSafeName(graph, parameter, true) + ") DONE in " + ((System.nanoTime() - start)*1e-6) + " ms");\r
177 \r
178             return items;\r
179         }\r
180 \r
181     }\r
182 \r
183     static class SubscriptionItemsRequest extends TernaryRead<Resource, String, Param, Map<String, SubscriptionItem>> {\r
184 \r
185         public SubscriptionItemsRequest(Resource subscription, String groupId, Param constants) {\r
186             super(subscription, groupId, constants);\r
187         }\r
188 \r
189         @Override\r
190         public Map<String, SubscriptionItem> perform(ReadGraph graph) throws DatabaseException {\r
191             if (PERF)\r
192                 System.out.println("DEBUG: CollectSubscriptions.SubscriptionItemsRequest(" + NameUtils.getSafeName(graph, parameter, true) + ")");\r
193             long start = System.nanoTime();\r
194 \r
195             Layer0 L0 = Layer0.getInstance(graph);\r
196             ModelingResources MOD = ModelingResources.getInstance(graph);\r
197 \r
198             Collection<Resource> subscriptionItems = graph.syncRequest(new ObjectsWithType(parameter, L0.ConsistsOf, MOD.Subscription_Item));\r
199             if (subscriptionItems.isEmpty())\r
200                 return Collections.emptyMap();\r
201 \r
202             Map<String, SubscriptionItem> result = new THashMap<>(subscriptionItems.size());\r
203             for (Resource subscriptionItem : subscriptionItems) {\r
204                 SubscriptionItem hi = graph.syncRequest(\r
205                         new ItemRequest(subscriptionItem, parameter2, parameter3),\r
206                         TransientCacheListener.<SubscriptionItem>instance());\r
207                 if (hi != null)\r
208                     result.put(hi.id, hi);\r
209             }\r
210 \r
211             if (PERF)\r
212                 System.out.println("DEBUG: CollectSubscriptions.SubscriptionItemsRequest(" + NameUtils.getSafeName(graph, parameter, true) + ") DONE in " + ((System.nanoTime() - start)*1e-6) + " ms with " + result.size() + " items");\r
213 \r
214             return result;\r
215         }\r
216 \r
217     }\r
218 \r
219     static class ItemRequest extends TernaryRead<Resource, String, Param, SubscriptionItem> {\r
220 \r
221         public ItemRequest(Resource item, String groupId, Param constants) {\r
222             super(item, groupId, constants);\r
223         }\r
224 \r
225         @Override\r
226         public SubscriptionItem perform(ReadGraph graph) throws DatabaseException {\r
227             ModelingResources MOD = ModelingResources.getInstance(graph);\r
228             Resource subscriptionItem = parameter;\r
229             String groupId = parameter2;\r
230             Param constants = parameter3;\r
231             Variable configurationContext = (Variable) constants.c0;\r
232             Variable experimentContext = (Variable) constants.c1;\r
233             double defaultSamplingInterval = (double) constants.c2;\r
234 \r
235             Binding rviBinding = graph.getService(Databoard.class).getBindingUnchecked( RVI.class );\r
236             RVI rvi = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_VariableId, rviBinding);\r
237             if (rvi == null) {\r
238                 //status.add(new Status(IStatus.WARNING, ModelHistoryCollector.BUNDLE_ID, "Subscription Item '" + NameUtils.getSafeName(graph, subscriptionItem) + "' is missing RVI property"));\r
239                 return null;\r
240             }\r
241 \r
242             Layer0 L0 = Layer0.getInstance(graph);\r
243             String guid = graph.getPossibleRelatedValue(subscriptionItem, L0.HasName);\r
244             if (guid == null) {\r
245                 //status.add(new Status(IStatus.WARNING, ModelHistoryCollector.BUNDLE_ID, "Subscription Item '" + NameUtils.getSafeName(graph, subscriptionItem) + "' has no name (ID)."));\r
246                 return null;\r
247             }\r
248             String variablePersistentId = rvi.toString();\r
249             Pair<Variable, Variable> variable = Variables.resolvePossible(graph, rvi, configurationContext, experimentContext);\r
250             if (variable == null) {\r
251                 if (DEBUG)\r
252                     System.out.println("DEBUG: unresolvable subscription: " + variablePersistentId);\r
253                 // Don't log these, these problems are conveyed to the\r
254                 // user through model browser UI labels.\r
255                 //status.add(new Status(IStatus.WARNING, ModelHistoryCollector.BUNDLE_ID, "Subscription Item '" + NameUtils.getSafeName(graph, subscriptionItem) + "' variable cannot be resolved from RVI " + rvi.toString(graph)));\r
256                 return null;\r
257             }\r
258             String variableId = rvi.asPossibleString(graph, variable.second);\r
259             //System.out.println("DEBUG: " + variablePersistentId + " - " + variableId);\r
260             if (variableId == null) {\r
261                 return null;\r
262             }\r
263 \r
264             Datatype type = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_Datatype, Bindings.getBindingUnchecked(Datatype.class));\r
265             if (type == null && variable != null) {\r
266                 type = variable.first.getPossibleDatatype(graph);\r
267             }\r
268             if (type == null) {\r
269                 //status.add(new Status(IStatus.WARNING, ModelHistoryCollector.BUNDLE_ID, "Subscription Item '" + NameUtils.getSafeName(graph, subscriptionItem) + "' is missing data type"));\r
270                 // Can't function without a datatype.\r
271                 return null;\r
272             }\r
273 \r
274             Double itemSamplingInterval = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_SamplingInterval, Bindings.DOUBLE);\r
275             Double itemDeadband = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_Deadband, Bindings.DOUBLE);\r
276 \r
277             Double bias = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_Bias, Bindings.DOUBLE);\r
278             Double gain = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_Gain, Bindings.DOUBLE);\r
279             String unit = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_Unit, Bindings.STRING);\r
280 \r
281             double samplingInterval = itemSamplingInterval != null ? itemSamplingInterval : defaultSamplingInterval;\r
282             double deadband = itemDeadband != null ? itemDeadband : 0.0;\r
283 \r
284             SubscriptionItem item = new SubscriptionItem();\r
285 \r
286             // HACK: use id for storing the name of the item\r
287             // Assumption: subscription item's name is unique within the model\r
288             item.id = guid;\r
289 \r
290             item.variableId = variableId;\r
291             item.groupId = groupId;\r
292             item.groupItemId = variablePersistentId;\r
293             // HACK: use format for storing the data type of the item\r
294             item.format = type;\r
295             // HACK: use formatId for storing the unit of the item,\r
296             // empty unit is interpreted to mean "no unit" because\r
297             // formatId cannot be null.\r
298             item.formatId = unit == null ? "" : unit;\r
299 \r
300             // Subscription parameters\r
301             item.deadband = deadband;\r
302             item.interval = samplingInterval;\r
303             if (bias != null) item.bias = bias;\r
304             if (gain != null) item.gain = gain;\r
305 \r
306             if (DEBUG)\r
307                 //System.out.println("DEBUG: ItemRequest(" + parameter + ", " + parameter2.getURI(graph) + ", " + parameter3 + ")\n\t= " + item);\r
308                 System.out.println("DEBUG: ItemRequest(" + parameter + ", " + parameter2 + ", " + parameter3 + ")\n\t= " + item);\r
309 \r
310             return item;\r
311         }\r
312 \r
313     }\r
314 \r
315 }