1 /*******************************************************************************
\r
2 * Copyright (c) 2011 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.modeling.subscription;
\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
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
46 import gnu.trove.map.hash.THashMap;
\r
49 * @author Tuukka Lehtonen
\r
51 public class CollectSubscriptions extends ResourceRead<SubscriptionCollectionResult> {
\r
53 private static final boolean PERF = false;
\r
54 private static final boolean DEBUG = false;
\r
56 protected Resource experiment;
\r
57 protected double defaultSamplingInterval;
\r
58 protected boolean synchronous;
\r
60 public CollectSubscriptions(IDynamicExperiment experiment, double defaultSamplingInterval) {
\r
61 this(experiment.getModel(), experiment.getResource(), defaultSamplingInterval, false);
\r
64 public CollectSubscriptions(IDynamicExperiment experiment, double defaultSamplingInterval, boolean synchronous) {
\r
65 this(experiment.getModel(), experiment.getResource(), defaultSamplingInterval, synchronous);
\r
68 public CollectSubscriptions(Resource model, Resource experiment, double defaultSamplingInterval) {
\r
69 this(model, experiment, defaultSamplingInterval, false);
\r
72 public CollectSubscriptions(Resource model, Resource experiment, double defaultSamplingInterval, boolean synchronous) {
\r
74 this.experiment = experiment;
\r
75 this.defaultSamplingInterval = defaultSamplingInterval;
\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
83 Map<String, SubscriptionItem> items = gatherSubscriptions(graph, resource, status, new TreeMap<String, SubscriptionItem>());
\r
84 return new SubscriptionCollectionResult(new ArrayList<>(items.values()), status);
\r
86 graph.setSynchronous(oldSync);
\r
91 * Scans thru a model and writes up all the variables that are to be monitored.
\r
95 * Spreadsheets (not in cur. impl)
\r
96 * Monitors on diagram (not in cur. impl)
\r
101 * @param variablesToMonitor
\r
102 * @throws DatabaseException
\r
104 public Map<String, SubscriptionItem> gatherSubscriptions(ReadGraph graph, Resource model, MultiStatus status,
\r
105 Map<String, SubscriptionItem> items) throws DatabaseException {
\r
107 System.out.println("DEBUG: CollectAprosSubscriptions.gatherSubscriptions");
\r
108 long start = System.nanoTime();
\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
115 Variable experimentVariable = null;
\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
122 experimentVariable = Variables.switchRealization(graph, configuration, run);
\r
123 } catch (DatabaseException e) {
\r
124 experimentVariable = Variables.switchPossibleContext(graph, configuration, run);
\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
139 System.out.println("DEBUG: CollectAprosSubscriptions.gatherSubscriptions ENDS, took " + ((System.nanoTime() - start)*1e-6) + " ms with " + items.size() + " items");
\r
144 static class Param extends Tuple3 {
\r
145 public Param(Variable configurationContext, Variable experimentContext, Double defaultSamplingInterval) {
\r
146 super(configurationContext, experimentContext, defaultSamplingInterval);
\r
150 static class SubscriptionRequest extends BinaryRead<Resource, Param, Map<String, SubscriptionItem>> {
\r
152 public SubscriptionRequest(Resource subscription, Param constants) {
\r
153 super(subscription, constants);
\r
157 public Map<String, SubscriptionItem> perform(ReadGraph graph) throws DatabaseException {
\r
159 System.out.println("DEBUG: CollectSubscriptions.SubscriptionRequest(" + NameUtils.getSafeName(graph, parameter, true) + ")");
\r
160 long start = System.nanoTime();
\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
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
172 Map<String, SubscriptionItem> items = graph.syncRequest(
\r
173 new SubscriptionItemsRequest(parameter, groupId, parameter2),
\r
174 TransientCacheAsyncListener.<Map<String, SubscriptionItem>>instance());
\r
176 System.out.println("DEBUG: CollectSubscriptions.SubscriptionRequest(" + NameUtils.getSafeName(graph, parameter, true) + ") DONE in " + ((System.nanoTime() - start)*1e-6) + " ms");
\r
183 static class SubscriptionItemsRequest extends TernaryRead<Resource, String, Param, Map<String, SubscriptionItem>> {
\r
185 public SubscriptionItemsRequest(Resource subscription, String groupId, Param constants) {
\r
186 super(subscription, groupId, constants);
\r
190 public Map<String, SubscriptionItem> perform(ReadGraph graph) throws DatabaseException {
\r
192 System.out.println("DEBUG: CollectSubscriptions.SubscriptionItemsRequest(" + NameUtils.getSafeName(graph, parameter, true) + ")");
\r
193 long start = System.nanoTime();
\r
195 Layer0 L0 = Layer0.getInstance(graph);
\r
196 ModelingResources MOD = ModelingResources.getInstance(graph);
\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
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
208 result.put(hi.id, hi);
\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
219 static class ItemRequest extends TernaryRead<Resource, String, Param, SubscriptionItem> {
\r
221 public ItemRequest(Resource item, String groupId, Param constants) {
\r
222 super(item, groupId, constants);
\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
235 Binding rviBinding = graph.getService(Databoard.class).getBindingUnchecked( RVI.class );
\r
236 RVI rvi = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_VariableId, rviBinding);
\r
238 //status.add(new Status(IStatus.WARNING, ModelHistoryCollector.BUNDLE_ID, "Subscription Item '" + NameUtils.getSafeName(graph, subscriptionItem) + "' is missing RVI property"));
\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
248 String variablePersistentId = rvi.toString();
\r
249 Pair<Variable, Variable> variable = Variables.resolvePossible(graph, rvi, configurationContext, experimentContext);
\r
250 if (variable == null) {
\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
258 String variableId = rvi.asPossibleString(graph, variable.second);
\r
259 //System.out.println("DEBUG: " + variablePersistentId + " - " + variableId);
\r
260 if (variableId == null) {
\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
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
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
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
281 double samplingInterval = itemSamplingInterval != null ? itemSamplingInterval : defaultSamplingInterval;
\r
282 double deadband = itemDeadband != null ? itemDeadband : 0.0;
\r
284 SubscriptionItem item = new SubscriptionItem();
\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
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
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
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