830f7a6bb74776ece6a99b35eb3b9b51999cc10a
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / util / Layer0Utils.java
1 /*******************************************************************************
2  * Copyright (c) 2012 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.layer0.util;
13
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.Comparator;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.TreeSet;
24
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.core.runtime.NullProgressMonitor;
27 import org.eclipse.core.runtime.SubMonitor;
28 import org.simantics.databoard.Bindings;
29 import org.simantics.databoard.Datatypes;
30 import org.simantics.databoard.adapter.AdaptException;
31 import org.simantics.databoard.adapter.Adapter;
32 import org.simantics.databoard.adapter.AdapterConstructionException;
33 import org.simantics.databoard.binding.Binding;
34 import org.simantics.databoard.binding.NumberBinding;
35 import org.simantics.databoard.binding.StringBinding;
36 import org.simantics.databoard.binding.error.BindingException;
37 import org.simantics.databoard.binding.mutable.MutableStringBinding;
38 import org.simantics.databoard.parser.repository.DataTypeSyntaxError;
39 import org.simantics.databoard.parser.repository.DataValueRepository;
40 import org.simantics.databoard.primitives.MutableString;
41 import org.simantics.databoard.type.ArrayType;
42 import org.simantics.databoard.type.BooleanType;
43 import org.simantics.databoard.type.ByteType;
44 import org.simantics.databoard.type.Datatype;
45 import org.simantics.databoard.type.DoubleType;
46 import org.simantics.databoard.type.FloatType;
47 import org.simantics.databoard.type.IntegerType;
48 import org.simantics.databoard.type.LongType;
49 import org.simantics.databoard.type.MapType;
50 import org.simantics.databoard.type.NumberType;
51 import org.simantics.databoard.type.OptionalType;
52 import org.simantics.databoard.type.RecordType;
53 import org.simantics.databoard.type.StringType;
54 import org.simantics.databoard.type.UnionType;
55 import org.simantics.databoard.type.VariantType;
56 import org.simantics.databoard.util.ObjectUtils;
57 import org.simantics.datatypes.literal.GUID;
58 import org.simantics.db.ChangeSetIdentifier;
59 import org.simantics.db.Operation;
60 import org.simantics.db.ReadGraph;
61 import org.simantics.db.RelationContext;
62 import org.simantics.db.Resource;
63 import org.simantics.db.Session;
64 import org.simantics.db.Statement;
65 import org.simantics.db.WriteGraph;
66 import org.simantics.db.WriteOnlyGraph;
67 import org.simantics.db.common.CommentMetadata;
68 import org.simantics.db.common.Indexing;
69 import org.simantics.db.common.StandardStatement;
70 import org.simantics.db.common.primitiverequest.PossibleRelatedValue;
71 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
72 import org.simantics.db.common.request.DelayedWriteRequest;
73 import org.simantics.db.common.request.ObjectsWithType;
74 import org.simantics.db.common.request.PossibleIndexRoot;
75 import org.simantics.db.common.request.WriteRequest;
76 import org.simantics.db.common.utils.CommonDBUtils;
77 import org.simantics.db.common.utils.NameUtils;
78 import org.simantics.db.event.ChangeListener;
79 import org.simantics.db.exception.CancelTransactionException;
80 import org.simantics.db.exception.DatabaseException;
81 import org.simantics.db.exception.ServiceException;
82 import org.simantics.db.layer0.adapter.CopyHandler;
83 import org.simantics.db.layer0.adapter.CopyHandler2;
84 import org.simantics.db.layer0.adapter.GenericRelationIndex;
85 import org.simantics.db.layer0.adapter.PasteHandler;
86 import org.simantics.db.layer0.adapter.impl.DefaultPasteHandler;
87 import org.simantics.db.layer0.adapter.impl.EntityRemover;
88 import org.simantics.db.layer0.adapter.impl.TGRemover;
89 import org.simantics.db.layer0.genericrelation.IndexedRelations;
90 import org.simantics.db.layer0.internal.SimanticsInternal;
91 import org.simantics.db.layer0.migration.OntologiesFromLibrary;
92 import org.simantics.db.layer0.property.OrderedResource;
93 import org.simantics.db.layer0.request.GlobalOntologies;
94 import org.simantics.db.layer0.request.PossibleVariableIndexRoot;
95 import org.simantics.db.layer0.request.PropertyInfo;
96 import org.simantics.db.layer0.request.PropertyInfoRequest;
97 import org.simantics.db.layer0.util.SimanticsClipboard.Representation;
98 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
99 import org.simantics.db.layer0.variable.Variable;
100 import org.simantics.db.service.ClusterCollectorPolicy;
101 import org.simantics.db.service.ClusterControl;
102 import org.simantics.db.service.ClusteringSupport;
103 import org.simantics.db.service.CollectionSupport;
104 import org.simantics.db.service.DebugSupport;
105 import org.simantics.db.service.GraphChangeListenerSupport;
106 import org.simantics.db.service.ManagementSupport;
107 import org.simantics.db.service.UndoRedoSupport;
108 import org.simantics.db.service.XSupport;
109 import org.simantics.graph.db.TransferableGraphSource;
110 import org.simantics.graph.db.TransferableGraphs;
111 import org.simantics.graph.diff.Diff;
112 import org.simantics.graph.diff.TransferableGraphDelta1;
113 import org.simantics.graph.refactoring.GraphRefactoringUtils;
114 import org.simantics.graph.representation.PrettyPrintTG;
115 import org.simantics.graph.representation.TransferableGraph1;
116 import org.simantics.layer0.Layer0;
117 import org.simantics.operation.Layer0X;
118 import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
119 import org.simantics.scl.compiler.types.Type;
120 import org.simantics.scl.osgi.SCLOsgi;
121 import org.simantics.scl.runtime.function.Function;
122 import org.simantics.scl.runtime.function.Function1;
123 import org.simantics.scl.runtime.function.FunctionImpl1;
124
125 public class Layer0Utils {
126
127         @SuppressWarnings("rawtypes")
128         public static final ThreadLocal SCL_GRAPH = new ThreadLocal();
129
130         public static Resource literal(WriteGraph g, String value) throws DatabaseException {
131                 Layer0 L0 = Layer0.getInstance(g);
132                 Resource r = g.newResource();
133                 g.claimValue(r, value, Bindings.STRING);
134                 g.claim(r, L0.InstanceOf, L0.String);
135                 return r;
136         }
137
138         public static Resource literal(WriteGraph g, double value) throws DatabaseException {
139                 Layer0 L0 = Layer0.getInstance(g);
140                 Resource r = g.newResource();
141                 g.claimValue(r, value, Bindings.DOUBLE);
142                 g.claim(r, L0.InstanceOf, L0.Double);
143                 return r;
144         }
145
146         public static Resource literal(WriteGraph g, int value) throws DatabaseException {
147                 Layer0 L0 = Layer0.getInstance(g);
148                 Resource r = g.newResource();
149                 g.claimValue(r, value, Bindings.INTEGER);
150                 g.claim(r, L0.InstanceOf, L0.Integer);
151                 return r;
152         }
153
154         public static void assert_(WriteGraph g, Resource type, Resource predicate, Resource object) throws DatabaseException {
155                 Layer0 L0 = Layer0.getInstance(g);
156                 Resource assertion = g.newResource();
157                 g.claim(type, L0.Asserts, assertion);
158                 g.claim(assertion, L0.InstanceOf, L0.Assertion);
159                 g.claim(assertion, L0.HasPredicate, predicate);
160                 g.claim(assertion, L0.HasObject, object);
161         }
162
163         public static Resource relation(WriteGraph g, Resource parent, String name, Resource superrelation) throws DatabaseException {
164                 Layer0 L0 = Layer0.getInstance(g);
165                 Resource relation = g.newResource();
166                 g.claim(relation, L0.SubrelationOf, superrelation);
167                 g.claim(relation, L0.HasName, literal(g, name));
168                 g.claim(parent, L0.ConsistsOf, relation);
169
170                 Resource superrelationInverse = g.getInverse(superrelation);
171                 if(superrelationInverse != null) {
172                         Resource inverse = g.newResource();
173                         g.claim(inverse, L0.SubrelationOf, superrelationInverse);
174                         g.claim(relation, L0.ConsistsOf, inverse);
175                         g.claim(inverse, L0.HasName, literal(g, "Inverse"));
176                 }
177                 return relation;
178         }
179
180         private static Resource getLiteralType(ReadGraph graph, Datatype type) throws DatabaseException {
181                 Layer0 L0 = Layer0.getInstance(graph);
182                 if(type instanceof DoubleType) return L0.Double;
183                 else if(type instanceof StringType) return L0.String;
184                 else if(type instanceof IntegerType) return L0.Integer;
185                 else if(type instanceof LongType) return L0.Long;
186                 else if(type instanceof FloatType) return L0.Float;
187                 else if(type instanceof ByteType) return L0.Byte;
188                 else if(type instanceof BooleanType) return L0.Boolean;
189                 else if(type instanceof ArrayType) {
190                         ArrayType at = (ArrayType)type;
191                         if(at.componentType instanceof DoubleType) return L0.DoubleArray;
192                         else if(at.componentType instanceof StringType) return L0.StringArray;
193                         else if(at.componentType instanceof IntegerType) return L0.IntegerArray;
194                         else if(at.componentType instanceof LongType) return L0.LongArray;
195                         else if(at.componentType instanceof FloatType) return L0.FloatArray;
196                         else if(at.componentType instanceof ByteType) return L0.ByteArray;
197                         else if(at.componentType instanceof BooleanType) return L0.BooleanArray;
198                         else if(at.componentType instanceof VariantType) return L0.VariantArray;
199                 }
200                 throw new DatabaseException("Unidentified literal type for datatype " + type);
201         }
202
203         private static Resource getPossibleLiteralType(ReadGraph graph, String type) throws DatabaseException {
204
205                 Layer0 L0 = Layer0.getInstance(graph);
206                 if("Double".equals(type)) return L0.Double;
207                 else if("String".equals(type)) return L0.String;
208                 else if("Integer".equals(type)) return L0.Integer;
209                 else if("Long".equals(type)) return L0.Long;
210                 else if("Float".equals(type)) return L0.Float;
211                 else if("Byte".equals(type)) return L0.Byte;
212                 else if("Boolean".equals(type)) return L0.Boolean;
213                 else if("[Double]".equals(type)) return L0.DoubleArray;
214                 else if("[String]".equals(type)) return L0.StringArray;
215                 else if("[Integer]".equals(type)) return L0.IntegerArray;
216                 else if("[Long]".equals(type)) return L0.LongArray;
217                 else if("[Float]".equals(type)) return L0.FloatArray;
218                 else if("[Byte]".equals(type)) return L0.ByteArray;
219                 else if("[Boolean]".equals(type)) return L0.BooleanArray;
220                 else if("[Variant]".equals(type)) return L0.VariantArray;
221                 else if("Array Double".equals(type)) return L0.DoubleArray;
222                 else if("Array String".equals(type)) return L0.StringArray;
223                 else if("Array Integer".equals(type)) return L0.IntegerArray;
224                 else if("Array Long".equals(type)) return L0.LongArray;
225                 else if("Array Float".equals(type)) return L0.FloatArray;
226                 else if("Array Byte".equals(type)) return L0.ByteArray;
227                 else if("Array Boolean".equals(type)) return L0.BooleanArray;
228                 else if("Array Variant".equals(type)) return L0.VariantArray;
229                 else if("Vector Double".equals(type)) return L0.DoubleArray;
230                 else if("Vector String".equals(type)) return L0.StringArray;
231                 else if("Vector Integer".equals(type)) return L0.IntegerArray;
232                 else if("Vector Long".equals(type)) return L0.LongArray;
233                 else if("Vector Float".equals(type)) return L0.FloatArray;
234                 else if("Vector Byte".equals(type)) return L0.ByteArray;
235                 else if("Vector Boolean".equals(type)) return L0.BooleanArray;
236                 else if("Vector Variant".equals(type)) return L0.VariantArray;
237                 else if("Datatype".equals(type)) return L0.DataType;
238                 else if("Variant".equals(type)) return L0.Variant;
239                 else return null;
240         }
241
242         public static Resource getPossibleLiteralType(ReadGraph graph, Variable variable) throws DatabaseException {
243                 Resource predicate = variable.getPossiblePredicateResource(graph);
244                 if(predicate == null) return null;
245                 return getPossibleLiteralType(graph, predicate);
246         }
247
248         public static Resource getLiteralType(ReadGraph graph, Variable variable) throws DatabaseException {
249                 Resource result = getPossibleLiteralType(graph, variable);
250                 if(result == null) throw new DatabaseException("Unidentified literal type for variable " + variable.getURI(graph));
251                 return result;
252         }
253
254         public static Resource getLiteralType(ReadGraph graph, Resource property) throws DatabaseException {
255                 Resource result = getPossibleLiteralType(graph, property);
256                 if(result == null) throw new DatabaseException("Unidentified literal type for property " + graph.getURI(property));
257                 return result;
258         }
259
260         public static Resource getPossibleLiteralType(ReadGraph graph, Resource property) throws DatabaseException {
261
262                 Layer0 L0 = Layer0.getInstance(graph);
263                 Layer0X L0X = Layer0X.getInstance(graph);
264
265                 Resource defaultLiteralType = graph.getPossibleObject(property, L0.HasDefaultLiteralType);
266                 if(defaultLiteralType != null) return defaultLiteralType;
267
268                 Resource range = graph.getPossibleObject(property, L0.HasRange);
269                 if(range != null && !L0.Value.equals(range)) return range;
270
271                 Datatype requiredDataType = graph.getPossibleRelatedValue(property, L0X.RequiresDataType, Bindings.DATATYPE);
272                 if(requiredDataType != null) return getLiteralType(graph, requiredDataType);
273
274                 String requiredValueType = graph.getPossibleRelatedValue(property, L0.RequiresValueType, Bindings.STRING);
275                 if(requiredValueType == null) return null;
276
277                 return getPossibleLiteralType(graph, requiredValueType);
278
279         }
280
281         /**
282          * @param type any data type definition
283          * @return SCL type that matches the specified data type on a basic level.
284          *         Data type metadata is/cannot be converted into SCL types.
285          * @throws IllegalArgumentException
286          *             if the input datatype can't be converted into an SCL type
287          */
288         public static String getSCLType(Datatype type) throws IllegalArgumentException {
289                 return buildSCLType(type, null).toString();
290         }
291
292         /**
293          * Only used internally by {@link #buildSCLType(Datatype, StringBuilder)}
294          * @param s
295          * @param toBuilder
296          * @return
297          * @see #buildSCLType(Datatype, StringBuilder)
298          */
299         private static StringBuilder append(StringBuilder toBuilder, String s) {
300                 return toBuilder != null ? toBuilder.append(s) : new StringBuilder(s);
301         }
302
303         private static CharSequence append(CharSequence to, String s) {
304                 if (to instanceof StringBuilder)
305                         return ((StringBuilder) to).append(s);
306                 return new StringBuilder(to.length() + s.length()).append(to).append(s);
307         }
308
309         private static CharSequence stringOrBuilder(StringBuilder toBuilder, String s) {
310                 return toBuilder != null ? toBuilder.append(s) : s;
311         }
312
313         /**
314          * @param type any data type definition
315          * @return SCL type that matches the specified data type on a basic level.
316          *         Data type metadata is/cannot be converted into SCL types.
317          * @throws IllegalArgumentException
318          *             if the input datatype can't be converted into an SCL type
319          */
320         private static CharSequence buildSCLType(Datatype type, StringBuilder result) throws IllegalArgumentException {
321                 if(type instanceof DoubleType) return stringOrBuilder(result, "Double");
322                 else if(type instanceof StringType) return stringOrBuilder(result, "String");
323                 else if(type instanceof IntegerType) return stringOrBuilder(result, "Integer");
324                 else if(type instanceof FloatType) return stringOrBuilder(result, "Float");
325                 else if(type instanceof BooleanType) return stringOrBuilder(result, "Boolean");
326                 else if(type instanceof ByteType) return stringOrBuilder(result, "Byte");
327                 else if(type instanceof LongType) return stringOrBuilder(result, "Long");
328                 else if(type instanceof VariantType) return stringOrBuilder(result, "Variant");
329                 else if(type instanceof ArrayType) {
330                         ArrayType at = (ArrayType) type;
331                         // Optimization to prevent allocations in the most basic array cases
332                         if(at.componentType instanceof DoubleType) return stringOrBuilder(result, "Vector Double");
333                         else if(at.componentType instanceof StringType) return stringOrBuilder(result, "Vector String");
334                         else if(at.componentType instanceof IntegerType) return stringOrBuilder(result, "Vector Integer");
335                         else if(at.componentType instanceof FloatType) return stringOrBuilder(result, "Vector Float");
336                         else if(at.componentType instanceof BooleanType) return stringOrBuilder(result, "Vector Boolean");
337                         else if(at.componentType instanceof ByteType) return stringOrBuilder(result, "Vector Byte");
338                         else if(at.componentType instanceof LongType) return stringOrBuilder(result, "Vector Long");
339                         else if(at.componentType instanceof VariantType) return stringOrBuilder(result, "Vector Variant");
340                         else return buildSCLType(at.componentType, append(result, "Vector "));
341                 } else if(type instanceof OptionalType) {
342                         OptionalType ot = (OptionalType) type;
343                         return append(buildSCLType(ot.componentType, append(result, "Maybe (")), ")");
344                 } else if (type instanceof RecordType) {
345                         throw new IllegalArgumentException("Unable to convert datatype into SCL type: " + type);
346                 } else if (type instanceof MapType) {
347                         throw new IllegalArgumentException("Unable to convert datatype into SCL type: " + type);
348                 } else if (type instanceof UnionType) {
349                         throw new IllegalArgumentException("Unable to convert datatype into SCL type: " + type);
350                 }
351                 throw new IllegalArgumentException("Unable to convert datatype into SCL type: " + type);
352         }
353
354         @Deprecated
355         public static Type getSCLType(ReadGraph graph, RuntimeEnvironment runtimeEnvironment, String typeText) throws DatabaseException {
356             return CommonDBUtils.getSCLType(graph, runtimeEnvironment, typeText);
357         }
358
359         public static Type getSCLType(ReadGraph graph, Variable property) throws DatabaseException {
360
361                 RuntimeEnvironment runtimeEnvironment = graph.syncRequest(new RuntimeEnvironmentRequest(property.getIndexRoot(graph)));
362                 return getSCLType(graph, runtimeEnvironment, getSCLTypeString(graph, property));
363
364         }
365
366                 
367         public static String getSCLTypeString(ReadGraph graph, Variable context) throws DatabaseException {
368                 return getSCLTypeString(graph, context.getPossiblePredicateResource(graph), context.getRepresents(graph));
369         }
370
371
372         public static String getSCLTypeString(ReadGraph graph, Resource predicate, Resource value) throws DatabaseException {
373
374                 if(predicate != null) {
375                     String requiredValueTypes = graph.getPossibleRelatedValue(predicate, Layer0.getInstance(graph).RequiresValueType, Bindings.STRING);
376                     if(requiredValueTypes != null)
377                         return requiredValueTypes;
378                 }
379
380                 Layer0 L0 = Layer0.getInstance(graph);
381                 Layer0X L0X = Layer0X.getInstance(graph);
382
383                 Datatype literalDatatype = graph.getPossibleRelatedValue(value, L0.HasDataType, Bindings.DATATYPE);
384                 if(literalDatatype != null) return getSCLType(literalDatatype);
385
386                 String literalValueType = graph.getPossibleRelatedValue(value, L0.HasValueType, Bindings.STRING);
387                 if(literalValueType != null) return literalValueType;
388
389                 if(predicate != null) {
390
391                         Datatype requiredDataType = graph.getPossibleRelatedValue(predicate, L0X.RequiresDataType, Bindings.DATATYPE);
392                         if(requiredDataType != null) return getSCLType(requiredDataType);
393
394                         throw new DatabaseException("Unidentified literal data type for property " + NameUtils.getURIOrSafeNameInternal(graph, predicate));
395
396                 }
397
398                 throw new DatabaseException("Unidentified literal data type");
399
400         }
401
402         public static Datatype getDatatype(ReadGraph graph, Variable variable) throws DatabaseException {
403                 Datatype result = getPossibleDatatype(graph, variable);
404                 if(result != null) return result;
405                 throw new DatabaseException("Unidentified literal data type for property " + variable.getURI(graph));
406         }
407
408         public static Datatype getPossibleDatatype(ReadGraph graph, Variable variable) throws DatabaseException {
409                 return getPossibleDatatype(graph, variable, null, true);
410         }
411
412         private static Datatype getPossibleDatatype(ReadGraph graph, Variable variable, PropertyInfo info, boolean checkPropertyDatatype) throws DatabaseException {
413                 Layer0 L0 = Layer0.getInstance(graph);
414                 Layer0X L0X = Layer0X.getInstance(graph);
415
416                 Resource property = variable.getPossiblePredicateResource(graph);
417                 if(checkPropertyDatatype && property != null) {
418                         Datatype requiredDataType = graph.syncRequest(new PossibleRelatedValue<Datatype>(property, L0X.RequiresDataType, Bindings.DATATYPE));
419                         if(requiredDataType != null) return requiredDataType;
420                 }
421
422                 Resource literal = variable.getPossibleRepresents(graph);
423                 if(literal != null) {
424                         Datatype literalDatatype = graph.getPossibleRelatedValue2(literal, L0.HasDataType, new StandardGraphPropertyVariable(graph, variable, null, literal, L0.HasDataType), Bindings.DATATYPE);
425                         if(literalDatatype != null) return literalDatatype;
426                 }
427
428                 if(property != null) {
429
430                         String requiredValueType = info != null
431                                         ? info.requiredValueType
432                                         : graph.getPossibleRelatedValue(property, L0.RequiresValueType, Bindings.STRING);
433                         if(requiredValueType != null) {
434                                 Datatype datatype = getPossibleDatatypeForValueType(requiredValueType);
435                                 if(datatype != null) return datatype;
436                         }
437
438                         Resource subject = variable.getParent(graph).getPossibleRepresents(graph);
439                         if(subject != null) {
440                                 Set<Resource> asses = new HashSet<Resource>();
441                                 for(Resource type : graph.getTypes(subject)) {
442                                         asses.addAll(graph.getAssertedObjects(type, property));
443                                 }
444                                 if(asses.size() == 1) {
445                                         Resource ass = asses.iterator().next();
446                                         Datatype dt = graph.getPossibleRelatedValue(ass, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
447                                         if(dt != null) return dt;
448                                 }
449                         }
450
451                 }
452
453                 return null;
454         }
455
456         private static Datatype getPossibleDatatypeForValueType(String requiredValueType) throws DatabaseException {
457
458                 String[] split = requiredValueType.split(" ");
459                 String arrayType = null;
460                 if(split.length == 2 && "Array".equals(split[0])) {
461                         arrayType = split[1];
462                 } else if(requiredValueType.startsWith("[") && requiredValueType.endsWith("]")) {
463                         arrayType = requiredValueType.substring(1, requiredValueType.length()-1);
464                 }
465
466                 Datatype arrayDataType = getDatatypeForType(arrayType != null ? arrayType : requiredValueType, arrayType != null);
467                 if(arrayDataType != null)
468                         return arrayDataType;
469
470                 Datatype dt = Datatypes.getDatatype(requiredValueType);
471                 if(dt != null) return dt;
472
473                 try {
474                         return Datatypes.translate(requiredValueType);
475                 } catch (DataTypeSyntaxError e) {
476                         return null;
477                 }
478
479         }
480
481         private static Datatype getDatatypeForType(String type, boolean isArray) {
482                 switch (type) {
483                         case "Double":  return isArray ? Datatypes.DOUBLE_ARRAY  : Datatypes.DOUBLE;
484                         case "String":  return isArray ? Datatypes.STRING_ARRAY  : Datatypes.STRING;
485                         case "Integer": return isArray ? Datatypes.INTEGER_ARRAY : Datatypes.INTEGER;
486                         case "Long":    return isArray ? Datatypes.LONG_ARRAY    : Datatypes.LONG;
487                         case "Float":   return isArray ? Datatypes.FLOAT_ARRAY   : Datatypes.FLOAT;
488                         case "Byte":    return isArray ? Datatypes.BYTE_ARRAY    : Datatypes.BYTE;
489                         case "Boolean": return isArray ? Datatypes.BOOLEAN_ARRAY : Datatypes.BOOLEAN;
490                         case "Variant": return isArray ? Datatypes.VARIANT_ARRAY : Datatypes.VARIANT;
491                 }
492                 return null;
493         }
494
495         public static Binding getDefaultBinding(ReadGraph graph, Variable variable) throws DatabaseException {
496
497                 Resource property = variable.getPossiblePredicateResource(graph);
498                 if(property != null) {
499                         PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(property), TransientCacheAsyncListener.<PropertyInfo>instance());
500                         if(info.defaultBinding != null) return info.defaultBinding;
501                 }
502
503                 Datatype type = getDatatype(graph, variable);
504                 return Bindings.getBinding(type);
505
506         }
507
508         public static Binding getPossibleDefaultBinding(ReadGraph graph, Variable variable) throws DatabaseException {
509
510                 Resource property = variable.getPossiblePredicateResource(graph);
511                 PropertyInfo info = null;
512                 if(property != null) {
513                         info = graph.syncRequest(new PropertyInfoRequest(property), TransientCacheAsyncListener.<PropertyInfo>instance());
514                         if(info.defaultBinding != null) return info.defaultBinding;
515                 }
516
517                 Datatype type = getPossibleDatatype(graph, variable, info, false);
518                 if (type == null) return null;
519
520                 return Bindings.getBinding(type);
521
522         }
523
524         public static String getPossibleUnit(Datatype dt) {
525                 if (dt == null)
526                         return null;
527                 else if (dt instanceof NumberType) {
528                         return ((NumberType) dt).getUnit();
529                 } else if (dt instanceof ArrayType) {
530                         ArrayType at = (ArrayType) dt;
531                         Datatype cdt = at.componentType();
532                         if (cdt instanceof NumberType) {
533                                 return ((NumberType) cdt).getUnit();
534                         }
535                 }
536                 return null;
537
538         }
539
540         public static String getUnit(ReadGraph graph, Variable variable) throws DatabaseException {
541
542                 Layer0 L0 = Layer0.getInstance(graph);
543                 Layer0X L0X = Layer0X.getInstance(graph);
544
545                 Resource literal = variable.getPossibleRepresents(graph);
546                 if(literal == null)
547                     return "";
548
549                 Datatype literalDatatype = graph.getPossibleRelatedValue2(literal, L0.HasDataType, new StandardGraphPropertyVariable(graph, variable, null, literal, L0.HasDataType), Bindings.DATATYPE);
550                 if(literalDatatype != null) {
551                         String unit = getPossibleUnit(literalDatatype);
552                         if(unit != null) return unit;
553                 }
554
555                 Resource property = variable.getPossiblePredicateResource(graph);
556                 if(property != null) {
557
558                         Datatype requiredDataType = graph.getPossibleRelatedValue(property, L0X.RequiresDataType, Bindings.DATATYPE);
559                         if(requiredDataType != null) {
560                                 String unit = getPossibleUnit(requiredDataType);
561                                 if(unit != null) return unit;
562                         }
563
564                 }
565
566                 return "";
567
568         }
569
570         public static void claimAdaptedValue(WriteGraph graph, Resource objectResource, Object value, Binding binding, Datatype targetDatatype) throws DatabaseException {
571
572                 try {
573
574                         Datatype sourceDatatype = binding.type();
575                         if(sourceDatatype.equals(targetDatatype)) {
576                                 graph.claimValue(objectResource, value, binding);
577                         } else {
578                                 Binding target = Bindings.getBinding(targetDatatype);
579                                 Adapter adapter = Bindings.getTypeAdapter(binding, target);
580                                 graph.claimValue(objectResource, adapter.adapt(value), target);
581                         }
582
583                 } catch (AdapterConstructionException e) {
584                         throw new DatabaseException(e);
585                 } catch (AdaptException e) {
586                         throw new DatabaseException(e);
587                 }
588
589         }
590
591         public static String toString(Object value, Binding binding) throws DatabaseException {
592                 try {
593                         if(value instanceof String) return (String)value;
594                         StringBuilder sb = new StringBuilder();
595                         DataValueRepository rep = new DataValueRepository();
596                         binding.printValue(value, sb, rep, false);
597                         return sb.toString();
598                 } catch (BindingException e) {
599                         throw new DatabaseException(e);
600                 } catch (IOException e) {
601                         throw new DatabaseException(e);
602                 }
603         }
604
605         public static Object parseValue(String text, Binding binding) throws DatabaseException {
606                 try {
607                         if(binding.isInstance(text)) return text;
608                         DataValueRepository rep = new DataValueRepository();
609                         return binding.parseValue(text, rep);
610                 } catch (BindingException e) {
611                         throw new DatabaseException(e);
612                 } catch (DataTypeSyntaxError e) {
613                         throw new DatabaseException(e);
614                 }
615         }
616
617         @SuppressWarnings("unchecked")
618         public static <T> T getValueAdaptedToBinding(ReadGraph graph, Resource literal, Binding targetBinding) throws DatabaseException {
619                 Datatype sourceDatatype = graph.getDataType(literal);
620                 Datatype targetDatatype = targetBinding.type();
621                 if (sourceDatatype.equals(targetDatatype))
622                         return graph.getValue(literal, targetBinding);
623
624                 Binding sourceBinding = Bindings.getBinding(sourceDatatype);
625                 try {
626                         Adapter adapter = Bindings.adapterFactory.getAdapter(Bindings.getBinding(sourceDatatype), targetBinding, true, false);
627                         Object value = graph.getValue(literal, sourceBinding);
628                         return (T) adapter.adaptUnchecked(value);
629                 } catch (AdapterConstructionException e) {
630                         throw new DatabaseException(e);
631                 }
632         }
633
634         public static Statement getStatementInLocal(Resource subject, Statement statement) {
635                 if(statement.isAsserted(subject)) return new StandardStatement(subject, statement.getPredicate(), statement.getObject());
636                 else return statement;
637         }
638
639         public static Resource browsePossible(ReadGraph graph, Resource root, String suffix) throws DatabaseException {
640                 return graph.getPossibleResource(graph.getURI(root) + suffix);
641         }
642
643         @Deprecated
644         public static Resource getPossibleChild(ReadGraph graph, Resource resource, String name) throws DatabaseException {
645                 return CommonDBUtils.getPossibleChild(graph, resource, name);
646         }
647
648         @Deprecated
649         public static Resource getPossibleChild(ReadGraph graph, Resource resource, Resource type, String name) throws DatabaseException {
650                 return CommonDBUtils.getPossibleChild(graph, resource, type, name);
651         }
652
653         public static RelationContext relationContext(ReadGraph graph, Resource subject, Resource predicate) throws DatabaseException {
654                 Statement stm = graph.getSingleStatement(subject, predicate);
655                 return new RelationContextImpl(subject, stm);
656         }
657
658         public static RelationContext relationContext(Statement stm) throws DatabaseException {
659                 return new RelationContextImpl(stm.getSubject(), stm);
660         }
661
662         public static <T> T valueInRelationContext(ReadGraph graph, Resource subject, Statement stm) throws DatabaseException {
663                 return graph.getValue2(subject, Layer0Utils.relationContext(stm));
664         }
665
666         public static <T> T valueInRelationContext(ReadGraph graph, Resource subject, Statement stm, Binding binding) throws DatabaseException {
667                 return graph.getValue2(subject, Layer0Utils.relationContext(stm), binding);
668         }
669
670         public static <T> T relatedValueInRelationContext(ReadGraph graph, Resource subject, Resource relation) throws DatabaseException {
671                 Statement stm = getStatementInLocal(subject, graph.getSingleStatement(subject, relation));
672                 return valueInRelationContext(graph, stm.getObject(), stm);
673         }
674
675         public static <T> T relatedValueInRelationContext(ReadGraph graph, Resource subject, Resource relation, Binding binding) throws DatabaseException {
676                 Statement stm = getStatementInLocal(subject, graph.getSingleStatement(subject, relation));
677                 return valueInRelationContext(graph, stm.getObject(), stm, binding);
678         }
679
680         public static Statement possibleObtainedStatementInternal(ReadGraph graph, Resource subject, Resource relation) throws DatabaseException {
681
682                 Layer0X L0X = Layer0X.getInstance(graph);
683
684                 for(Resource ob : graph.getObjects(subject, L0X.DefinesObtainedStatement)) {
685                         Resource pred = graph.getSingleObject(ob, L0X.ObtainedStatement_predicate);
686                         if(graph.isSubrelationOf(pred, relation)) {
687                                 Resource object = graph.getSingleObject(ob, L0X.ObtainedStatement_object);
688                                 return new StandardStatement(subject, pred, object);
689                         }
690                 }
691
692                 ArrayList<OrderedResource> order = new ArrayList<OrderedResource>();
693                 for(Statement stm : graph.getStatements(subject, L0X.ObtainsProperty)) {
694                         Integer position = graph.getRelatedValue(stm.getPredicate(), L0X.NaturalNumberOrderRelation, Bindings.INTEGER);
695                         order.add(new OrderedResource(position, stm.getObject()));
696                 }
697
698                 for(OrderedResource or : order) {
699                         Statement stm = possibleObtainedStatementInternal(graph, or.r, relation);
700                         if(stm != null) return stm;
701                 }
702
703                 return null;
704
705         }
706
707         public static <T> T possibleObtainedValue(ReadGraph graph, RelationContext ctx, Binding binding) throws DatabaseException {
708
709                 Statement stm = ctx.getStatement();
710                 Statement obj = Layer0Utils.possibleObtainedStatementInternal(graph, stm.getSubject(), stm.getPredicate());
711
712                 if(obj != null) {
713                         return Layer0Utils.valueInRelationContext(graph, obj.getObject(), obj, binding);
714                 } else {
715                         return null;
716                 }
717
718         }
719
720         public static void addObtainedStatement(WriteGraph graph, Resource subject, Resource predicate, Resource object) throws DatabaseException {
721                 Layer0 L0 = Layer0.getInstance(graph);
722                 Layer0X L0X = Layer0X.getInstance(graph);
723                 Resource ob = graph.newResource();
724                 graph.claim(ob, L0.InstanceOf, null, L0X.ObtainedStatement);
725                 graph.claim(ob, L0X.ObtainedStatement_predicate, null, predicate);
726                 graph.claim(ob, L0X.ObtainedStatement_object, null, object);
727                 graph.claim(subject, L0X.DefinesObtainedStatement, null, ob);
728         }
729
730         public static void addObtainedValue(WriteGraph graph, Resource subject, Resource predicate, Resource type, Object value, Binding binding) throws DatabaseException {
731                 Layer0 L0 = Layer0.getInstance(graph);
732                 Resource object = graph.newResource();
733                 graph.claim(object, L0.InstanceOf, type);
734                 graph.claimValue(object, value, binding);
735                 Layer0Utils.addObtainedStatement(graph, subject, predicate, object);
736         }
737
738         //-------------------------------------------------------------------------
739         // Indexing state query utilities idle handling utilities
740         //-------------------------------------------------------------------------
741
742         /**
743          * This method waits until the indexing engine becomes idle.
744          * @since 1.8
745          */
746         public static void waitIndexPending() {
747                 Indexing.waitIndexPending();
748         }
749
750         /**
751          * @param graph an active database write handle to prove one is in a write
752          *        transaction and wants to disable dependencies indexing for this
753          *        transaction only.
754          * @return previous value
755          * @since 1.8
756          */
757         public static boolean setDependenciesIndexingDisabled(WriteOnlyGraph graph, boolean disabled) {
758                 return Indexing.setDependenciesIndexingDisabled(graph, disabled);
759         }
760
761         public static String undo() throws DatabaseException {
762
763             Session session = SimanticsInternal.getSession();
764
765         UndoRedoSupport support = session.getService(UndoRedoSupport.class);
766
767         List<Operation> ops = support.undoAndReturnOperations(session, 1);
768         if(ops.isEmpty())
769             return "Undo history is empty.";
770
771         Operation mainOperation = ops.get(0);
772
773         long csId = mainOperation.getCSId();
774
775         ManagementSupport management = session.getService(ManagementSupport.class);
776         Collection<ChangeSetIdentifier> ids = management.getChangeSetIdentifiers(csId, csId);
777
778         return "Undo reverted " + ids.size() + " change sets.";
779
780         }
781
782         public static String undoOperations(int amountOfOperations) throws DatabaseException {
783
784             Session session = SimanticsInternal.getSession();
785
786         UndoRedoSupport support = session.getService(UndoRedoSupport.class);
787
788         List<Operation> ops = support.undoAndReturnOperations(session, amountOfOperations);
789         if(ops.isEmpty())
790             return "Undo history is empty.";
791
792         Operation mainOperation = ops.get(0);
793
794         long csId = mainOperation.getCSId();
795
796         ManagementSupport management = session.getService(ManagementSupport.class);
797         Collection<ChangeSetIdentifier> ids = management.getChangeSetIdentifiers(csId, csId);
798
799         return "Undo reverted " + ids.size() + " change sets.";
800
801         }
802
803         public static String redo() throws DatabaseException {
804
805             Session session = SimanticsInternal.getSession();
806
807         UndoRedoSupport support = session.getService(UndoRedoSupport.class);
808
809         List<Operation> ops = support.redo(session, 1);
810         if(ops.isEmpty())
811             return "Redo history is empty.";
812
813         Operation mainOperation = ops.get(0);
814
815         long csId = mainOperation.getCSId();
816
817         ManagementSupport management = session.getService(ManagementSupport.class);
818         Collection<ChangeSetIdentifier> ids = management.getChangeSetIdentifiers(csId, csId);
819
820         return "Redo redid " + ids.size() + " change sets.";
821
822         }
823
824         public static String getComment(Session session, ChangeSetIdentifier id) {
825             byte[] data = id.getMetadata().get(CommentMetadata.class.getName());
826             if(data == null)
827                 return "Undescribed operation.";
828             String comment = CommentMetadata.deserialise(session, data).toString().trim();
829             if(comment.isEmpty())
830                 return "Undescribed operation.";
831             return comment;
832         }
833
834     /**
835      * This method adds CommentMetadata for write transaction. CommentMetadata is used e.g. in Undo view.
836      * @param graph
837      *    graph handle
838      * @param string
839      *    comment
840      * @throws ServiceException
841      */
842     public static void addCommentMetadata(WriteOnlyGraph graph, String string) throws ServiceException {
843         // Add a comment to metadata.
844         CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
845         graph.addMetadata(cm.add(ObjectUtils.toString(string)));
846     }
847
848         //-------------------------------------------------------------------------
849
850         /**
851          * Copy the specified source resource into the specified container using the
852          * specified write transaction handle.
853          *
854          * @param graph write transaction handle
855          * @param targetContainer target container resource of the created copy. The
856          *        exact logic of how the copy will be contained by the target
857          *        container is up to the PasteHandler to decide
858          * @param source the source resource to copy
859          * @throws DatabaseException
860          * @since 1.8
861          */
862         public static Collection<Resource> copyTo(WriteGraph graph, Resource targetContainer, Resource source) throws DatabaseException {
863                 return copyTo(graph, targetContainer, source, null, null, null);
864         }
865
866         public static Collection<Resource> copyTo(WriteGraph graph, Resource targetContainer, Resource source, PasteEventHandler handler) throws DatabaseException {
867                 return copyTo(graph, targetContainer, source, handler, null, null);
868         }
869
870         public static Collection<Resource> copyTo(WriteGraph graph, Resource targetContainer, Resource source, PasteEventHandler handler, CopyHandler copyHandler, PasteHandler pasteHandler) throws DatabaseException {
871                 if(copyHandler == null) copyHandler = graph.adapt(source, CopyHandler.class);
872                 return copyTo(graph, targetContainer, handler, copyHandler, pasteHandler);
873         }
874
875         public static Collection<Resource> copyTo(WriteGraph graph, Resource targetContainer, PasteEventHandler handler, CopyHandler copyHandler, PasteHandler pasteHandler) throws DatabaseException {
876                 SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();
877                 copyHandler.copyToClipboard(graph, clipboard, new NullProgressMonitor());
878                 if(targetContainer != null) {
879                         if(pasteHandler == null) pasteHandler = graph.adapt(targetContainer, PasteHandler.class);
880                         return pasteHandler.pasteFromClipboard(graph, clipboard, handler);
881                 } else {
882                         DefaultPasteHandler ph = new DefaultPasteHandler(null);
883                         return ph.pasteFromClipboard(graph, clipboard, handler);
884                 }
885         }
886
887         public static CopyHandler2 getPossibleCopyHandler(ReadGraph graph, Collection<Resource> rs) throws DatabaseException {
888         CopyHandler2 ch = null;
889         for(Resource r : rs) {
890             if(ch == null) {
891                 CopyHandler ch2_ = graph.adapt(r, CopyHandler.class);
892                 if(ch2_ instanceof CopyHandler2) {
893                     ch = (CopyHandler2)ch2_;
894                 }
895             } else {
896                 CopyHandler ch2_ = graph.adapt(r, CopyHandler.class);
897                 if(ch2_ instanceof CopyHandler2) {
898                     CopyHandler2 ch2 = (CopyHandler2)ch2_;
899                     ch = ch.combine(ch2);
900                 }
901             }
902         }
903         return ch;
904         }
905
906         public static ClusterCollectorPolicy setClusterCollectorPolicy(ClusterCollectorPolicy policy) {
907                 Session session = SimanticsInternal.getSession();
908                 ClusterControl cc = session.getService(ClusterControl.class);
909                 return cc.setPolicy(policy);
910         }
911
912         private static String decodeType(ReadGraph graph, Variable variable) throws DatabaseException {
913                 Datatype dt = getDatatype(graph, variable);
914                 return dt.toSingleLineString();
915         }
916
917         private static boolean isAsserted(ReadGraph graph, Resource subject, Resource predicate) throws DatabaseException {
918                 Statement stm = graph.getPossibleStatement(subject, predicate);
919                 return stm != null && stm.isAsserted(subject);
920         }
921
922         /*
923          * Works around problems in WriteGraph methods with similar signature. 
924          * Especially handles better some cases with existing literals.
925          * 
926          */
927         public static void claimLiteral(WriteGraph graph, Resource r, Resource p, Resource i, Resource t, Object value, Binding binding) throws DatabaseException {
928             Statement stm = graph.getPossibleStatement(r, p);
929             if(stm != null && !stm.isAsserted(r)) {
930                 if(graph.isInstanceOf(stm.getObject(), t)) {
931                     // Existing statement is compatible, reuse the literal
932                     graph.claimValue(stm.getObject(), value, binding);
933                     return;
934                 } else {
935                     // Existing statement is incompatible - remove it
936                     graph.deny(stm);
937                 }
938             }
939             // Create new statement
940             graph.claimLiteral(r, p, i, t, value, binding);
941         }
942         
943         public static void setExpression(WriteGraph graph, Variable context, String text, Resource expressionValueType) throws DatabaseException {
944                 
945                 Resource value = context.getRepresents(graph);
946                 Resource predicateResource = context.getPredicateResource(graph);
947                 Variable parent = context.getParent(graph);
948                 Resource parentResource = parent.getRepresents(graph);
949                 setExpression(graph, parentResource, predicateResource, value, text, expressionValueType);
950
951         }
952
953         public static void setExpression(WriteGraph graph, Resource parentResource, Resource predicateResource, Resource value, String text, Resource expressionValueType) throws DatabaseException {
954
955                 Layer0 L0 = Layer0.getInstance(graph);
956                 boolean hasExpression = graph.isInstanceOf(value, expressionValueType);
957                 String t = getSCLTypeString(graph, predicateResource, value);
958                 String expression = text.substring(1).trim();
959                 if(isAsserted(graph, parentResource, predicateResource)) {
960                         Resource newValue = graph.newResource();
961                         graph.claim(newValue, L0.InstanceOf, expressionValueType);
962                         graph.claimLiteral(newValue, L0.HasValueType, t, Bindings.STRING);
963                         graph.claimLiteral(newValue, L0.SCLValue_expression, expression, Bindings.STRING);
964                         graph.claim(parentResource, predicateResource, newValue);
965                 } else {
966                         if(hasExpression) {
967                                 graph.claimLiteral(value, L0.SCLValue_expression, expression, Bindings.STRING);
968                         } else {
969                                 Resource newValue = graph.newResource();
970                                 graph.claim(newValue, L0.InstanceOf, expressionValueType);
971                                 graph.claimLiteral(newValue, L0.HasValueType, t, Bindings.STRING);
972                                 graph.claimLiteral(newValue, L0.SCLValue_expression, expression, Bindings.STRING);
973                                 graph.deny(parentResource, predicateResource);
974                                 graph.claim(parentResource, predicateResource, newValue);
975                         }
976                 }
977
978         }
979
980         public static void clearExpression(WriteGraph graph, Variable property, Resource expressionValueType) throws DatabaseException {
981
982                 Resource object = property.getPossibleRepresents(graph);
983                 if(object != null) {
984                         boolean hasExpression = graph.isInstanceOf(object, expressionValueType);
985                         if(hasExpression) {
986                                 // There was an expression and now we go back to a value
987                                 Resource subject = property.getParent(graph).getPossibleRepresents(graph);
988                                 if(subject != null) {
989                                         Resource predicate = property.getPossiblePredicateResource(graph);
990                                         if(predicate != null) {
991                                                 graph.deny(subject, predicate, object);
992                                                 RemoverUtil.remove(graph, object);
993                                         }
994                                 }
995                         }
996                 }
997
998         }
999
1000         public static boolean setOrClearExpression(WriteGraph graph, Variable property, String text, Resource expressionValueType) throws DatabaseException {
1001
1002                 if(text.startsWith("=")) {
1003                         setExpression(graph, property, text, expressionValueType);
1004                         return true;
1005                 }
1006
1007                 clearExpression(graph, property, expressionValueType);
1008
1009                 return false;
1010
1011         }
1012
1013         public static void setValueAsString(WriteGraph graph, Variable property, String text, Resource expressionValueType) throws DatabaseException {
1014
1015                 try {
1016
1017                         if (setOrClearExpression(graph, property, text, expressionValueType))
1018                                 return;
1019
1020                         Object value = text;
1021                         Datatype type = property.getPossibleDatatype(graph);
1022                         if (type != null) {
1023
1024                                 Binding binding = Bindings.getBinding(type);
1025
1026                                 if (binding instanceof StringBinding) {
1027
1028                                         if (binding instanceof MutableStringBinding)
1029                                                 value = new MutableString(text);
1030                                         else
1031                                                 value = text;
1032
1033                                 } else {
1034
1035                                         if (binding instanceof NumberBinding) {
1036                                                 text = text.replace(",", ".");
1037                                         }
1038
1039                                         value = binding.parseValue(text, new DataValueRepository());
1040
1041                                 }
1042
1043                                 property.setValue(graph, value, binding);
1044
1045                         } else {
1046
1047                                 property.setValue(graph, value);
1048
1049                         }
1050
1051                         // Add a comment to metadata.
1052                         CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
1053                         graph.addMetadata(cm.add("Set value " + ObjectUtils.toString(value)));
1054
1055                 } catch (DataTypeSyntaxError e) {
1056                         throw new DatabaseException(e);
1057                 } catch (BindingException e) {
1058                         throw new DatabaseException(e);
1059                 }
1060
1061         }
1062
1063
1064     public static String queryDebugSupport(String query) {
1065         Session session = SimanticsInternal.getSession();
1066         DebugSupport ds = session.getService(DebugSupport.class);
1067         return ds.query(session, "exec " + query);
1068     }
1069
1070     public static String queryListSupport (String query) {
1071         Session session = SimanticsInternal.getSession();
1072         DebugSupport ds = session.getService(DebugSupport.class);
1073         return ds.query(session, "list " + query);
1074     }
1075
1076     final public static Function1<Resource,Resource> resourceCluster = new FunctionImpl1<Resource, Resource>() {
1077                 @Override
1078                 public Resource apply(Resource p0) {
1079                         return p0;
1080                 }
1081         };
1082
1083         public static void sort(ReadGraph graph, List<Resource> collection) {
1084         CollectionSupport cos = graph.getService(CollectionSupport.class);
1085         cos.sort(collection);
1086         }
1087
1088         public static List<Resource> sortByCluster(ReadGraph graph, Collection<Resource> collection) {
1089         CollectionSupport cos = graph.getService(CollectionSupport.class);
1090         return cos.asSortedList(collection);
1091         }
1092
1093         public static List<Object> sortByCluster(final ReadGraph graph, List<Object> list, final Function1<Object,Resource> fn) {
1094         final ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1095         ArrayList<Object> result = new ArrayList<Object>(list);
1096         Collections.sort(result, new Comparator<Object>() {
1097
1098                         @Override
1099                         public int compare(Object o1, Object o2) {
1100                                 Resource r1 = fn.apply(o1);
1101                                 Resource r2 = fn.apply(o2);
1102                                 long l1 = cs.getCluster(r1);
1103                                 long l2 = cs.getCluster(r2);
1104                                 if(l1 < l2) return -1;
1105                                 else if (l1 > l2) return 1;
1106                                 else return 0;
1107                         }
1108
1109         });
1110         return result;
1111     }
1112
1113     public static <T> List<T> sortByClusterT(final ReadGraph graph, Collection<T> list, final Function1<T,Resource> fn) {
1114         final ClusteringSupport cs = graph.getService(ClusteringSupport.class);
1115         ArrayList<T> result = new ArrayList<T>(list);
1116         Collections.sort(result, new Comparator<Object>() {
1117
1118             @Override
1119             public int compare(Object o1, Object o2) {
1120                 Resource r1 = fn.apply((T)o1);
1121                 Resource r2 = fn.apply((T)o2);
1122                 long l1 = cs.getCluster(r1);
1123                 long l2 = cs.getCluster(r2);
1124                 if(l1 < l2) return -1;
1125                 else if (l1 > l2) return 1;
1126                 else return 0;
1127             }
1128
1129         });
1130         return result;
1131     }
1132
1133     public static void makeSynchronous(ReadGraph graph, boolean value) throws DatabaseException {
1134         graph.setSynchronous(value);
1135     }
1136
1137     public static Set<Resource> listIndexRoots(ReadGraph graph) throws DatabaseException {
1138         
1139         Layer0 L0 = Layer0.getInstance(graph);
1140         
1141                 Set<Resource> indexRoots = new TreeSet<Resource>();
1142                 indexRoots.addAll(Layer0Utils.listOntologies(graph));
1143                 indexRoots.addAll(graph.syncRequest(new ObjectsWithType(SimanticsInternal.getProject(), L0.ConsistsOf, L0.IndexRoot)));
1144                 return indexRoots;
1145
1146     }
1147     
1148     public static List<Resource> listOntologies(ReadGraph graph) throws DatabaseException {
1149         return graph.syncRequest(new OntologiesFromLibrary(graph.getRootLibrary()));
1150     }
1151
1152     public static List<Resource> listGlobalOntologies(ReadGraph graph) throws DatabaseException {
1153         return graph.syncRequest(new GlobalOntologies(graph.getRootLibrary()));
1154     }
1155
1156     public static <T> T applySCL(String module, String function, ReadGraph graph, Object ... args) throws DatabaseException {
1157
1158                 try {
1159                         SCL_GRAPH.set(graph);
1160                         T t = (T)((Function)SCLOsgi.MODULE_REPOSITORY.getValue(module + "/" + function)).applyArray(args);
1161                         SCL_GRAPH.set(null);
1162                         return t;
1163                 } catch (Throwable t) {
1164                         throw new DatabaseException(t);
1165                 }
1166
1167     }
1168
1169     public static boolean isContainerPublished(ReadGraph graph, Variable variable) throws DatabaseException {
1170
1171         Resource indexRoot = graph.syncRequest(new PossibleVariableIndexRoot(variable));
1172         if(indexRoot == null) return false;
1173         Resource represents = variable.getPossibleRepresents(graph);
1174         if(represents != null && represents.equals(indexRoot)) return false;
1175         return isPublished(graph, indexRoot);
1176
1177     }
1178
1179     public static boolean isContainerPublished(ReadGraph graph, Resource resource) throws DatabaseException {
1180
1181         Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(resource));
1182         if(indexRoot == null) return false;
1183         if(resource.equals(indexRoot)) return false;
1184         return isPublished(graph, indexRoot);
1185
1186     }
1187
1188     public static boolean isPublished(ReadGraph graph, Resource resource) throws DatabaseException {
1189
1190         Layer0 L0 = Layer0.getInstance(graph);
1191         Boolean value = graph.getPossibleRelatedValue(resource, L0.Entity_published, Bindings.BOOLEAN);
1192         if(value != null && value) return true;
1193
1194         // This is safety - root should not be published it child is not
1195         Resource root = graph.syncRequest(new PossibleIndexRoot(resource));
1196         if(root != null) {
1197                 value = graph.getPossibleRelatedValue(root, L0.Entity_published, Bindings.BOOLEAN);
1198                 if(value != null && value) return true;
1199         }
1200
1201         return false;
1202
1203     }
1204
1205     private static TransferableGraph1 makeTG(ReadGraph graph, Resource r) throws DatabaseException {
1206
1207         SimanticsClipboardImpl cp = new SimanticsClipboardImpl();
1208         CopyHandler c1 = graph.adapt(r, CopyHandler.class);
1209         c1.copyToClipboard(graph, cp, null);
1210         Collection<Set<Representation>> reps = cp.getContents();
1211         if(reps.size() != 1) return null;
1212         return ClipboardUtils.accept(graph, reps.iterator().next(), SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
1213
1214     }
1215
1216     public static TransferableGraphSource makeTGSource(ReadGraph graph, Resource r) throws DatabaseException {
1217
1218         SimanticsClipboardImpl cp = new SimanticsClipboardImpl();
1219         CopyHandler c1 = graph.adapt(r, CopyHandler.class);
1220         c1.copyToClipboard(graph, cp, null);
1221         Collection<Set<Representation>> reps = cp.getContents();
1222         if(reps.size() != 1) return null;
1223         return ClipboardUtils.accept(graph, reps.iterator().next(), SimanticsKeys.KEY_TRANSFERABLE_GRAPH_SOURCE);
1224
1225     }
1226
1227     /*
1228      * Modifies target to resemble source.
1229      */
1230     public static boolean merge(WriteGraph graph, Resource source, Resource target) throws DatabaseException {
1231
1232         TransferableGraphSource tgs1 = makeTGSource(graph, target);
1233         TransferableGraph1 tg1 = TransferableGraphs.create(graph, tgs1);
1234         TransferableGraph1 tg2 = makeTG(graph, source);
1235
1236         GraphRefactoringUtils.fixIncorrectRoot(tg1.identities);
1237         GraphRefactoringUtils.fixIncorrectRoot(tg2.identities);
1238
1239         ModelTransferableGraphSource mtgs = (ModelTransferableGraphSource)tgs1;
1240
1241                 Diff diff = new Diff(tg1, tg2);
1242                 TransferableGraphDelta1 delta = diff.diff();
1243
1244                 long[] oldResources = mtgs.getResourceArray(graph);
1245                 if(TransferableGraphs.hasChanges(graph, oldResources, delta)) {
1246                         TransferableGraphs.applyDelta(graph, mtgs.getResourceArray(graph), delta);
1247                         return true;
1248                 } else {
1249                         return false;
1250                 }
1251
1252     }
1253
1254     public static Resource inferLiteralTypeFromString(ReadGraph graph, String text) {
1255         return Layer0.getInstance(graph).String;
1256     }
1257
1258     public static void emptyTrashBin() throws ServiceException {
1259         emptyTrashBin(new NullProgressMonitor());
1260     }
1261
1262     public static void emptyTrashBin(IProgressMonitor monitor) throws ServiceException {
1263         emptyTrashBin(monitor, SimanticsInternal.getSession(), SimanticsInternal.getProject());
1264     }
1265
1266     public static void emptyTrashBin(final IProgressMonitor monitor, Session session, final Resource project)
1267             throws ServiceException {
1268         final SubMonitor mon = SubMonitor.convert(monitor, "Emptying Trash Bin...", 10000);
1269         try {
1270             ArrayList<Resource> unhandled = new ArrayList<Resource>();
1271             session.syncRequest(new DelayedWriteRequest() {
1272                 @Override
1273                 public void perform(WriteGraph graph) throws DatabaseException {
1274                     Layer0Utils.setDependenciesIndexingDisabled(graph, true);
1275                     Layer0 L0 = Layer0.getInstance(graph);
1276                     Layer0X L0X = Layer0X.getInstance(graph);
1277                     Resource parent = graph.getSingleObject(project, L0.PartOf);
1278                     Resource trashBin = Layer0Utils.getPossibleChild(graph, parent, "TrashBin");
1279                     Collection<Resource> trashes = trashBin != null ? graph.getObjects(trashBin, L0.ConsistsOf)
1280                             : Collections.<Resource> emptyList();
1281                     if (trashes.isEmpty())
1282                         throw new CancelTransactionException();
1283                     mon.setWorkRemaining((2 + trashes.size()) * 1000);
1284                     for (Resource trash : trashes) {
1285                         if (mon.isCanceled())
1286                             throw new CancelTransactionException();
1287                         mon.subTask(NameUtils.getSafeName(graph, trash));
1288                         boolean isIndexRoot = graph.isInstanceOf(trash, L0.IndexRoot);
1289                         TGRemover remo = new TGRemover(mon.newChild(1000, SubMonitor.SUPPRESS_ALL_LABELS), trash);
1290                         try {
1291                             remo.remove(graph);
1292                             unhandled.addAll(remo.getRoots());
1293                         } catch (DatabaseException e) {
1294                             // Something went wrong - try to remove this later
1295                             // with EntityRemover
1296                             unhandled.add(trash);
1297                         }
1298                         if (isIndexRoot) {
1299                             // TODO: this should be an utility
1300                             GenericRelationIndex index = graph.adapt(L0X.DependenciesRelation,
1301                                     GenericRelationIndex.class);
1302                             IndexedRelations ir = graph.getService(IndexedRelations.class);
1303                             // Deletes index files
1304                             ir.reset(null, graph, L0X.DependenciesRelation, trash);
1305                             // Notifies DB listeners
1306                             index.reset(graph, trash);
1307                         }
1308                     }
1309                     if (mon.isCanceled())
1310                         throw new CancelTransactionException();
1311                     mon.subTask("Committing Changes");
1312                     mon.newChild(1000);
1313                 }
1314             });
1315
1316             session.syncRequest(new WriteRequest() {
1317                 @Override
1318                 public void perform(WriteGraph graph) throws DatabaseException {
1319                     for (Resource r : unhandled)
1320                         EntityRemover.remove(graph, r);
1321                 }
1322             });
1323
1324             if (mon.isCanceled())
1325                 return;
1326             mon.subTask("Purging Database");
1327             mon.newChild(1000);
1328             purgeDatabase(monitor, session);
1329         } catch (CancelTransactionException e) {
1330             // Ignore.
1331         } catch (DatabaseException e) {
1332             throw new ServiceException(e);
1333         }
1334     }
1335
1336     public static void purgeDatabase() throws ServiceException {
1337         purgeDatabase(new NullProgressMonitor());
1338     }
1339
1340     public static void purgeDatabase(final IProgressMonitor monitor) throws ServiceException {
1341         purgeDatabase(monitor, SimanticsInternal.getSession());
1342     }
1343
1344     public static void purgeDatabase(final IProgressMonitor monitor, Session session) throws ServiceException {
1345         try {
1346                 XSupport xs = session.getService(XSupport.class);
1347                 xs.purge();
1348         } catch (DatabaseException e) {
1349                 throw new ServiceException(e);
1350         }
1351     }
1352
1353     public static Resource getSingleDomainOf(ReadGraph graph, Resource type, Resource target) throws DatabaseException {
1354         Resource result = null;
1355         for(Resource candidate : getDomainOf(graph, type).values()) {
1356                 if(graph.isInstanceOf(candidate, target)) {
1357                         if(result != null) throw new DatabaseException("Multiple relations found for target " + graph.getURI(target) + " in type " + graph.getURI(type));
1358                         else result = candidate;
1359                 }
1360         }
1361         if(result == null) throw new DatabaseException("Multiple relations found for target " + graph.getURI(target) + " in type " + graph.getURI(type));
1362         return result;
1363     }
1364
1365     public static Map<String, Resource> getDomainOf(ReadGraph graph, Resource type) throws DatabaseException {
1366         CollectionSupport cs = graph.getService(CollectionSupport.class);
1367         Map<String, Resource> result = cs.createObjectResourceMap(String.class);
1368         Layer0 L0 = Layer0.getInstance(graph);
1369         for(Resource r : graph.getObjects(type, L0.DomainOf)) {
1370                 String name = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING);
1371                 if(name != null) result.put(name, r);
1372         }
1373         for(Resource t : graph.getSupertypes(type)) {
1374                 for(Resource r : graph.getObjects(t, L0.DomainOf)) {
1375                         String name = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING);
1376                         if(name != null) result.put(name, r);
1377                 }
1378         }
1379         return result;
1380     }
1381
1382     public static Resource possibleObjectForType(ReadGraph graph, Resource type, Resource relation) throws DatabaseException {
1383         PropertyInfo pi = graph.syncRequest(new PropertyInfoRequest(relation));
1384         return possibleObjectForType(graph, type, relation, pi.isFunctional);
1385     }
1386
1387     public static Resource possibleObjectForType(ReadGraph graph, Resource type, Resource relation, boolean functional) throws DatabaseException {
1388         if(functional) {
1389             Layer0 L0 = Layer0.getInstance(graph);
1390             Resource result = graph.getPossibleObject(type, relation);
1391             if(result != null)
1392                 return result;
1393             for(Resource su : graph.getObjects(L0.Inherits, type)) {
1394                 Resource r = possibleObjectForType(graph, su, relation, functional);
1395                 if(r != null) {
1396                     if(result != null)
1397                         return null;
1398                     result = r;
1399                 }
1400             }
1401             return result;
1402         } else {
1403             Set<Resource> found = objectsForTypeNonFunctional(graph, type, relation, new HashSet<>());
1404             return found.size() == 1 ? found.iterator().next() : null;
1405         }
1406     }
1407
1408     private static Set<Resource> objectsForTypeNonFunctional(ReadGraph graph, Resource type, Resource relation, Set<Resource> found) throws DatabaseException {
1409         Layer0 L0 = Layer0.getInstance(graph);
1410         found.addAll(graph.getObjects(type, relation));
1411         for(Resource su : graph.getObjects(L0.Inherits, type)) {
1412             objectsForTypeNonFunctional(graph, su, relation, found);
1413         }
1414         return found;
1415     }
1416
1417     public static Resource getPossiblePredicateByNameFromType(ReadGraph graph, Resource type, String name) throws DatabaseException {
1418         Map<String,Resource> domain = getDomainOf(graph, type);
1419         return domain.get(name); 
1420     }
1421     
1422     public static Resource getPossiblePredicateByName(ReadGraph graph, Resource instance, String predicateName) throws DatabaseException {
1423         for(Resource type : graph.getPrincipalTypes(instance)) {
1424                 Map<String, Resource> domainOf = getDomainOf(graph, type);
1425                 Resource predicate = domainOf.get(predicateName);
1426                 if(predicate != null) return predicate;
1427         }
1428         return null;
1429     }
1430     
1431     public static Resource getPossiblePredicateByLabel(ReadGraph graph, Resource instance, String predicateName) throws DatabaseException {
1432         Layer0 L0 = Layer0.getInstance(graph);
1433         for(Resource type : graph.getPrincipalTypes(instance)) {
1434                 Map<String, Resource> domainOf = getDomainOf(graph, type);
1435                 for(Resource r : domainOf.values()) {
1436                         String label = graph.getPossibleRelatedValue(r, L0.HasLabel, Bindings.STRING);
1437                         if(predicateName.equals(label))
1438                                 return r;
1439                 }
1440         }
1441         return null;
1442     }
1443     
1444     public static void claimLiteralDataboard(WriteGraph graph, Resource container, Resource property, String valueText) throws DatabaseException {
1445
1446         try {
1447                 PropertyInfo pi = graph.syncRequest(new PropertyInfoRequest(property));
1448                 if(pi.literalRange == null) throw new DatabaseException("No suitable literal type defined as range for property.");
1449                 if(pi.defaultBinding == null) throw new DatabaseException("No suitable default binding for property.");
1450                         Object value = pi.defaultBinding.parseValue(valueText, new DataValueRepository());
1451                         graph.claimLiteral(container, property, pi.literalRange, value, pi.defaultBinding);
1452                 } catch (DataTypeSyntaxError e) {
1453                         throw new DatabaseException(e);
1454                 } catch (BindingException e) {
1455                         throw new DatabaseException(e);
1456                 }
1457         
1458     }
1459
1460     public static String prettyPrintResource(ReadGraph graph, Resource resource, boolean ignoreIdentifiers) throws Exception {
1461         TransferableGraphSource source = makeTGSource(graph, resource);
1462         TransferableGraph1 tg = TransferableGraphs.create(graph, source);
1463         GraphRefactoringUtils.fixOntologyExport(tg);
1464         System.out.println("Printing resoure " + graph.getURI(resource));
1465         return PrettyPrintTG.print(tg, ignoreIdentifiers);
1466     }
1467
1468     /**
1469      * Adds a random {@link GUID} as a value for <code>L0.identifier</code>
1470      * 
1471      * @param graph
1472      * @param component
1473      *            for which the identifier is added
1474      * @param add
1475      *            <code>true</code> to invoke addLiteral, <code>false</code> to
1476      *            invoke claimLiteral
1477      * @throws DatabaseException
1478      */
1479     public static void claimNewIdentifier(WriteGraph graph, Resource component, boolean add) throws DatabaseException {
1480         Layer0 L0 = Layer0.getInstance(graph);
1481         GUID guid = GUID.random();
1482         if (add)
1483             graph.addLiteral(component, L0.identifier, L0.identifier_Inverse, L0.GUID, guid, GUID.BINDING);
1484         else
1485             graph.claimLiteral(component, L0.identifier, L0.identifier_Inverse, L0.GUID, guid, GUID.BINDING);
1486     }
1487
1488     /**
1489      * Sets a new random unique identifier for the specified entity if it already
1490      * has an identifier. If the entity does not have a previous identifier, nothing
1491      * is done.
1492      * 
1493      * @param graph
1494      * @param entity
1495      *            for which the identifier is added
1496      * @return <code>true</code> if the identifier was renewed, <code>false</code>
1497      *         otherwise
1498      * @throws DatabaseException
1499      * @see {@link #claimNewIdentifier(WriteGraph, Resource, boolean)}
1500      */
1501     public static boolean renewIdentifier(WriteGraph graph, Resource entity) throws DatabaseException {
1502         Layer0 L0 = Layer0.getInstance(graph);
1503         Statement stm = graph.getPossibleStatement(entity, L0.identifier);
1504         if (stm != null) {
1505             graph.claimValue(stm.getObject(), GUID.random(), GUID.BINDING);
1506             return true;
1507         }
1508         return false;
1509     }
1510
1511     public static void addMetadataListener(ChangeListener listener) {
1512         SimanticsInternal.getSession().getService(GraphChangeListenerSupport.class).addMetadataListener(listener);
1513     }
1514
1515     public static void removeMetadataListener(ChangeListener listener) {
1516         SimanticsInternal.getSession().getService(GraphChangeListenerSupport.class).removeMetadataListener(listener);
1517     }
1518
1519 }