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