X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.modeling%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Fsubscription%2FCollectSubscriptions.java;fp=bundles%2Forg.simantics.modeling%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Fsubscription%2FCollectSubscriptions.java;h=169c246cfda5c15cecccca7e35d3f21f58e25dfa;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/subscription/CollectSubscriptions.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/subscription/CollectSubscriptions.java new file mode 100644 index 000000000..169c246cf --- /dev/null +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/subscription/CollectSubscriptions.java @@ -0,0 +1,315 @@ +/******************************************************************************* + * Copyright (c) 2011 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.subscription; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; + +import org.eclipse.core.runtime.MultiStatus; +import org.simantics.databoard.Bindings; +import org.simantics.databoard.Databoard; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.type.Datatype; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; +import org.simantics.db.common.procedure.adapter.TransientCacheListener; +import org.simantics.db.common.request.BinaryRead; +import org.simantics.db.common.request.ObjectsWithType; +import org.simantics.db.common.request.ResourceRead; +import org.simantics.db.common.request.TernaryRead; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.RVI; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.layer0.variable.Variables; +import org.simantics.history.util.subscription.SubscriptionItem; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ModelingResources; +import org.simantics.scl.runtime.tuple.Tuple3; +import org.simantics.simulation.experiment.IDynamicExperiment; +import org.simantics.simulation.ontology.SimulationResource; +import org.simantics.utils.datastructures.Pair; + +import gnu.trove.map.hash.THashMap; + +/** + * @author Tuukka Lehtonen + */ +public class CollectSubscriptions extends ResourceRead { + + private static final boolean PERF = false; + private static final boolean DEBUG = false; + + protected Resource experiment; + protected double defaultSamplingInterval; + protected boolean synchronous; + + public CollectSubscriptions(IDynamicExperiment experiment, double defaultSamplingInterval) { + this(experiment.getModel(), experiment.getResource(), defaultSamplingInterval, false); + } + + public CollectSubscriptions(IDynamicExperiment experiment, double defaultSamplingInterval, boolean synchronous) { + this(experiment.getModel(), experiment.getResource(), defaultSamplingInterval, synchronous); + } + + public CollectSubscriptions(Resource model, Resource experiment, double defaultSamplingInterval) { + this(model, experiment, defaultSamplingInterval, false); + } + + public CollectSubscriptions(Resource model, Resource experiment, double defaultSamplingInterval, boolean synchronous) { + super(model); + this.experiment = experiment; + this.defaultSamplingInterval = defaultSamplingInterval; + } + + @Override + public SubscriptionCollectionResult perform(ReadGraph graph) throws DatabaseException { + MultiStatus status = new MultiStatus(ModelHistoryCollector.BUNDLE_ID, 0, "History collection subscription resolution problems:", null); + boolean oldSync = graph.setSynchronous(synchronous); + try { + Map items = gatherSubscriptions(graph, resource, status, new TreeMap()); + return new SubscriptionCollectionResult(new ArrayList<>(items.values()), status); + } finally { + graph.setSynchronous(oldSync); + } + } + + /** + * Scans thru a model and writes up all the variables that are to be monitored. + * This includes: + * Subscriptions + * Charts + * Spreadsheets (not in cur. impl) + * Monitors on diagram (not in cur. impl) + * + * @param graph + * @param model + * @param status + * @param variablesToMonitor + * @throws DatabaseException + */ + public Map gatherSubscriptions(ReadGraph graph, Resource model, MultiStatus status, + Map items) throws DatabaseException { + if (PERF) + System.out.println("DEBUG: CollectAprosSubscriptions.gatherSubscriptions"); + long start = System.nanoTime(); + + // Get active experiment context if possible to be able + // to resolve the whole model, not just the configuration. + Variable configuration = Variables.getPossibleConfigurationContext(graph, model); + if (configuration == null) + return items; + Variable experimentVariable = null; + + SimulationResource SIMU = SimulationResource.getInstance(graph); + Layer0 L0 = Layer0.getInstance(graph); + for (Resource run : graph.syncRequest(new ObjectsWithType(experiment, L0.ConsistsOf, SIMU.Run))) { + if (graph.hasStatement(run, SIMU.IsActive)) { + try { + experimentVariable = Variables.switchRealization(graph, configuration, run); + } catch (DatabaseException e) { + experimentVariable = Variables.switchPossibleContext(graph, configuration, run); + } + } + } + + ModelingResources MOD = ModelingResources.getInstance(graph); + Param constants = new Param(configuration, experimentVariable, defaultSamplingInterval); + for (Resource subscription : graph.syncRequest(new ObjectsWithType(model, L0.ConsistsOf, MOD.Subscription))) { + Map subscriptionItems = graph.syncRequest( + new SubscriptionRequest(subscription, constants), + TransientCacheAsyncListener.>instance()); + items.putAll(subscriptionItems); + } + + if (PERF) + System.out.println("DEBUG: CollectAprosSubscriptions.gatherSubscriptions ENDS, took " + ((System.nanoTime() - start)*1e-6) + " ms with " + items.size() + " items"); + + return items; + } + + static class Param extends Tuple3 { + public Param(Variable configurationContext, Variable experimentContext, Double defaultSamplingInterval) { + super(configurationContext, experimentContext, defaultSamplingInterval); + } + } + + static class SubscriptionRequest extends BinaryRead> { + + public SubscriptionRequest(Resource subscription, Param constants) { + super(subscription, constants); + } + + @Override + public Map perform(ReadGraph graph) throws DatabaseException { + if (PERF) + System.out.println("DEBUG: CollectSubscriptions.SubscriptionRequest(" + NameUtils.getSafeName(graph, parameter, true) + ")"); + long start = System.nanoTime(); + + ModelingResources MOD = ModelingResources.getInstance(graph); + Boolean v = graph.getPossibleRelatedValue(parameter, MOD.Subscription_Enabled, Bindings.BOOLEAN); + if (!Boolean.TRUE.equals(v)) + return Collections.emptyMap(); + + Layer0 L0 = Layer0.getInstance(graph); + String groupId = graph.getPossibleRelatedValue(parameter, L0.HasName, Bindings.STRING); + if (groupId == null) + return Collections.emptyMap(); + + Map items = graph.syncRequest( + new SubscriptionItemsRequest(parameter, groupId, parameter2), + TransientCacheAsyncListener.>instance()); + if (PERF) + System.out.println("DEBUG: CollectSubscriptions.SubscriptionRequest(" + NameUtils.getSafeName(graph, parameter, true) + ") DONE in " + ((System.nanoTime() - start)*1e-6) + " ms"); + + return items; + } + + } + + static class SubscriptionItemsRequest extends TernaryRead> { + + public SubscriptionItemsRequest(Resource subscription, String groupId, Param constants) { + super(subscription, groupId, constants); + } + + @Override + public Map perform(ReadGraph graph) throws DatabaseException { + if (PERF) + System.out.println("DEBUG: CollectSubscriptions.SubscriptionItemsRequest(" + NameUtils.getSafeName(graph, parameter, true) + ")"); + long start = System.nanoTime(); + + Layer0 L0 = Layer0.getInstance(graph); + ModelingResources MOD = ModelingResources.getInstance(graph); + + Collection subscriptionItems = graph.syncRequest(new ObjectsWithType(parameter, L0.ConsistsOf, MOD.Subscription_Item)); + if (subscriptionItems.isEmpty()) + return Collections.emptyMap(); + + Map result = new THashMap<>(subscriptionItems.size()); + for (Resource subscriptionItem : subscriptionItems) { + SubscriptionItem hi = graph.syncRequest( + new ItemRequest(subscriptionItem, parameter2, parameter3), + TransientCacheListener.instance()); + if (hi != null) + result.put(hi.id, hi); + } + + if (PERF) + System.out.println("DEBUG: CollectSubscriptions.SubscriptionItemsRequest(" + NameUtils.getSafeName(graph, parameter, true) + ") DONE in " + ((System.nanoTime() - start)*1e-6) + " ms with " + result.size() + " items"); + + return result; + } + + } + + static class ItemRequest extends TernaryRead { + + public ItemRequest(Resource item, String groupId, Param constants) { + super(item, groupId, constants); + } + + @Override + public SubscriptionItem perform(ReadGraph graph) throws DatabaseException { + ModelingResources MOD = ModelingResources.getInstance(graph); + Resource subscriptionItem = parameter; + String groupId = parameter2; + Param constants = parameter3; + Variable configurationContext = (Variable) constants.c0; + Variable experimentContext = (Variable) constants.c1; + double defaultSamplingInterval = (double) constants.c2; + + Binding rviBinding = graph.getService(Databoard.class).getBindingUnchecked( RVI.class ); + RVI rvi = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_VariableId, rviBinding); + if (rvi == null) { + //status.add(new Status(IStatus.WARNING, ModelHistoryCollector.BUNDLE_ID, "Subscription Item '" + NameUtils.getSafeName(graph, subscriptionItem) + "' is missing RVI property")); + return null; + } + + Layer0 L0 = Layer0.getInstance(graph); + String guid = graph.getPossibleRelatedValue(subscriptionItem, L0.HasName); + if (guid == null) { + //status.add(new Status(IStatus.WARNING, ModelHistoryCollector.BUNDLE_ID, "Subscription Item '" + NameUtils.getSafeName(graph, subscriptionItem) + "' has no name (ID).")); + return null; + } + String variablePersistentId = rvi.toString(); + Pair variable = Variables.resolvePossible(graph, rvi, configurationContext, experimentContext); + if (variable == null) { + if (DEBUG) + System.out.println("DEBUG: unresolvable subscription: " + variablePersistentId); + // Don't log these, these problems are conveyed to the + // user through model browser UI labels. + //status.add(new Status(IStatus.WARNING, ModelHistoryCollector.BUNDLE_ID, "Subscription Item '" + NameUtils.getSafeName(graph, subscriptionItem) + "' variable cannot be resolved from RVI " + rvi.toString(graph))); + return null; + } + String variableId = rvi.asPossibleString(graph, variable.second); + //System.out.println("DEBUG: " + variablePersistentId + " - " + variableId); + if (variableId == null) { + return null; + } + + Datatype type = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_Datatype, Bindings.getBindingUnchecked(Datatype.class)); + if (type == null && variable != null) { + type = variable.first.getPossibleDatatype(graph); + } + if (type == null) { + //status.add(new Status(IStatus.WARNING, ModelHistoryCollector.BUNDLE_ID, "Subscription Item '" + NameUtils.getSafeName(graph, subscriptionItem) + "' is missing data type")); + // Can't function without a datatype. + return null; + } + + Double itemSamplingInterval = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_SamplingInterval, Bindings.DOUBLE); + Double itemDeadband = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_Deadband, Bindings.DOUBLE); + + Double bias = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_Bias, Bindings.DOUBLE); + Double gain = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_Gain, Bindings.DOUBLE); + String unit = graph.getPossibleRelatedValue(subscriptionItem, MOD.Subscription_Item_Unit, Bindings.STRING); + + double samplingInterval = itemSamplingInterval != null ? itemSamplingInterval : defaultSamplingInterval; + double deadband = itemDeadband != null ? itemDeadband : 0.0; + + SubscriptionItem item = new SubscriptionItem(); + + // HACK: use id for storing the name of the item + // Assumption: subscription item's name is unique within the model + item.id = guid; + + item.variableId = variableId; + item.groupId = groupId; + item.groupItemId = variablePersistentId; + // HACK: use format for storing the data type of the item + item.format = type; + // HACK: use formatId for storing the unit of the item, + // empty unit is interpreted to mean "no unit" because + // formatId cannot be null. + item.formatId = unit == null ? "" : unit; + + // Subscription parameters + item.deadband = deadband; + item.interval = samplingInterval; + if (bias != null) item.bias = bias; + if (gain != null) item.gain = gain; + + if (DEBUG) + //System.out.println("DEBUG: ItemRequest(" + parameter + ", " + parameter2.getURI(graph) + ", " + parameter3 + ")\n\t= " + item); + System.out.println("DEBUG: ItemRequest(" + parameter + ", " + parameter2 + ", " + parameter3 + ")\n\t= " + item); + + return item; + } + + } + +} \ No newline at end of file