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