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