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