/******************************************************************************* * Copyright (c) 2012 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.util; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.SubMonitor; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.adapter.Adapter; import org.simantics.databoard.adapter.AdapterConstructionException; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.NumberBinding; import org.simantics.databoard.binding.StringBinding; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.mutable.MutableStringBinding; import org.simantics.databoard.parser.repository.DataTypeSyntaxError; import org.simantics.databoard.parser.repository.DataValueRepository; import org.simantics.databoard.primitives.MutableString; import org.simantics.databoard.type.ArrayType; import org.simantics.databoard.type.BooleanType; import org.simantics.databoard.type.ByteType; import org.simantics.databoard.type.Datatype; import org.simantics.databoard.type.DoubleType; import org.simantics.databoard.type.FloatType; import org.simantics.databoard.type.IntegerType; import org.simantics.databoard.type.LongType; import org.simantics.databoard.type.MapType; import org.simantics.databoard.type.NumberType; import org.simantics.databoard.type.OptionalType; import org.simantics.databoard.type.RecordType; import org.simantics.databoard.type.StringType; import org.simantics.databoard.type.UnionType; import org.simantics.databoard.type.VariantType; import org.simantics.databoard.util.ObjectUtils; import org.simantics.db.ChangeSetIdentifier; import org.simantics.db.Operation; import org.simantics.db.ReadGraph; import org.simantics.db.RelationContext; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.WriteOnlyGraph; import org.simantics.db.common.CommentMetadata; import org.simantics.db.common.Indexing; import org.simantics.db.common.StandardStatement; import org.simantics.db.common.primitiverequest.PossibleRelatedValue; import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; import org.simantics.db.common.request.DelayedWriteRequest; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.PossibleChild; import org.simantics.db.common.request.PossibleIndexRoot; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.CancelTransactionException; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ServiceException; import org.simantics.db.layer0.adapter.CopyHandler; import org.simantics.db.layer0.adapter.CopyHandler2; import org.simantics.db.layer0.adapter.GenericRelationIndex; import org.simantics.db.layer0.adapter.PasteHandler; import org.simantics.db.layer0.adapter.impl.DefaultPasteHandler; import org.simantics.db.layer0.adapter.impl.TGRemover; import org.simantics.db.layer0.genericrelation.IndexedRelations; import org.simantics.db.layer0.internal.SimanticsInternal; import org.simantics.db.layer0.migration.OntologiesFromLibrary; import org.simantics.db.layer0.property.OrderedResource; import org.simantics.db.layer0.request.GlobalOntologies; import org.simantics.db.layer0.request.PossibleVariableIndexRoot; import org.simantics.db.layer0.request.PropertyInfo; import org.simantics.db.layer0.request.PropertyInfoRequest; import org.simantics.db.layer0.util.SimanticsClipboard.Representation; import org.simantics.db.layer0.variable.StandardGraphPropertyVariable; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.service.ClusterCollectorPolicy; import org.simantics.db.service.ClusterControl; import org.simantics.db.service.ClusteringSupport; import org.simantics.db.service.CollectionSupport; import org.simantics.db.service.DebugSupport; import org.simantics.db.service.ManagementSupport; import org.simantics.db.service.UndoRedoSupport; import org.simantics.db.service.XSupport; import org.simantics.graph.db.TransferableGraphSource; import org.simantics.graph.db.TransferableGraphs; import org.simantics.graph.diff.Diff; import org.simantics.graph.diff.TransferableGraphDelta1; import org.simantics.graph.refactoring.GraphRefactoringUtils; import org.simantics.graph.representation.TransferableGraph1; import org.simantics.layer0.Layer0; import org.simantics.operation.Layer0X; import org.simantics.scl.compiler.environment.Environments; import org.simantics.scl.compiler.runtime.RuntimeEnvironment; import org.simantics.scl.compiler.top.SCLExpressionCompilationException; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.osgi.SCLOsgi; import org.simantics.scl.runtime.function.Function; import org.simantics.scl.runtime.function.Function1; import org.simantics.scl.runtime.function.FunctionImpl1; public class Layer0Utils { @SuppressWarnings("rawtypes") public static final ThreadLocal SCL_GRAPH = new ThreadLocal(); final public static Binding datatype_binging = Bindings.getBindingUnchecked(Datatype.class); public static Resource literal(WriteGraph g, String value) throws DatabaseException { Layer0 L0 = Layer0.getInstance(g); Resource r = g.newResource(); g.claimValue(r, value, Bindings.STRING); g.claim(r, L0.InstanceOf, L0.String); return r; } public static Resource literal(WriteGraph g, double value) throws DatabaseException { Layer0 L0 = Layer0.getInstance(g); Resource r = g.newResource(); g.claimValue(r, value, Bindings.DOUBLE); g.claim(r, L0.InstanceOf, L0.Double); return r; } public static Resource literal(WriteGraph g, int value) throws DatabaseException { Layer0 L0 = Layer0.getInstance(g); Resource r = g.newResource(); g.claimValue(r, value, Bindings.INTEGER); g.claim(r, L0.InstanceOf, L0.Integer); return r; } public static void assert_(WriteGraph g, Resource type, Resource predicate, Resource object) throws DatabaseException { Layer0 L0 = Layer0.getInstance(g); Resource assertion = g.newResource(); g.claim(type, L0.Asserts, assertion); g.claim(assertion, L0.InstanceOf, L0.Assertion); g.claim(assertion, L0.HasPredicate, predicate); g.claim(assertion, L0.HasObject, object); } public static Resource relation(WriteGraph g, Resource parent, String name, Resource superrelation) throws DatabaseException { Layer0 L0 = Layer0.getInstance(g); Resource relation = g.newResource(); g.claim(relation, L0.SubrelationOf, superrelation); g.claim(relation, L0.HasName, literal(g, name)); g.claim(parent, L0.ConsistsOf, relation); Resource superrelationInverse = g.getInverse(superrelation); if(superrelationInverse != null) { Resource inverse = g.newResource(); g.claim(inverse, L0.SubrelationOf, superrelationInverse); g.claim(relation, L0.ConsistsOf, inverse); g.claim(inverse, L0.HasName, literal(g, "Inverse")); } return relation; } private static Resource getLiteralType(ReadGraph graph, Datatype type) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); if(type instanceof DoubleType) return L0.Double; else if(type instanceof StringType) return L0.String; else if(type instanceof IntegerType) return L0.Integer; else if(type instanceof LongType) return L0.Long; else if(type instanceof FloatType) return L0.Float; else if(type instanceof ByteType) return L0.Byte; else if(type instanceof BooleanType) return L0.Boolean; else if(type instanceof ArrayType) { ArrayType at = (ArrayType)type; if(at.componentType instanceof DoubleType) return L0.DoubleArray; else if(at.componentType instanceof StringType) return L0.StringArray; else if(at.componentType instanceof IntegerType) return L0.IntegerArray; else if(at.componentType instanceof LongType) return L0.LongArray; else if(at.componentType instanceof FloatType) return L0.FloatArray; else if(at.componentType instanceof ByteType) return L0.ByteArray; else if(at.componentType instanceof BooleanType) return L0.BooleanArray; else if(at.componentType instanceof VariantType) return L0.VariantArray; } throw new DatabaseException("Unidentified literal type for datatype " + type); } private static Resource getPossibleLiteralType(ReadGraph graph, String type) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); if("Double".equals(type)) return L0.Double; else if("String".equals(type)) return L0.String; else if("Integer".equals(type)) return L0.Integer; else if("Long".equals(type)) return L0.Long; else if("Float".equals(type)) return L0.Float; else if("Byte".equals(type)) return L0.Byte; else if("Boolean".equals(type)) return L0.Boolean; else if("[Double]".equals(type)) return L0.DoubleArray; else if("[String]".equals(type)) return L0.StringArray; else if("[Integer]".equals(type)) return L0.IntegerArray; else if("[Long]".equals(type)) return L0.LongArray; else if("[Float]".equals(type)) return L0.FloatArray; else if("[Byte]".equals(type)) return L0.ByteArray; else if("[Boolean]".equals(type)) return L0.BooleanArray; else if("[Variant]".equals(type)) return L0.VariantArray; else if("Array Double".equals(type)) return L0.DoubleArray; else if("Array String".equals(type)) return L0.StringArray; else if("Array Integer".equals(type)) return L0.IntegerArray; else if("Array Long".equals(type)) return L0.LongArray; else if("Array Float".equals(type)) return L0.FloatArray; else if("Array Byte".equals(type)) return L0.ByteArray; else if("Array Boolean".equals(type)) return L0.BooleanArray; else if("Array Variant".equals(type)) return L0.VariantArray; else if("Vector Double".equals(type)) return L0.DoubleArray; else if("Vector String".equals(type)) return L0.StringArray; else if("Vector Integer".equals(type)) return L0.IntegerArray; else if("Vector Long".equals(type)) return L0.LongArray; else if("Vector Float".equals(type)) return L0.FloatArray; else if("Vector Byte".equals(type)) return L0.ByteArray; else if("Vector Boolean".equals(type)) return L0.BooleanArray; else if("Vector Variant".equals(type)) return L0.VariantArray; else if("Datatype".equals(type)) return L0.DataType; else if("Variant".equals(type)) return L0.Variant; else return null; } public static Resource getPossibleLiteralType(ReadGraph graph, Variable variable) throws DatabaseException { Resource predicate = variable.getPossiblePredicateResource(graph); if(predicate == null) return null; return getPossibleLiteralType(graph, predicate); } public static Resource getLiteralType(ReadGraph graph, Variable variable) throws DatabaseException { Resource result = getPossibleLiteralType(graph, variable); if(result == null) throw new DatabaseException("Unidentified literal type for variable " + variable.getURI(graph)); return result; } public static Resource getLiteralType(ReadGraph graph, Resource property) throws DatabaseException { Resource result = getPossibleLiteralType(graph, property); if(result == null) throw new DatabaseException("Unidentified literal type for property " + graph.getURI(property)); return result; } public static Resource getPossibleLiteralType(ReadGraph graph, Resource property) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Layer0X L0X = Layer0X.getInstance(graph); Resource defaultLiteralType = graph.getPossibleObject(property, L0.HasDefaultLiteralType); if(defaultLiteralType != null) return defaultLiteralType; Resource range = graph.getPossibleObject(property, L0.HasRange); if(range != null && !L0.Value.equals(range)) return range; Datatype requiredDataType = graph.getPossibleRelatedValue(property, L0X.RequiresDataType, datatype_binging); if(requiredDataType != null) return getLiteralType(graph, requiredDataType); String requiredValueType = graph.getPossibleRelatedValue(property, L0.RequiresValueType, Bindings.STRING); if(requiredValueType == null) return null; return getPossibleLiteralType(graph, requiredValueType); } /** * @param type any data type definition * @return SCL type that matches the specified data type on a basic level. * Data type metadata is/cannot be converted into SCL types. * @throws IllegalArgumentException * if the input datatype can't be converted into an SCL type */ public static String getSCLType(Datatype type) throws IllegalArgumentException { return buildSCLType(type, null).toString(); } /** * Only used internally by {@link #buildSCLType(Datatype, StringBuilder)} * @param s * @param toBuilder * @return * @see #buildSCLType(Datatype, StringBuilder) */ private static StringBuilder append(StringBuilder toBuilder, String s) { return toBuilder != null ? toBuilder.append(s) : new StringBuilder(s); } private static CharSequence append(CharSequence to, String s) { if (to instanceof StringBuilder) return ((StringBuilder) to).append(s); return new StringBuilder(to.length() + s.length()).append(to).append(s); } private static CharSequence stringOrBuilder(StringBuilder toBuilder, String s) { return toBuilder != null ? toBuilder.append(s) : s; } /** * @param type any data type definition * @return SCL type that matches the specified data type on a basic level. * Data type metadata is/cannot be converted into SCL types. * @throws IllegalArgumentException * if the input datatype can't be converted into an SCL type */ private static CharSequence buildSCLType(Datatype type, StringBuilder result) throws IllegalArgumentException { if(type instanceof DoubleType) return stringOrBuilder(result, "Double"); else if(type instanceof StringType) return stringOrBuilder(result, "String"); else if(type instanceof IntegerType) return stringOrBuilder(result, "Integer"); else if(type instanceof FloatType) return stringOrBuilder(result, "Float"); else if(type instanceof BooleanType) return stringOrBuilder(result, "Boolean"); else if(type instanceof ByteType) return stringOrBuilder(result, "Byte"); else if(type instanceof LongType) return stringOrBuilder(result, "Long"); else if(type instanceof VariantType) return stringOrBuilder(result, "Variant"); else if(type instanceof ArrayType) { ArrayType at = (ArrayType) type; // Optimization to prevent allocations in the most basic array cases if(at.componentType instanceof DoubleType) return stringOrBuilder(result, "Vector Double"); else if(at.componentType instanceof StringType) return stringOrBuilder(result, "Vector String"); else if(at.componentType instanceof IntegerType) return stringOrBuilder(result, "Vector Integer"); else if(at.componentType instanceof FloatType) return stringOrBuilder(result, "Vector Float"); else if(at.componentType instanceof BooleanType) return stringOrBuilder(result, "Vector Boolean"); else if(at.componentType instanceof ByteType) return stringOrBuilder(result, "Vector Byte"); else if(at.componentType instanceof LongType) return stringOrBuilder(result, "Vector Long"); else if(at.componentType instanceof VariantType) return stringOrBuilder(result, "Vector Variant"); else return buildSCLType(at.componentType, append(result, "Vector ")); } else if(type instanceof OptionalType) { OptionalType ot = (OptionalType) type; return append(buildSCLType(ot.componentType, append(result, "Maybe (")), ")"); } else if (type instanceof RecordType) { throw new IllegalArgumentException("Unable to convert datatype into SCL type: " + type); } else if (type instanceof MapType) { throw new IllegalArgumentException("Unable to convert datatype into SCL type: " + type); } else if (type instanceof UnionType) { throw new IllegalArgumentException("Unable to convert datatype into SCL type: " + type); } throw new IllegalArgumentException("Unable to convert datatype into SCL type: " + type); } public static Type getSCLType(ReadGraph graph, RuntimeEnvironment runtimeEnvironment, String typeText) throws DatabaseException { try { return Environments.getType(runtimeEnvironment.getEnvironment(), typeText); } catch (SCLExpressionCompilationException e) { throw new DatabaseException(e); } } public static Type getSCLType(ReadGraph graph, Variable property) throws DatabaseException { RuntimeEnvironment runtimeEnvironment = graph.syncRequest(new RuntimeEnvironmentRequest(property.getIndexRoot(graph))); return getSCLType(graph, runtimeEnvironment, getSCLTypeString(graph, property)); } public static String getSCLTypeString(ReadGraph graph, Variable context) throws DatabaseException { return getSCLTypeString(graph, context.getPossiblePredicateResource(graph), context.getRepresents(graph)); } public static String getSCLTypeString(ReadGraph graph, Resource predicate, Resource value) throws DatabaseException { if(predicate != null) { String requiredValueTypes = graph.getPossibleRelatedValue(predicate, Layer0.getInstance(graph).RequiresValueType, Bindings.STRING); if(requiredValueTypes != null) return requiredValueTypes; } Layer0 L0 = Layer0.getInstance(graph); Layer0X L0X = Layer0X.getInstance(graph); Datatype literalDatatype = graph.getPossibleRelatedValue(value, L0.HasDataType, datatype_binging); if(literalDatatype != null) return getSCLType(literalDatatype); String literalValueType = graph.getPossibleRelatedValue(value, L0.HasValueType, Bindings.STRING); if(literalValueType != null) return literalValueType; if(predicate != null) { Datatype requiredDataType = graph.getPossibleRelatedValue(predicate, L0X.RequiresDataType, datatype_binging); if(requiredDataType != null) return getSCLType(requiredDataType); throw new DatabaseException("Unidentified literal data type for property " + NameUtils.getURIOrSafeNameInternal(graph, predicate)); } throw new DatabaseException("Unidentified literal data type"); } public static Datatype getDatatype(ReadGraph graph, Variable variable) throws DatabaseException { Datatype result = getPossibleDatatype(graph, variable); if(result != null) return result; throw new DatabaseException("Unidentified literal data type for property " + variable.getURI(graph)); } public static Datatype getPossibleDatatype(ReadGraph graph, Variable variable) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Layer0X L0X = Layer0X.getInstance(graph); Resource property = variable.getPossiblePredicateResource(graph); if(property != null) { // Datatype requiredDataType = graph.getPossibleRelatedValue(property, L0X.RequiresDataType, datatype_binging); Datatype requiredDataType = graph.syncRequest(new PossibleRelatedValue(property, L0X.RequiresDataType, datatype_binging)); if(requiredDataType != null) return requiredDataType; } Resource literal = variable.getPossibleRepresents(graph); if(literal != null) { Datatype literalDatatype = graph.getPossibleRelatedValue2(literal, L0.HasDataType, new StandardGraphPropertyVariable(graph, variable, null, literal, L0.HasDataType), datatype_binging); if(literalDatatype != null) return literalDatatype; } if(property != null) { String requiredValueType = graph.getPossibleRelatedValue(property, L0.RequiresValueType, Bindings.STRING); if(requiredValueType != null) { Datatype datatype = getPossibleDatatypeForValueType(requiredValueType); if(datatype != null) return datatype; } Resource subject = variable.getParent(graph).getPossibleRepresents(graph); if(subject != null) { Set asses = new HashSet(); for(Resource type : graph.getTypes(subject)) { asses.addAll(graph.getAssertedObjects(type, property)); } if(asses.size() == 1) { Resource ass = asses.iterator().next(); Datatype dt = graph.getPossibleRelatedValue(ass, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class)); if(dt != null) return dt; } } } return null; } private static Datatype getPossibleDatatypeForValueType(String requiredValueType) throws DatabaseException { String[] split = requiredValueType.split(" "); String arrayType = null; if(split.length == 2 && "Array".equals(split[0])) { arrayType = split[1]; } else if(requiredValueType.startsWith("[") && requiredValueType.endsWith("]")) { arrayType = requiredValueType.substring(1, requiredValueType.length()-1); } if(arrayType != null) { Datatype arrayDataType = getArrayDataTypeForType(arrayType); if(arrayDataType != null) return arrayDataType; } Datatype dt = Datatypes.getDatatype(requiredValueType); if(dt != null) return dt; try { return Datatypes.translate(requiredValueType); } catch (DataTypeSyntaxError e) { return null; } } private static Datatype getArrayDataTypeForType(String type) { if("Double".equals(type)) return Datatypes.DOUBLE_ARRAY; else if("String".equals(type)) return Datatypes.STRING_ARRAY; else if("Integer".equals(type)) return Datatypes.INTEGER_ARRAY; else if("Long".equals(type)) return Datatypes.LONG_ARRAY; else if("Float".equals(type)) return Datatypes.FLOAT_ARRAY; else if("Byte".equals(type)) return Datatypes.BYTE_ARRAY; else if("Boolean".equals(type)) return Datatypes.BOOLEAN_ARRAY; else if("Variant".equals(type)) return Datatypes.VARIANT_ARRAY; return null; } public static Binding getDefaultBinding(ReadGraph graph, Variable variable) throws DatabaseException { Resource property = variable.getPossiblePredicateResource(graph); if(property != null) { PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(property), TransientCacheAsyncListener.instance()); if(info.defaultBinding != null) return info.defaultBinding; } Datatype type = getDatatype(graph, variable); if (type == null) throw new DatabaseException("No datatype available for variable " + variable.getURI(graph)); return Bindings.getBinding(type); } public static Binding getPossibleDefaultBinding(ReadGraph graph, Variable variable) throws DatabaseException { Resource property = variable.getPossiblePredicateResource(graph); if(property != null) { PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(property), TransientCacheAsyncListener.instance()); if(info.defaultBinding != null) return info.defaultBinding; } Datatype type = getPossibleDatatype(graph, variable); if (type == null) return null; return Bindings.getBinding(type); } public static String getPossibleUnit(Datatype dt) { if (dt == null) return null; else if (dt instanceof NumberType) { return ((NumberType) dt).getUnit(); } else if (dt instanceof ArrayType) { ArrayType at = (ArrayType) dt; Datatype cdt = at.componentType(); if (cdt instanceof NumberType) { return ((NumberType) cdt).getUnit(); } } return null; } public static String getUnit(ReadGraph graph, Variable variable) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Layer0X L0X = Layer0X.getInstance(graph); Resource literal = variable.getPossibleRepresents(graph); if(literal == null) return ""; Datatype literalDatatype = graph.getPossibleRelatedValue2(literal, L0.HasDataType, new StandardGraphPropertyVariable(graph, variable, null, literal, L0.HasDataType), datatype_binging); if(literalDatatype != null) { String unit = getPossibleUnit(literalDatatype); if(unit != null) return unit; } Resource property = variable.getPossiblePredicateResource(graph); if(property != null) { Datatype requiredDataType = graph.getPossibleRelatedValue(property, L0X.RequiresDataType, datatype_binging); if(requiredDataType != null) { String unit = getPossibleUnit(requiredDataType); if(unit != null) return unit; } } return ""; } public static void claimAdaptedValue(WriteGraph graph, Resource objectResource, Object value, Binding binding, Datatype datatype) throws DatabaseException { try { Datatype source = binding.type(); if(source.equals(datatype)) { graph.claimValue(objectResource, value, binding); } else { Binding target = Bindings.getBinding(datatype); Adapter adapter = Bindings.getAdapter(binding, target); graph.claimValue(objectResource, adapter.adapt(value), target); } } catch (AdapterConstructionException e) { throw new DatabaseException(e); } catch (AdaptException e) { throw new DatabaseException(e); } } public static String toString(Object value, Binding binding) throws DatabaseException { try { if(value instanceof String) return (String)value; StringBuilder sb = new StringBuilder(); DataValueRepository rep = new DataValueRepository(); binding.printValue(value, sb, rep, false); return sb.toString(); } catch (BindingException e) { throw new DatabaseException(e); } catch (IOException e) { throw new DatabaseException(e); } } public static Object parseValue(String text, Binding binding) throws DatabaseException { try { if(binding.isInstance(text)) return text; DataValueRepository rep = new DataValueRepository(); return binding.parseValue(text, rep); } catch (BindingException e) { throw new DatabaseException(e); } catch (DataTypeSyntaxError e) { throw new DatabaseException(e); } } @SuppressWarnings("unchecked") public static T getValueAdaptedToBinding(ReadGraph graph, Resource literal, Binding targetBinding) throws DatabaseException { Datatype sourceDatatype = graph.getDataType(literal); Datatype targetDatatype = targetBinding.type(); if (sourceDatatype.equals(targetDatatype)) return graph.getValue(literal, targetBinding); Binding sourceBinding = Bindings.getBinding(sourceDatatype); try { Adapter adapter = Bindings.adapterFactory.getAdapter(Bindings.getBinding(sourceDatatype), targetBinding, true, false); Object value = graph.getValue(literal, sourceBinding); return (T) adapter.adaptUnchecked(value); } catch (AdapterConstructionException e) { throw new DatabaseException(e); } } public static Statement getStatementInLocal(Resource subject, Statement statement) { if(statement.isAsserted(subject)) return new StandardStatement(subject, statement.getPredicate(), statement.getObject()); else return statement; } public static Resource browsePossible(ReadGraph graph, Resource root, String suffix) throws DatabaseException { return graph.getPossibleResource(graph.getURI(root) + suffix); } public static Resource getPossibleChild(ReadGraph graph, Resource resource, String name) throws DatabaseException { return graph.sync(new PossibleChild(resource, name)); } public static Resource getPossibleChild(ReadGraph graph, Resource resource, Resource type, String name) throws DatabaseException { Resource child = graph.sync(new PossibleChild(resource, name)); if(child == null) return null; if(!graph.isInstanceOf(child, type)) return null; return child; } public static RelationContext relationContext(ReadGraph graph, Resource subject, Resource predicate) throws DatabaseException { Statement stm = graph.getSingleStatement(subject, predicate); return new RelationContextImpl(subject, stm); } public static RelationContext relationContext(Statement stm) throws DatabaseException { return new RelationContextImpl(stm.getSubject(), stm); } public static T valueInRelationContext(ReadGraph graph, Resource subject, Statement stm) throws DatabaseException { return graph.getValue2(subject, Layer0Utils.relationContext(stm)); } public static T valueInRelationContext(ReadGraph graph, Resource subject, Statement stm, Binding binding) throws DatabaseException { return graph.getValue2(subject, Layer0Utils.relationContext(stm), binding); } public static T relatedValueInRelationContext(ReadGraph graph, Resource subject, Resource relation) throws DatabaseException { Statement stm = getStatementInLocal(subject, graph.getSingleStatement(subject, relation)); return valueInRelationContext(graph, stm.getObject(), stm); } public static T relatedValueInRelationContext(ReadGraph graph, Resource subject, Resource relation, Binding binding) throws DatabaseException { Statement stm = getStatementInLocal(subject, graph.getSingleStatement(subject, relation)); return valueInRelationContext(graph, stm.getObject(), stm, binding); } public static Statement possibleObtainedStatementInternal(ReadGraph graph, Resource subject, Resource relation) throws DatabaseException { Layer0X L0X = Layer0X.getInstance(graph); for(Resource ob : graph.getObjects(subject, L0X.DefinesObtainedStatement)) { Resource pred = graph.getSingleObject(ob, L0X.ObtainedStatement_predicate); if(graph.isSubrelationOf(pred, relation)) { Resource object = graph.getSingleObject(ob, L0X.ObtainedStatement_object); return new StandardStatement(subject, pred, object); } } ArrayList order = new ArrayList(); for(Statement stm : graph.getStatements(subject, L0X.ObtainsProperty)) { Integer position = graph.getRelatedValue(stm.getPredicate(), L0X.NaturalNumberOrderRelation, Bindings.INTEGER); order.add(new OrderedResource(position, stm.getObject())); } for(OrderedResource or : order) { Statement stm = possibleObtainedStatementInternal(graph, or.r, relation); if(stm != null) return stm; } return null; } public static T possibleObtainedValue(ReadGraph graph, RelationContext ctx, Binding binding) throws DatabaseException { Statement stm = ctx.getStatement(); Statement obj = Layer0Utils.possibleObtainedStatementInternal(graph, stm.getSubject(), stm.getPredicate()); if(obj != null) { return Layer0Utils.valueInRelationContext(graph, obj.getObject(), obj, binding); } else { return null; } } public static void addObtainedStatement(WriteGraph graph, Resource subject, Resource predicate, Resource object) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Layer0X L0X = Layer0X.getInstance(graph); Resource ob = graph.newResource(); graph.claim(ob, L0.InstanceOf, null, L0X.ObtainedStatement); graph.claim(ob, L0X.ObtainedStatement_predicate, null, predicate); graph.claim(ob, L0X.ObtainedStatement_object, null, object); graph.claim(subject, L0X.DefinesObtainedStatement, null, ob); } public static void addObtainedValue(WriteGraph graph, Resource subject, Resource predicate, Resource type, Object value, Binding binding) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Resource object = graph.newResource(); graph.claim(object, L0.InstanceOf, type); graph.claimValue(object, value, binding); Layer0Utils.addObtainedStatement(graph, subject, predicate, object); } //------------------------------------------------------------------------- // Indexing state query utilities idle handling utilities //------------------------------------------------------------------------- /** * This method waits until the indexing engine becomes idle. * @since 1.8 */ public static void waitIndexPending() { Indexing.waitIndexPending(); } /** * @param graph an active database write handle to prove one is in a write * transaction and wants to disable dependencies indexing for this * transaction only. * @return previous value * @since 1.8 */ public static boolean setDependenciesIndexingDisabled(WriteOnlyGraph graph, boolean disabled) { return Indexing.setDependenciesIndexingDisabled(graph, disabled); } public static String undo() throws DatabaseException { Session session = SimanticsInternal.getSession(); UndoRedoSupport support = session.getService(UndoRedoSupport.class); List ops = support.undoAndReturnOperations(session, 1); if(ops.isEmpty()) return "Undo history is empty."; Operation mainOperation = ops.get(0); long csId = mainOperation.getCSId(); ManagementSupport management = session.getService(ManagementSupport.class); Collection ids = management.getChangeSetIdentifiers(csId, csId); return "Undo reverted " + ids.size() + " change sets."; } public static String undoOperations(int amountOfOperations) throws DatabaseException { Session session = SimanticsInternal.getSession(); UndoRedoSupport support = session.getService(UndoRedoSupport.class); List ops = support.undoAndReturnOperations(session, amountOfOperations); if(ops.isEmpty()) return "Undo history is empty."; Operation mainOperation = ops.get(0); long csId = mainOperation.getCSId(); ManagementSupport management = session.getService(ManagementSupport.class); Collection ids = management.getChangeSetIdentifiers(csId, csId); return "Undo reverted " + ids.size() + " change sets."; } public static String redo() throws DatabaseException { Session session = SimanticsInternal.getSession(); UndoRedoSupport support = session.getService(UndoRedoSupport.class); List ops = support.redo(session, 1); if(ops.isEmpty()) return "Redo history is empty."; Operation mainOperation = ops.get(0); long csId = mainOperation.getCSId(); ManagementSupport management = session.getService(ManagementSupport.class); Collection ids = management.getChangeSetIdentifiers(csId, csId); return "Redo redid " + ids.size() + " change sets."; } public static String getComment(Session session, ChangeSetIdentifier id) { byte[] data = id.getMetadata().get(CommentMetadata.class.getName()); if(data == null) return "Undescribed operation."; String comment = CommentMetadata.deserialise(session, data).toString().trim(); if(comment.isEmpty()) return "Undescribed operation."; return comment; } /** * This method adds CommentMetadata for write transaction. CommentMetadata is used e.g. in Undo view. * @param graph * graph handle * @param string * comment * @throws ServiceException */ public static void addCommentMetadata(WriteOnlyGraph graph, String string) throws ServiceException { // Add a comment to metadata. CommentMetadata cm = graph.getMetadata(CommentMetadata.class); graph.addMetadata(cm.add(ObjectUtils.toString(string))); } //------------------------------------------------------------------------- /** * Copy the specified source resource into the specified container using the * specified write transaction handle. * * @param graph write transaction handle * @param targetContainer target container resource of the created copy. The * exact logic of how the copy will be contained by the target * container is up to the PasteHandler to decide * @param source the source resource to copy * @throws DatabaseException * @since 1.8 */ public static Collection copyTo(WriteGraph graph, Resource targetContainer, Resource source) throws DatabaseException { return copyTo(graph, targetContainer, source, null, null, null); } public static Collection copyTo(WriteGraph graph, Resource targetContainer, Resource source, PasteEventHandler handler) throws DatabaseException { return copyTo(graph, targetContainer, source, handler, null, null); } public static Collection copyTo(WriteGraph graph, Resource targetContainer, Resource source, PasteEventHandler handler, CopyHandler copyHandler, PasteHandler pasteHandler) throws DatabaseException { if(copyHandler == null) copyHandler = graph.adapt(source, CopyHandler.class); return copyTo(graph, targetContainer, handler, copyHandler, pasteHandler); } public static Collection copyTo(WriteGraph graph, Resource targetContainer, PasteEventHandler handler, CopyHandler copyHandler, PasteHandler pasteHandler) throws DatabaseException { SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl(); copyHandler.copyToClipboard(graph, clipboard); if(targetContainer != null) { if(pasteHandler == null) pasteHandler = graph.adapt(targetContainer, PasteHandler.class); return pasteHandler.pasteFromClipboard(graph, clipboard, handler); } else { DefaultPasteHandler ph = new DefaultPasteHandler(null); return ph.pasteFromClipboard(graph, clipboard, handler); } } public static CopyHandler2 getPossibleCopyHandler(ReadGraph graph, Collection rs) throws DatabaseException { CopyHandler2 ch = null; for(Resource r : rs) { if(ch == null) { CopyHandler ch2_ = graph.adapt(r, CopyHandler.class); if(ch2_ instanceof CopyHandler2) { ch = (CopyHandler2)ch2_; } } else { CopyHandler ch2_ = graph.adapt(r, CopyHandler.class); if(ch2_ instanceof CopyHandler2) { CopyHandler2 ch2 = (CopyHandler2)ch2_; ch = ch.combine(ch2); } } } return ch; } public static ClusterCollectorPolicy setClusterCollectorPolicy(ClusterCollectorPolicy policy) { Session session = SimanticsInternal.getSession(); ClusterControl cc = session.getService(ClusterControl.class); return cc.setPolicy(policy); } private static String decodeType(ReadGraph graph, Variable variable) throws DatabaseException { Datatype dt = getDatatype(graph, variable); return dt.toSingleLineString(); } private static boolean isAsserted(ReadGraph graph, Resource subject, Resource predicate) throws DatabaseException { Statement stm = graph.getPossibleStatement(subject, predicate); return stm != null && stm.isAsserted(subject); } public static void setExpression(WriteGraph graph, Variable context, String text, Resource expressionValueType) throws DatabaseException { Resource value = context.getRepresents(graph); Resource predicateResource = context.getPredicateResource(graph); Variable parent = context.getParent(graph); Resource parentResource = parent.getRepresents(graph); setExpression(graph, parentResource, predicateResource, value, text, expressionValueType); } public static void setExpression(WriteGraph graph, Resource parentResource, Resource predicateResource, Resource value, String text, Resource expressionValueType) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); boolean hasExpression = graph.isInstanceOf(value, expressionValueType); String t = getSCLTypeString(graph, predicateResource, value); String expression = text.substring(1).trim(); if(isAsserted(graph, parentResource, predicateResource)) { Resource newValue = graph.newResource(); graph.claim(newValue, L0.InstanceOf, expressionValueType); graph.claimLiteral(newValue, L0.HasValueType, t, Bindings.STRING); graph.claimLiteral(newValue, L0.SCLValue_expression, expression, Bindings.STRING); graph.claim(parentResource, predicateResource, newValue); } else { if(hasExpression) { graph.claimLiteral(value, L0.SCLValue_expression, expression, Bindings.STRING); } else { Resource newValue = graph.newResource(); graph.claim(newValue, L0.InstanceOf, expressionValueType); graph.claimLiteral(newValue, L0.HasValueType, t, Bindings.STRING); graph.claimLiteral(newValue, L0.SCLValue_expression, expression, Bindings.STRING); graph.deny(parentResource, predicateResource); graph.claim(parentResource, predicateResource, newValue); } } } public static void clearExpression(WriteGraph graph, Variable property, Resource expressionValueType) throws DatabaseException { Resource object = property.getPossibleRepresents(graph); if(object != null) { boolean hasExpression = graph.isInstanceOf(object, expressionValueType); if(hasExpression) { // There was an expression and now we go back to a value Resource subject = property.getParent(graph).getPossibleRepresents(graph); if(subject != null) { Resource predicate = property.getPossiblePredicateResource(graph); if(predicate != null) { graph.deny(subject, predicate, object); RemoverUtil.remove(graph, object); } } } } } public static boolean setOrClearExpression(WriteGraph graph, Variable property, String text, Resource expressionValueType) throws DatabaseException { if(text.startsWith("=")) { setExpression(graph, property, text, expressionValueType); return true; } clearExpression(graph, property, expressionValueType); return false; } public static void setValueAsString(WriteGraph graph, Variable property, String text, Resource expressionValueType) throws DatabaseException { try { if (setOrClearExpression(graph, property, text, expressionValueType)) return; Object value = text; Datatype type = property.getPossibleDatatype(graph); if (type != null) { Binding binding = Bindings.getBinding(type); if (binding instanceof StringBinding) { if (binding instanceof MutableStringBinding) value = new MutableString(text); else value = text; } else { if (binding instanceof NumberBinding) { text = text.replace(",", "."); } value = binding.parseValue(text, new DataValueRepository()); } property.setValue(graph, value, binding); } else { property.setValue(graph, value); } // Add a comment to metadata. CommentMetadata cm = graph.getMetadata(CommentMetadata.class); graph.addMetadata(cm.add("Set value " + ObjectUtils.toString(value))); } catch (DataTypeSyntaxError e) { throw new DatabaseException(e); } catch (BindingException e) { throw new DatabaseException(e); } } public static String queryDebugSupport(String query) { Session session = SimanticsInternal.getSession(); DebugSupport ds = session.getService(DebugSupport.class); return ds.query(session, "exec " + query); } public static String queryListSupport (String query) { Session session = SimanticsInternal.getSession(); DebugSupport ds = session.getService(DebugSupport.class); return ds.query(session, "list " + query); } final public static Function1 resourceCluster = new FunctionImpl1() { @Override public Resource apply(Resource p0) { return p0; } }; public static void sort(ReadGraph graph, List collection) { CollectionSupport cos = graph.getService(CollectionSupport.class); cos.sort(collection); } public static List sortByCluster(ReadGraph graph, Collection collection) { CollectionSupport cos = graph.getService(CollectionSupport.class); return cos.asSortedList(collection); } public static List sortByCluster(final ReadGraph graph, List list, final Function1 fn) { final ClusteringSupport cs = graph.getService(ClusteringSupport.class); ArrayList result = new ArrayList(list); Collections.sort(result, new Comparator() { @Override public int compare(Object o1, Object o2) { Resource r1 = fn.apply(o1); Resource r2 = fn.apply(o2); long l1 = cs.getCluster(r1); long l2 = cs.getCluster(r2); if(l1 < l2) return -1; else if (l1 > l2) return 1; else return 0; } }); return result; } public static List sortByClusterT(final ReadGraph graph, Collection list, final Function1 fn) { final ClusteringSupport cs = graph.getService(ClusteringSupport.class); ArrayList result = new ArrayList(list); Collections.sort(result, new Comparator() { @Override public int compare(Object o1, Object o2) { Resource r1 = fn.apply((T)o1); Resource r2 = fn.apply((T)o2); long l1 = cs.getCluster(r1); long l2 = cs.getCluster(r2); if(l1 < l2) return -1; else if (l1 > l2) return 1; else return 0; } }); return result; } public static void makeSynchronous(ReadGraph graph, boolean value) throws DatabaseException { graph.setSynchronous(value); } public static Set listIndexRoots(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Set indexRoots = new TreeSet(); indexRoots.addAll(Layer0Utils.listOntologies(graph)); indexRoots.addAll(graph.syncRequest(new ObjectsWithType(SimanticsInternal.getProject(), L0.ConsistsOf, L0.IndexRoot))); return indexRoots; } public static List listOntologies(ReadGraph graph) throws DatabaseException { return graph.syncRequest(new OntologiesFromLibrary(graph.getRootLibrary())); } public static List listGlobalOntologies(ReadGraph graph) throws DatabaseException { return graph.syncRequest(new GlobalOntologies(graph.getRootLibrary())); } public static T applySCL(String module, String function, ReadGraph graph, Object ... args) throws DatabaseException { try { SCL_GRAPH.set(graph); T t = (T)((Function)SCLOsgi.MODULE_REPOSITORY.getValue(module + "/" + function)).applyArray(args); SCL_GRAPH.set(null); return t; } catch (Throwable t) { throw new DatabaseException(t); } } public static boolean isContainerPublished(ReadGraph graph, Variable variable) throws DatabaseException { Resource indexRoot = graph.syncRequest(new PossibleVariableIndexRoot(variable)); if(indexRoot == null) return false; if(variable.equals(indexRoot)) return false; return isPublished(graph, indexRoot); } public static boolean isContainerPublished(ReadGraph graph, Resource resource) throws DatabaseException { Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(resource)); if(indexRoot == null) return false; if(resource.equals(indexRoot)) return false; return isPublished(graph, indexRoot); } public static boolean isPublished(ReadGraph graph, Resource resource) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Boolean value = graph.getPossibleRelatedValue(resource, L0.Entity_published, Bindings.BOOLEAN); if(value != null && value) return true; // This is safety - root should not be published it child is not Resource root = graph.syncRequest(new PossibleIndexRoot(resource)); if(root != null) { value = graph.getPossibleRelatedValue(root, L0.Entity_published, Bindings.BOOLEAN); if(value != null && value) return true; } return false; } private static TransferableGraph1 makeTG(ReadGraph graph, Resource r) throws DatabaseException { SimanticsClipboardImpl cp = new SimanticsClipboardImpl(); CopyHandler c1 = graph.adapt(r, CopyHandler.class); c1.copyToClipboard(graph, cp); Collection> reps = cp.getContents(); if(reps.size() != 1) return null; return ClipboardUtils.accept(graph, reps.iterator().next(), SimanticsKeys.KEY_TRANSFERABLE_GRAPH); } private static TransferableGraphSource makeTGSource(ReadGraph graph, Resource r) throws DatabaseException { SimanticsClipboardImpl cp = new SimanticsClipboardImpl(); CopyHandler c1 = graph.adapt(r, CopyHandler.class); c1.copyToClipboard(graph, cp); Collection> reps = cp.getContents(); if(reps.size() != 1) return null; return ClipboardUtils.accept(graph, reps.iterator().next(), SimanticsKeys.KEY_TRANSFERABLE_GRAPH_SOURCE); } /* * Modifies target to resemble source. */ public static boolean merge(WriteGraph graph, Resource source, Resource target) throws DatabaseException { TransferableGraphSource tgs1 = makeTGSource(graph, target); TransferableGraph1 tg1 = TransferableGraphs.create(graph, tgs1); TransferableGraph1 tg2 = makeTG(graph, source); GraphRefactoringUtils.fixIncorrectRoot(tg1.identities); GraphRefactoringUtils.fixIncorrectRoot(tg2.identities); ModelTransferableGraphSource mtgs = (ModelTransferableGraphSource)tgs1; Diff diff = new Diff(tg1, tg2); TransferableGraphDelta1 delta = diff.diff(); long[] oldResources = mtgs.getResourceArray(graph); if(TransferableGraphs.hasChanges(graph, oldResources, delta)) { TransferableGraphs.applyDelta(graph, mtgs.getResourceArray(graph), delta); return true; } else { return false; } } public static Resource inferLiteralTypeFromString(ReadGraph graph, String text) { return Layer0.getInstance(graph).String; } public static void emptyTrashBin() throws ServiceException { emptyTrashBin(new NullProgressMonitor()); } public static void emptyTrashBin(IProgressMonitor monitor) throws ServiceException { emptyTrashBin(monitor, SimanticsInternal.getSession(), SimanticsInternal.getProject()); } public static void emptyTrashBin(final IProgressMonitor monitor, Session session, final Resource project) throws ServiceException { final SubMonitor mon = SubMonitor.convert(monitor, "Emptying Trash Bin...", 10000); try { session.syncRequest(new DelayedWriteRequest() { @Override public void perform(WriteGraph graph) throws DatabaseException { Layer0Utils.setDependenciesIndexingDisabled(graph, true); Layer0 L0 = Layer0.getInstance(graph); Layer0X L0X = Layer0X.getInstance(graph); Resource parent = graph.getSingleObject(project, L0.PartOf); Resource trashBin = Layer0Utils.getPossibleChild(graph, parent, "TrashBin"); Collection trashes = trashBin != null ? graph.getObjects(trashBin, L0.ConsistsOf) : Collections.emptyList(); if (trashes.isEmpty()) throw new CancelTransactionException(); mon.setWorkRemaining((2 + trashes.size()) * 1000); for(Resource trash : trashes) { if (mon.isCanceled()) throw new CancelTransactionException(); mon.subTask(NameUtils.getSafeName(graph, trash)); TGRemover remo = new TGRemover(mon.newChild(1000, SubMonitor.SUPPRESS_ALL_LABELS), trash); remo.remove(graph); if(graph.isInstanceOf(trash, L0.IndexRoot)) { // TODO: this should be an utility GenericRelationIndex index = graph.adapt(L0X.DependenciesRelation, GenericRelationIndex.class); IndexedRelations ir = graph.getService(IndexedRelations.class); // Deletes index files ir.reset(null, graph, L0X.DependenciesRelation, trash); // Notifies DB listeners index.reset(graph, trash); } } if (mon.isCanceled()) throw new CancelTransactionException(); mon.subTask("Committing Changes"); mon.newChild(1000); } }); if (mon.isCanceled()) return; mon.subTask("Purging Database"); mon.newChild(1000); purgeDatabase(monitor, session); } catch (CancelTransactionException e) { // Ignore. } catch (DatabaseException e) { throw new ServiceException(e); } } public static void purgeDatabase() throws ServiceException { purgeDatabase(new NullProgressMonitor()); } public static void purgeDatabase(final IProgressMonitor monitor) throws ServiceException { purgeDatabase(monitor, SimanticsInternal.getSession()); } public static void purgeDatabase(final IProgressMonitor monitor, Session session) throws ServiceException { try { XSupport xs = session.getService(XSupport.class); xs.purge(); } catch (DatabaseException e) { throw new ServiceException(e); } } public static Resource getSingleDomainOf(ReadGraph graph, Resource type, Resource target) throws DatabaseException { Resource result = null; for(Resource candidate : getDomainOf(graph, type).values()) { if(graph.isInstanceOf(candidate, target)) { if(result != null) throw new DatabaseException("Multiple relations found for target " + graph.getURI(target) + " in type " + graph.getURI(type)); else result = candidate; } } if(result == null) throw new DatabaseException("Multiple relations found for target " + graph.getURI(target) + " in type " + graph.getURI(type)); return result; } public static Map getDomainOf(ReadGraph graph, Resource type) throws DatabaseException { CollectionSupport cs = graph.getService(CollectionSupport.class); Map result = cs.createObjectResourceMap(String.class); Layer0 L0 = Layer0.getInstance(graph); for(Resource r : graph.getObjects(type, L0.DomainOf)) { String name = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING); if(name != null) result.put(name, r); } for(Resource t : graph.getSupertypes(type)) { for(Resource r : graph.getObjects(t, L0.DomainOf)) { String name = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING); if(name != null) result.put(name, r); } } return result; } public static Resource getPossiblePredicateByName(ReadGraph graph, Resource instance, String predicateName) throws DatabaseException { for(Resource type : graph.getPrincipalTypes(instance)) { Map domainOf = getDomainOf(graph, type); Resource predicate = domainOf.get(predicateName); if(predicate != null) return predicate; } return null; } public static void claimLiteralDataboard(WriteGraph graph, Resource container, Resource property, String valueText) throws DatabaseException { try { PropertyInfo pi = graph.syncRequest(new PropertyInfoRequest(property)); if(pi.literalRange == null) throw new DatabaseException("No suitable literal type defined as range for property."); if(pi.defaultBinding == null) throw new DatabaseException("No suitable default binding for property."); Object value = pi.defaultBinding.parseValue(valueText, new DataValueRepository()); graph.claimLiteral(container, property, pi.literalRange, value, pi.defaultBinding); } catch (DataTypeSyntaxError e) { throw new DatabaseException(e); } catch (BindingException e) { throw new DatabaseException(e); } } }