X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.db.layer0%2Fsrc%2Forg%2Fsimantics%2Fdb%2Flayer0%2Fvariable%2FVariables.java;fp=bundles%2Forg.simantics.db.layer0%2Fsrc%2Forg%2Fsimantics%2Fdb%2Flayer0%2Fvariable%2FVariables.java;h=81e1e46e94a3d027faed3853938a739e8d78d05e;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/Variables.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/Variables.java new file mode 100644 index 000000000..81e1e46e9 --- /dev/null +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/Variables.java @@ -0,0 +1,807 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 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.db.layer0.variable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.mutable.Variant; +import org.simantics.databoard.type.Datatype; +import org.simantics.databoard.type.NumberType; +import org.simantics.databoard.util.URIStringUtils; +import org.simantics.db.ReadGraph; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.common.request.TernaryRead; +import org.simantics.db.common.utils.Logger; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.exception.MissingVariableException; +import org.simantics.db.layer0.request.Model; +import org.simantics.db.layer0.request.PossibleActiveVariableFromVariable; +import org.simantics.db.layer0.request.PossibleModel; +import org.simantics.db.layer0.request.PossibleVariableIndexRoot; +import org.simantics.db.layer0.request.PossibleVariableModel; +import org.simantics.db.layer0.request.PropertyInfo; +import org.simantics.db.layer0.request.PropertyInfoRequest; +import org.simantics.db.layer0.request.ResourceURIToVariable; +import org.simantics.db.layer0.request.VariableIndexRoot; +import org.simantics.db.layer0.request.VariableURI; +import org.simantics.layer0.Layer0; +import org.simantics.operation.Layer0X; +import org.simantics.project.ontology.ProjectResource; +import org.simantics.scl.runtime.function.Function1; +import org.simantics.scl.runtime.function.Function2; +import org.simantics.scl.runtime.function.Function3; +import org.simantics.simulation.ontology.SimulationResource; +import org.simantics.simulator.variable.exceptions.NodeManagerException; +import org.simantics.utils.datastructures.Pair; + +import gnu.trove.map.hash.TObjectIntHashMap; + +final public class Variables { + + public static final Variant PENDING_NODE_VALUE = new Variant(); + + public static final NodeStructure PENDING_NODE_STRUCTURE = new NodeStructure(Collections.emptyMap(), Collections.emptyMap()) { + public boolean equals(Object object) { + return this == object; + } + }; + + public static enum Role { + + CHILD("/"), PROPERTY("#"); + + transient final String identifier; + + private Role(String identifier) { + this.identifier = identifier; + } + + final public String getIdentifier() { + return identifier; + } + + public static Role getRole( String identifier ) { + for (Role role : Role.values()) if (role.identifier.equals( identifier )) return role; + return null; + } + + } + + // use getPredicate + //final public static String PREDICATE = "PREDICATE"; + + @Deprecated + // use getName + final public static String NAME = "HasName"; + final public static String CLASSIFICATIONS = "classifications"; + final public static String EXPRESSION = "HasExpression"; + final public static String INPUT_VALIDATOR = "HasInputValidator"; + final public static String INPUT_MODIFIER = "HasInputModifier"; + final public static String FORMATTER = "HasFormatter"; + + final public static String STANDARD_RESOURCE = "hasStandardResource"; + //@Deprecated + // use getPresents + //final public static String REPRESENTS = "Represents"; + final public static String TYPE = "Type"; + final public static String URI = "URI"; + /** + * @deprecated use {@link Variable#getRVI(ReadGraph)} and {@link RVI} instead. + */ +// @Deprecated +// final public static String SERIALISED = "Serialised"; +// @Deprecated + // use getParent + //final public static String PARENT = "Parent"; + //final public static String ROLE = "Role"; + //final public static String DATATYPE = "DATATYPE"; + //final public static String UNIT = "UNIT"; + + final public static String VALID = "valid"; + final public static String REQUIRED = "required"; + final public static String DEFAULT = "default"; + final public static String READONLY = "readOnly"; + final public static String VALIDATOR = "validator"; + + final public static String LABEL = "HasLabel"; + + final public static String ENUMERATION_VALUES = "HasEnumerationValues"; + final public static String CUSTOM_MODIFIER = "HasCustomModifier"; + + final public static String DISPLAY_COLUMN = "HasDisplayColumn"; + + final public static String DISPLAY_PROPERTY = "HasDisplayProperty"; + final public static String DISPLAY_VALUE = "HasDisplayValue"; + final public static String DISPLAY_UNIT = "HasDisplayUnit"; + + final public static String CONVERTED_VALUE = "convertedValue"; + + /** + * This property should exist for array valued property variables. + */ + final public static String ARRAY_SIZE = "ARRAY_SIZE"; + + + @Deprecated + // use etc. variable.adapt(graph, Interface.class).getResource() + final public static String RESOURCE = "Resource"; + @Deprecated + final public static String CONTAINER_RESOURCE = "ContainerResource"; + @Deprecated + final public static String PROPERTY_RESOURCE = "PROPERTY_RESOURCE"; + + @Deprecated + public final static String[] builtins = { + TYPE, RESOURCE, URI + //, SERIALISED + }; + + public static Variable getPossibleVariable(ReadGraph graph, Resource resource) throws DatabaseException { + String uri = graph.getPossibleURI(resource); + return uri != null ? getPossibleVariable(graph, uri) : null; + } + + public static Variable getPossibleVariable(ReadGraph graph, String uri) throws DatabaseException { + try { + return getVariable(graph, uri); + } catch (DatabaseException e) { + return null; + } + } + + public static Variable getVariable(ReadGraph graph, Resource resource) throws DatabaseException { + return getVariable(graph, graph.getURI(resource)); + } + + public static Variable getVariable(ReadGraph graph, String uri) throws DatabaseException { + try { + return graph.sync(new ResourceURIToVariable(uri)); + } catch (MissingVariableException e) { + return VariableRepository.get(graph, uri); + } + } + + private static int commonPrefixLength(String a, String b) { + int maxC = Math.min(a.length(), b.length()); + for(int c=0;c 0 && !isSplitPos(baseURI, prefixLength);--prefixLength); + } + if(prefixLength == baseURI.length()) + return otherURI.substring(prefixLength); + else + return prefixByParentPath( + pathLength(baseURI.substring(prefixLength)), + otherURI.substring(prefixLength)); + } + + public static String getRVI2(ReadGraph graph, Variable base, Variable other) throws DatabaseException { + TObjectIntHashMap baseLength = new TObjectIntHashMap(); + for(int depth=0;base != null;base = base.getParent(graph),++depth) + baseLength.put(base, depth); + Variable cur; + for(cur=other;!baseLength.containsKey(cur);cur=cur.getParent(graph)); + + // To string + String curURI = cur.getURI(graph); + String otherURI = other.getURI(graph); + + return prefixByParentPath(baseLength.get(cur), otherURI.substring(curURI.length())); + } + + public static String getProjectRVI(ReadGraph graph, Variable variable) throws DatabaseException { + Resource project = getProject(graph, variable); + String projectURI = graph.getURI(project); + return variable.getURI(graph).substring(projectURI.length()); + } + + private static int getSegmentEnd(String suffix) { + int pos; + for(pos=1;pos getPath(ReadGraph graph, Variable base, Variable var) throws DatabaseException { + if(!isChild(graph, base, var)) return null; + LinkedList result = new LinkedList(); + var = var.getParent(graph); + while(!var.equals(base)) { + result.addFirst(var); + var = var.getParent(graph); + } + return result; + } + + public static Variable getChild(ReadGraph graph, Variable base, Variable var) throws DatabaseException { + List path = getPath(graph, base, var); + if(path == null || path.size() == 0) return null; + return path.get(0); + } + + public static boolean isChild(ReadGraph graph, Variable base, Variable var) throws DatabaseException { + if(base.equals(var)) return false; + return var.getURI(graph).startsWith(base.getURI(graph)); + } + + public static Variable switchRealization(ReadGraph graph, Variable variable, Resource realization) throws DatabaseException { + Resource current = getRealization(graph, variable); + if(current == null) throw new DatabaseException("No current realization found for variable"); + return switchRealization(graph, variable, current, realization); + } + + public static Variable switchPossibleContext(ReadGraph graph, Variable variable, Resource realization) throws DatabaseException { + Variable current = getPossibleContext(graph, variable); + if (current == null) + return null; + Resource currentContext = current.getPossibleRepresents(graph); + if (currentContext == null) + return null; + return switchPossibleRealization(graph, variable, currentContext, realization); + } + + public static Variable switchRealization(ReadGraph graph, Variable variable, Variable realization) throws DatabaseException { + Resource current = getRealization(graph, variable); + return switchRealization(graph, variable, current, realization); + } + + public static Variable switchRealization(ReadGraph graph, Variable variable, Resource currentRealization, Resource targetRealization) throws DatabaseException { + String currentURI = graph.getURI(currentRealization); + String targetURI = graph.getURI(targetRealization); + String variableURI = variable.getURI(graph); + String targetVariableURI = targetURI + variableURI.substring(currentURI.length()); + return getVariable(graph, targetVariableURI); + } + + public static Variable switchRealization(ReadGraph graph, Variable variable, Resource currentRealization, Variable targetRealization) throws DatabaseException { + String currentURI = graph.getURI(currentRealization); + String targetURI = targetRealization.getURI(graph); + String variableURI = variable.getURI(graph); + String targetVariableURI = targetURI + variableURI.substring(currentURI.length()); + return getVariable(graph, targetVariableURI); + } + + public static Variable switchPossibleRealization(ReadGraph graph, Variable variable, Resource currentRealization, Resource targetRealization) throws DatabaseException { + String currentURI = graph.getURI(currentRealization); + String targetURI = graph.getURI(targetRealization); + String variableURI = variable.getURI(graph); + String targetVariableURI = targetURI + variableURI.substring(currentURI.length()); + return getPossibleVariable(graph, targetVariableURI); + } + + public static Variable toConfigurationVariable(ReadGraph graph, Variable variable) throws DatabaseException { + Variable config = getConfigurationContext(graph, variable); + return switchRealization(graph, variable, config); + } + + public static Variable toPossibleConfigurationVariable(ReadGraph graph, Variable variable) throws DatabaseException { + + Resource represents = variable.getPossibleRepresents(graph); + if(represents == null) return null; + Resource config = getPossibleConfigurationContextResource(graph, represents); + if(config == null) return null; + return switchPossibleContext(graph, variable, config); + + } + + public static String toRVI(ReadGraph graph, List compositePath) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + StringBuilder rvi = new StringBuilder(); + for (Resource composite : compositePath) { + String name = graph.getPossibleRelatedValue(composite, L0.HasName); + if (name == null) + return null; + + rvi.append('/'); + String escapedName = URIStringUtils.escape(name); + rvi.append(escapedName); + } + return rvi.toString(); + } + + public static String appendRVI(ReadGraph graph, String modelURI, String rvi, Resource configuration) throws DatabaseException { + + Layer0 L0 = Layer0.getInstance(graph); + String partName = graph.getPossibleRelatedValue(configuration, L0.HasName); + if(partName == null) throw new MissingVariableException("Can not append a child corresponding to " + configuration + " to rvi '" + rvi + "' since there is no name."); + String escaped = URIStringUtils.escape(partName); + return rvi + "/" + escaped; + + } + + public static boolean isValid(ReadGraph graph, Variable variable) { + if(variable == null) return false; + try { + variable.getURI(graph); + } catch (DatabaseException e) { + return false; + } + return true; + } + + public static Variable possibleChildWithType(ReadGraph graph, Variable variable, Resource targetType) throws DatabaseException { + Variable found = null; + for(Variable child : variable.getChildren(graph)) { + Resource type = child.getPossiblePropertyValue(graph, Variables.TYPE); + if(type != null && graph.isInheritedFrom(type, targetType)) { + if(found != null) return null; + found = child; + } + } + return found; + } + + public static Collection childrenWithType(ReadGraph graph, Variable variable, Resource targetType) throws DatabaseException { + ArrayList result = new ArrayList(); + for(Variable child : variable.getChildren(graph)) { + Resource type = child.getPossiblePropertyValue(graph, Variables.TYPE); + if(graph.isInheritedFrom(type, targetType)) result.add(child); + } + return result; + } + + public static T adapt(ReadGraph graph, Variable variable, String property, Class clazz) throws DatabaseException { + Resource resource = variable.getPropertyValue(graph, property); + return graph.adapt(resource, clazz); + } + + public static T getPossiblePropertyValue(RequestProcessor processor, Variable variable, Resource property, Binding binding) { + try { + return processor.sync(new TernaryRead(variable, property, binding) { + + @Override + public T perform(ReadGraph graph) throws DatabaseException { + return parameter.getPossiblePropertyValue(graph, parameter2, parameter3); + } + + }); + } catch (DatabaseException e) { + return null; + } + } + + public static Variable possibleActiveVariable(ReadGraph graph, Variable variable) throws DatabaseException { + Variable activeVariable = graph.sync(new PossibleActiveVariableFromVariable(variable)); + return activeVariable; + } + + public static Variant requestNodeValue(ReadGraph graph, VariableNode node) throws DatabaseException { + return requestNodeValue(graph, node, null); + } + + public static Variant requestNodeValue(ReadGraph graph, VariableNode node, final Binding binding) throws DatabaseException { + Variant value = graph.syncRequest(new NodeValueRequest(node, binding)); + if(PENDING_NODE_VALUE == value && graph.getSynchronous()) { + // In this case a PENDING value was previously cached but now the value needs to be obtained for real. + + ValueGetter getter = new ValueGetter(node, binding); + try { + node.support.manager.getRealm().syncExec(getter); + } catch (InterruptedException e) { + Logger.defaultLogError(e); + } + + if (getter.exception != null) + throw new DatabaseException(getter.exception); + + return getter.result; + } + return value; + } + + public static class NodeStructure { + // Immutable but wrapped with Collections.unmodifiableMap as an optimization + public final Map children; + // Immutable but not wrapped with Collections.unmodifiableMap as an optimization + public final Map properties; + private final int hash; + + public NodeStructure(Map children, Map properties) { + this.children = children; + this.properties = properties; + this.hash = calcHash(); + } + + private int calcHash() { + return 31*children.hashCode() + 41*properties.hashCode(); + } + + @Override + public int hashCode() { + return hash; + } + + @Override + public boolean equals(Object object) { + if (this == object) + return true; + else if (object == null || object == Variables.PENDING_NODE_STRUCTURE) + return false; + else if (!(object instanceof NodeStructure)) + return false; + NodeStructure r = (NodeStructure)object; + return r.children.equals(children) && r.properties.equals(properties); + } + } + + public static NodeStructure requestNodeStructure(ReadGraph graph, VariableNode node) throws DatabaseException { + NodeStructure value = graph.syncRequest(new NodeStructureRequest(node)); + if (value == null) throw new DatabaseException("External data access error"); + if(PENDING_NODE_STRUCTURE == value && graph.getSynchronous()) { + // In this case a PENDING value was previously cached but now the value needs to be obtained for real. + + StructureGetter getter = new StructureGetter(node); + try { + node.support.manager.getRealm().syncExec(getter); + } catch (InterruptedException e) { + Logger.defaultLogError(e); + throw new DatabaseException("External data access error", e); + } + + if (getter.exception != null) + throw new DatabaseException("External data access error", getter.exception); + if (getter.result == null) + throw new DatabaseException("External data access error"); + + return getter.result; + + } + return value; + + } + + public static String getPossibleUnit(ReadGraph graph, Variable variable) throws DatabaseException { + + try { + + Resource predicate = variable.getPossiblePredicateResource(graph); + if(predicate != null) { + PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate)); + if(info.definedUnit != null) return info.definedUnit; + } + + Variant variant = variable.getVariantValue(graph); + Binding binding = variant.getBinding(); + if(binding == null) return null; + Datatype dt = binding.type(); + if(!(dt instanceof NumberType)) return null; + NumberType nt = (NumberType)dt; + return nt.getUnit(); + + } catch (DatabaseException e) { + return null; + } + + } + + /** + * @param graph + * @param rvi + * @param context1 primary context to use for resolving the specified RVI, must not be null + * @param context2 secondary context to use for resolving the specified RVI, may be null + * @return pair of variables where first is the resolved variable and second + * is the context it was resolved with + * @throws DatabaseException + * @since 1.18.1 + */ + public static Pair resolvePossible(ReadGraph graph, RVI rvi, Variable context1, Variable context2) throws DatabaseException { + Variable v = rvi.resolvePossible(graph, context1); + if (v != null) + return new Pair<>(v, context1); + if (context2 != null) { + v = rvi.resolvePossible(graph, context2); + if (v != null) + return new Pair<>(v, context2); + } + return null; + } + + + @SuppressWarnings("rawtypes") + private static class ValueGetter implements VariableNodeReadRunnable { + + final VariableNode n; + final Binding binding; + Variant result; + Exception exception; + + public ValueGetter(VariableNode n, Binding binding) { + this.n = n; + this.binding = binding; + } + + @SuppressWarnings("unchecked") + @Override + public void run() { + try { + if (binding != null) + result = new Variant(binding, n.support.manager.getValue(n.node, binding)); + else + result = n.support.manager.getValue(n.node); + } catch (Exception e) { + Logger.defaultLogError(e); + exception = e; + } + } + + } + + @SuppressWarnings("rawtypes") + private static class StructureGetter implements VariableNodeReadRunnable { + + final VariableNode n; + NodeStructure result; + Exception exception; + + public StructureGetter(VariableNode n) { + this.n = n; + } + + @Override + public void run() { + try { + result = NodeStructureRequest.get(n); + } catch (NodeManagerException e) { + Logger.defaultLogError(e); + exception = e; + } + } + + }; + + public static Variable tryGetProperty(ReadGraph graph, Resource entity, Resource property) throws DatabaseException { + Variable v = Variables.getPossibleVariable(graph, entity); + return v != null ? v.getPossibleProperty(graph, property) : null; + } + + public static ValueAccessor createValueAccessor(Function1 getValue1, Function2 getValue2, + Function2 setValue2, Function3 setValue3, + Function1 getDatatype) { + return new SCLValueAccessor(getValue1, getValue2, setValue2, setValue3, getDatatype); + } + + +}