--- /dev/null
+package org.simantics.db.layer0.variable;\r
+\r
+import java.util.Map;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.adapter.AdaptException;\r
+import org.simantics.databoard.adapter.Adapter;\r
+import org.simantics.databoard.adapter.AdapterConstructionException;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.type.Datatype;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.EnumerationMap;\r
+import org.simantics.db.common.request.IsEnumeratedValue;\r
+import org.simantics.db.common.utils.CommonDBUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.RuntimeDatabaseException;\r
+import org.simantics.db.layer0.util.Layer0Utils;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.scl.runtime.function.Function4;\r
+import org.simantics.scl.runtime.function.FunctionImpl4;\r
+\r
+public class VariableUtils {\r
+\r
+ final private static Binding datatype_binding = Bindings.getBindingUnchecked(Datatype.class);\r
+ \r
+ public static Function4<WriteGraph, Variable, Object, Object, String> defaultInputModifier = new FunctionImpl4<WriteGraph, Variable, Object, Object, String>() {\r
+\r
+ public String apply(WriteGraph graph, Variable variable, Object value, Object _binding) {\r
+ try {\r
+ return safeApply(graph, variable, value, _binding);\r
+ } catch (DatabaseException e) {\r
+ throw new RuntimeDatabaseException(e);\r
+ }\r
+ }\r
+\r
+ public String safeApply(WriteGraph graph, Variable variable, Object value, Object _binding) throws DatabaseException {\r
+\r
+ Binding binding = (Binding)_binding;\r
+ \r
+ Variable parent = variable.getParent(graph);\r
+ Resource property = variable.getPossiblePredicateResource(graph);\r
+ Resource container = parent.getPossibleRepresents(graph);\r
+ if(container == null) return null;\r
+ if(property == null) return null;\r
+\r
+ CommonDBUtils.selectClusterSet(graph, container);\r
+\r
+ Statement object = graph.getPossibleStatement(container, property);\r
+ if(object == null) return null;\r
+\r
+ Resource objectResource = object.getObject();\r
+ if(graph.sync(new IsEnumeratedValue(objectResource))) {\r
+\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ Resource type = graph.getSingleObject(objectResource, L0.PartOf);\r
+ \r
+ Map<String, Resource> enumMap = graph.syncRequest(new EnumerationMap(type));\r
+ Resource newLiteral = enumMap.get(value);\r
+ graph.deny(container, property, objectResource);\r
+ graph.claim(container, property, newLiteral);\r
+ \r
+ return null;\r
+ \r
+ }\r
+\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ Statement dt = graph.getPossibleStatement(objectResource, L0.HasDataType);\r
+ if (dt == null) {\r
+ throw new DatabaseException("Can't write variable " + variable.getURI(graph) + " since its literal resource " + objectResource + " does not contain a datatype statement"); \r
+ }\r
+\r
+ boolean needsCustomDatatype = !dt.isAsserted(objectResource);\r
+ Datatype correctDatatype = graph.getValue(dt.getObject(), datatype_binding);\r
+ Binding correctBinding = Bindings.getBinding(correctDatatype);\r
+\r
+ try {\r
+ Adapter adapter = Bindings.getTypeAdapter(binding, correctBinding);\r
+ Object correctValue = adapter.adapt(value);\r
+ if (correctValue == value) {\r
+ // Adapter is passthrough, i.e. the specified binding can be\r
+ // considered correct for the value.\r
+ correctBinding = binding;\r
+ }\r
+ value = correctValue;\r
+ } catch (AdapterConstructionException e) {\r
+ throw new DatabaseException("Can't adapt values from source datatype '" + binding.type().toSingleLineString() + "' to target '" + correctDatatype.toSingleLineString() + "'");\r
+ } catch (AdaptException e) {\r
+ throw new DatabaseException("Can't adapt value " + value + " from source datatype '" + binding.type().toSingleLineString() + "' to target '" + correctDatatype.toSingleLineString() + "'");\r
+ }\r
+\r
+ if (object.isAsserted(container)) {\r
+ String sclType = needsCustomDatatype ? Layer0Utils.getSCLType(correctDatatype) : null;\r
+\r
+ Resource type = graph.getPossibleType(objectResource, L0.Literal);\r
+ objectResource = graph.newResource();\r
+ graph.claim(objectResource, L0.InstanceOf, null, type);\r
+ graph.claim(container, property, objectResource);\r
+ if(needsCustomDatatype) {\r
+ graph.addLiteral(objectResource, L0.HasDataType, L0.HasDataType_Inverse, L0.DataType, correctDatatype, datatype_binding);\r
+ graph.addLiteral(objectResource, L0.HasValueType, L0.HasValueType_Inverse, L0.String, sclType, Bindings.STRING);\r
+ }\r
+ }\r
+ \r
+ graph.claimValue(objectResource, value, correctBinding);\r
+ return null;\r
+ \r
+ }\r
+ \r
+ };\r
+ \r
+}\r