]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.common/src/org/simantics/db/common/utils/NameUtils.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.db.common / src / org / simantics / db / common / utils / NameUtils.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in 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.common.utils;
13
14 import java.nio.CharBuffer;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Collection;
18 import java.util.Comparator;
19 import java.util.Formatter;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Locale;
23 import java.util.Set;
24 import java.util.TreeSet;
25
26 import org.simantics.databoard.Bindings;
27 import org.simantics.databoard.binding.mutable.Variant;
28 import org.simantics.databoard.util.binary.RandomAccessBinary;
29 import org.simantics.db.ReadGraph;
30 import org.simantics.db.Resource;
31 import org.simantics.db.Statement;
32 import org.simantics.db.exception.BindingException;
33 import org.simantics.db.exception.DatabaseException;
34 import org.simantics.db.exception.ServiceException;
35 import org.simantics.db.exception.ValidationException;
36 import org.simantics.layer0.Layer0;
37 import org.simantics.utils.datastructures.MapList;
38
39
40 public final class NameUtils {
41
42         public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource propertyToList, Set<String> result, MapList<String,String> reservation) throws DatabaseException {
43                 
44                 if (proposition == null)
45                         throw new NullPointerException("null proposition");
46                 if (propertyToList == null)
47                         throw new NullPointerException("null property to list");
48                 if (result == null)
49                         result = new HashSet<String>();
50                 
51                 if (reservation != null) {
52                         String possibleURI = g.getPossibleURI(container);
53                         if(possibleURI != null) {
54                                 result.addAll(reservation.getValuesUnsafe(possibleURI));
55                         }
56                 }
57                 
58                 for (Resource r : g.getObjects(container, consistRelation)) {
59                         String name = g.getPossibleRelatedValue(r, propertyToList);
60                         if (name != null && name.startsWith(proposition))
61                                 result.add(Versions.getBaseName(name));
62                 }
63                 
64                 return result;
65                 
66         }
67
68         public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource propertyToList, Set<String> result) throws DatabaseException {
69                 return findReservedNames(g, proposition, container, consistRelation, propertyToList, result, null);
70         }
71
72         public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation, Set<String> result) throws DatabaseException {
73                 Layer0 L0 = Layer0.getInstance(g);
74                 return findReservedNames(g, proposition, container, consistRelation, L0.HasName, result);
75         }
76
77         public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation) throws DatabaseException {
78                 Set<String> result = new HashSet<String>();
79                 findReservedNames(g, proposition, container, consistRelation, result);
80                 return result;
81         }
82
83         public static String findFreshName(ReadGraph g, String proposition, Resource container) throws DatabaseException {
84                 Layer0 b = Layer0.getInstance(g);
85                 return findFreshName(g, proposition, container, b.ConsistsOf);
86         }
87
88         public static String findFreshLabel(ReadGraph g, String proposition, Resource container) throws DatabaseException {
89                 Layer0 L0 = Layer0.getInstance(g);
90                 return _findFreshName(g, proposition, container, L0.ConsistsOf, L0.HasLabel, " ");
91         }
92
93         public static String findFreshEscapedName(ReadGraph g, String proposition, Resource container) throws DatabaseException {
94                 Layer0 b = Layer0.getInstance(g);
95                 return findFreshEscapedName(g, proposition, container, b.ConsistsOf);
96         }
97
98         public static final Comparator<Object> STRING_CHARBUFFER_COMPARATOR = new Comparator<Object>(){
99                 @Override
100                 public int compare(Object o1, Object o2) {
101                         String s1 = null;
102                         String s2 = null;
103                         if (o1 instanceof String)
104                                 s1 = (String) o1;
105                         if (o2 instanceof String)
106                                 s2 = (String) o2;
107                         if (s1 != null && s2 != null)
108                                 return s1.compareTo((String) o2);
109
110                         if (s1 == null && s2 == null)
111                                 return 0;
112
113                         if (s1 == null && (o1 instanceof CharBuffer))
114                                 return -compare(s2, (CharBuffer) o1);
115                         if (s2 == null && (o2 instanceof CharBuffer))
116                                 return compare(s1, (CharBuffer) o2);
117
118                         return 0;
119                 }
120                 int compare(String s, CharBuffer buf) {
121                         int len1 = s.length();
122                         int len2 = buf.position();
123                         int n = Math.min(len1, len2);
124                         int k = 0;
125                         while (k < n) {
126                                 char c1 = s.charAt(k);
127                                 char c2 = buf.get(k);
128                                 if (c1 != c2) {
129                                         return c1 - c2;
130                                 }
131                                 k++;
132                         }
133                         return len1 - len2;
134                 }
135         };
136
137         public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation) throws DatabaseException {
138                 return _findFreshName(g, proposition, container, consistRelation, " ");
139         }
140
141         public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, String nameFormat) throws DatabaseException {
142                 return findFreshName(g, proposition, container, consistRelation, Layer0.getInstance(g).HasName, nameFormat);
143         }
144
145         public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource nameProperty, String nameFormat) throws DatabaseException {
146                 Set<String> reservedNames = new TreeSet<String>(STRING_CHARBUFFER_COMPARATOR);
147                 findReservedNames(g, proposition, container, consistRelation, nameProperty, reservedNames);
148                 return findFreshNameFormatted(proposition, reservedNames, nameFormat);
149         }
150
151         public static String findFreshEscapedName(ReadGraph g, String proposition, Resource container, Resource consistRelation) throws DatabaseException {
152                 return _findFreshName(g, proposition, container, consistRelation, "_");
153         }
154         
155         /**
156          * Find a fresh name using the specified name proposition among an
157          * externally specified set of names using suffix numbers.
158          * 
159          * @param g
160          * @param proposition
161          * @param reservedNames
162          * @param numberSeparator
163          * @return
164          * @throws DatabaseException
165          */
166         public static String findFreshName(ReadGraph g, String proposition, Set<String> reservedNames, String numberSeparator) throws DatabaseException {
167                 // Trying to optimize away unnecessary allocation of new String instances
168                 // when looking for fresh names for objects.
169                 if (!reservedNames.contains(proposition))
170                         return proposition;
171
172                 // Need to make sure that the set is using the correct comparator.
173                 Set<String> used = new TreeSet<String>(STRING_CHARBUFFER_COMPARATOR);
174                 used.addAll(reservedNames);
175                 return findFreshNameNumbered(proposition, used, numberSeparator);
176         }
177
178         public static String findFreshInstanceName(ReadGraph g, Resource type, Resource container) throws DatabaseException {
179                 String typeName = g.getPossibleRelatedValue(type, Layer0.getInstance(g).HasName);
180                 if (typeName == null)
181                         typeName = "Entity";
182                 return findFreshName(g, typeName, container);
183         }
184
185         public static String findFreshInstanceName(ReadGraph g, Resource type, Resource container, Resource relation) throws DatabaseException {
186                 String typeName = g.getPossibleRelatedValue(type, Layer0.getInstance(g).HasName);
187                 if (typeName == null)
188                         typeName = "Entity";
189                 return findFreshName(g, typeName, container, relation);
190         }
191
192         private static String _findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, String numberSeparator) throws DatabaseException {
193                 return _findFreshName(g, proposition, container, consistRelation, Layer0.getInstance(g).HasName, numberSeparator);
194         }
195
196         private static String _findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource nameProperty, String numberSeparator) throws DatabaseException {
197                 return findFreshName(g, proposition, container, consistRelation, nameProperty, numberSeparator, null);
198         }
199         
200         public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource nameProperty, String numberSeparator, MapList<String, String> reservation) throws DatabaseException {
201                 Set<String> reservedNames = new TreeSet<String>(STRING_CHARBUFFER_COMPARATOR);
202                 findReservedNames(g, proposition, container, consistRelation, nameProperty, reservedNames, reservation);
203                 return findFreshNameNumbered(proposition, reservedNames, numberSeparator);
204         }
205
206         public static String findFreshNameNumbered(String proposition, Set<String> reservedNames, String numberSeparator) {
207                 // Trying to optimize away unnecessary allocation of new String instances
208                 // when looking for fresh names for objects.
209                 if (!reservedNames.contains(proposition))
210                         return proposition;
211
212                 CharBuffer cb = CharBuffer.allocate(proposition.length() + 10);
213                 cb.append(proposition);
214                 cb.append(numberSeparator);
215                 cb.mark();
216                 int i = reservedNames.size() + 1;
217                 while (true) {
218                         cb.reset();
219                         cb.append(String.valueOf(i));
220                         if (!reservedNames.contains(cb)) {
221                                 // Construct a String from the CharBuffer
222                                 cb.limit(cb.position());
223                                 cb.rewind();
224                                 return cb.toString();
225                         }
226                         ++i;
227                 }
228         }
229
230         public static String findFreshNameFormatted(String proposition, Set<String> reservedNames, String nameFormat) {
231                 if (!reservedNames.contains(proposition))
232                         return proposition;
233
234                 // Trying to optimize away unnecessary allocation of new String instances
235                 // when looking for fresh names for objects.
236                 CharBuffer cb = CharBuffer.allocate(proposition.length() + 10);
237                 cb.mark();
238
239                 @SuppressWarnings("resource")
240                 Formatter formatter = new Formatter(cb, Locale.US);
241
242                 int i = reservedNames.size() + 1;
243                 for (;; ++i) {
244                         cb.reset();
245                         formatter.format(nameFormat, proposition, i);
246                         if (!reservedNames.contains(cb)) {
247                                 // Construct a String from the CharBuffer
248                                 cb.limit(cb.position());
249                                 cb.rewind();
250                                 String result = cb.toString();
251                                 return result;
252                         }
253                 }
254         }
255
256         public static String getSafeName(ReadGraph graph, Resource resource, boolean id) throws ValidationException, ServiceException {
257
258                 if(id && resource != null) {
259                         return getSafeName(graph, resource) + ":$" + resource.getResourceId();
260                 } else {
261                         return getSafeName(graph, resource);
262                 }
263
264         }
265
266         public static String getSafeName(ReadGraph graph, Collection<Resource> rs) throws ValidationException, ServiceException {
267
268                 StringBuilder b = new StringBuilder();
269                 b.append("{");
270                 for(Resource r : rs) {
271                         b.append(getSafeName(graph, r));
272                         b.append(",");
273                 }
274                 b.append("}");
275                 return b.toString();
276
277         }
278
279         public static String getSafeLabel(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {
280                 return getSafeNameInternal(graph, resource, true);
281         }
282
283         public static String getSafeName(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {
284                 return getSafeNameInternal(graph, resource, false);
285         }
286
287         private static Object truncate(Object array) {
288                 if(array instanceof byte[]) {
289                         byte[] bytes = (byte[])array;
290                         if(bytes.length > 100)
291                                 return Arrays.copyOfRange(bytes, 0, 100);
292                 }
293                 return array;
294         }
295
296         public static String getURIOrSafeNameInternal(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {
297                 return getURIOrSafeNameInternal(graph, resource, false);
298         }
299
300         public static String getURIOrSafeNameInternal(ReadGraph graph, Resource resource, boolean tryLabel) throws ValidationException, ServiceException {
301                 if (resource == null) return "null";
302                 String uri = graph.getPossibleURI(resource);
303                 if(uri != null) return uri;
304                 else return getSafeNameInternal(graph, resource, tryLabel);
305         }
306
307         public static long getPossibleValueSize(ReadGraph graph, Resource resource) {
308                 try {
309                         if(graph.hasValue(resource)) {
310                                 RandomAccessBinary rab = graph.getRandomAccessBinary(resource);
311                                 return rab.length();
312                         }
313                 }catch (Exception e) {
314
315                 }
316                 return 0;
317         }
318
319         private static String getSafeNameInternal(ReadGraph graph, Resource resource, boolean tryLabel) throws ValidationException, ServiceException {
320                 if(resource == null) return "null";
321                 Layer0 b = Layer0.getInstance(graph);
322                 if (graph.isInstanceOf(resource, b.Variant)) {
323                         try {
324                                 Variant v = graph.getPossibleValue(resource, Bindings.VARIANT);
325                                 return v.toString();
326                         } catch (BindingException e) {
327                         }
328                 }
329                 List<String> names = new ArrayList<String>(1);
330                 if (tryLabel) {
331                         for(Resource nameResource : graph.getObjects(resource, b.HasLabel)) {
332                                 if(graph.isInstanceOf(nameResource, b.Literal)) {
333                                         Object value = graph.getPossibleValue(nameResource);
334                                         if(value != null) {
335                                                 String s = Literals.literalToString(value);
336                                                 if (!s.isEmpty())
337                                                         names.add(s);
338                                         }
339                                 }
340                         }
341                 }
342                 if (names.isEmpty()) {
343                         for(Resource nameResource : graph.getObjects(resource, b.HasName)) {
344                                 Object value = graph.getPossibleValue(nameResource);
345                                 if(value != null) {
346                                         names.add(Literals.literalToString(value));
347                                 }
348                         }
349                 }
350                 if(!names.isEmpty()) {
351                         if(names.size() == 1)
352                                 return names.get(0);
353                         else {
354                                 StringBuilder bb = new StringBuilder();
355                                 bb.append('[');
356                                 for(int i=0;i<names.size();++i) {
357                                         if(i>0)
358                                                 bb.append(", ");
359                                         bb.append(names.get(i));
360                                 }
361                                 bb.append(']');
362                                 return bb.toString();
363                         }
364                 }
365                 StringBuilder bb = new StringBuilder();
366                 long valueSize = getPossibleValueSize(graph, resource);
367                 //System.err.println("valueSize=" + valueSize);
368                 if(valueSize > 0) {
369                         if(valueSize < 1e6) {
370                                 Object val = graph.getPossibleValue(resource);
371                                 if(val != null) {
372                                         val = truncate(val);
373                                         if(val instanceof double[])
374                                                 bb.append(Arrays.toString((double[])val));
375                                         else if(val instanceof float[])
376                                                 bb.append(Arrays.toString((float[])val));
377                                         else if(val instanceof int[])
378                                                 bb.append(Arrays.toString((int[])val));
379                                         else if(val instanceof boolean[])
380                                                 bb.append(Arrays.toString((boolean[])val));
381                                         else if(val instanceof long[])
382                                                 bb.append(Arrays.toString((long[])val));
383                                         else if(val instanceof byte[])
384                                                 bb.append(Arrays.toString((byte[])val));
385                                         else if(val instanceof String[])
386                                                 bb.append(Arrays.toString((String[])val));
387                                         else
388                                                 bb.append(val);
389                                 } else {
390                                         bb.append('$').append(resource.getResourceId());
391                                 }
392                         } else {
393                                 bb.append('$').append(resource.getResourceId());
394                                 bb.append("[" + valueSize + " bytes of value]");
395                         }
396                 } else {
397                         bb.append('$').append(resource.getResourceId());
398                 }
399                 boolean ok = false;
400                 for(Resource r : graph.getObjects(resource, b.InstanceOf)) {
401                         if(!r.equals(resource))
402                                 bb.append(" : (" + getSafeName(graph, r) + ")");
403                         ok = true;
404                 }
405                 if(!ok) {
406                         for(Resource r : graph.getObjects(resource, b.Inherits)) {
407                                 bb.append(" <T (" + getSafeName(graph, r) + ")");
408                                 ok = true;
409                         }
410                         if(!ok) {
411                                 for(Resource r : graph.getObjects(resource, b.SubrelationOf)) {
412                                         bb.append(" <R (" + getSafeName(graph, r) + ")");
413                                         ok = true;
414                                 }
415                         }
416                 }
417                 return bb.toString();
418         }
419
420         public static String toString(ReadGraph graph, Statement stm) throws DatabaseException {
421                 return getSafeName(graph, stm.getSubject()) + ", " +
422                                 getSafeName(graph, stm.getPredicate()) + ", " +
423                                 getSafeName(graph, stm.getObject());
424         }
425
426         public static String toString(ReadGraph graph, Statement stm, boolean ids) throws DatabaseException {
427                 return getSafeName(graph, stm.getSubject(), ids) + ", " +
428                                 getSafeName(graph, stm.getPredicate(), ids) + ", " +
429                                 getSafeName(graph, stm.getObject(), ids);
430         }
431
432         public static String toIdString(ReadGraph graph, Statement stm) throws DatabaseException {
433                 return stm.getSubject() + ", " + stm.getPredicate() + ", " + stm.getObject();
434         }
435
436         /**
437          * Convert a collection of resources into a String in the same manner as
438          * {@link Arrays#toString(Object[])} does but by consulting
439          * {@link #getSafeName(ReadGraph, Resource)} for each resource.
440          * 
441          * @param g database accessor
442          * @param c the collection of resources to translate to named strings
443          * @return string representation of the resource collection
444          * @throws DatabaseException
445          */
446         public static String toString(ReadGraph g, Collection<Resource> c) throws DatabaseException {
447                 return toString(g, c, false);
448         }
449
450         /**
451          * Convert a collection of resources into a String in the same manner as
452          * {@link Arrays#toString(Object[])} does but by consulting
453          * {@link #getSafeName(ReadGraph, Resource)} for each resource.
454          * 
455          * @param g database accessor
456          * @param c the collection of resources to translate to named strings
457          * @param ids <code>true</code> to print the ID of each resource after its
458          *        name separated by ':'
459          * @return string representation of the resource collection
460          * @throws DatabaseException
461          */
462         public static String toString(ReadGraph g, Collection<Resource> c, boolean ids) throws DatabaseException {
463                 StringBuilder sb = new StringBuilder();
464                 sb.append('[');
465                 boolean first = true;
466                 for (Resource r : c) {
467                         if (!first)
468                                 sb.append(", ");
469                         first = false;
470                         sb.append(getSafeName(g, r, ids));
471                 }
472                 return sb.append(']').toString();
473         }
474
475         /**
476          * @param graph
477          * @param r
478          * @return
479          * @throws DatabaseException
480          */
481         public static String resourcePath(ReadGraph graph, Resource r) throws DatabaseException {
482                 return resourcePath0(graph, r, new StringBuilder(80)).toString();
483         }
484
485         /**
486          * @param graph
487          * @param r
488          * @return
489          * @throws DatabaseException
490          */
491         private static StringBuilder resourcePath0(ReadGraph graph, Resource r, StringBuilder result) throws DatabaseException {
492                 String uri = graph.getPossibleURI(r);
493                 if (uri != null)
494                         return result.append(uri);
495                 Resource owner = null;
496                 try {
497                         owner = CommonDBUtils.getPossibleOwner(graph, r);
498                         if (owner == null)
499                                 return result.append(NameUtils.getSafeName(graph, r));
500                 } catch (DatabaseException e) {
501                         // Owner resource not found by CommonDBUtils.getPossibleOwner.
502                         return result.append(NameUtils.getSafeName(graph, r));
503                 }
504                 // See if there's a statement between r and owner.
505                 Layer0 L0 = Layer0.getInstance(graph);
506                 for (Statement stm : graph.getStatements(owner, L0.IsWeaklyRelatedTo)) {
507                         if (stm.getObject().equals(r)) {
508                                 Resource predicate = stm.getPredicate();
509                                 if (predicate.equals(L0.ConsistsOf)) {
510                                         return resourcePath0(graph, owner, result)
511                                                         .append(" / ")
512                                                         .append(NameUtils.getSafeName(graph, r));
513                                 } else if (graph.isSubrelationOf(predicate, L0.HasProperty)) {
514                                         return resourcePath0(graph, owner, result)
515                                                         .append(" #(")
516                                                         .append(NameUtils.getSafeName(graph, predicate, true))
517                                                         .append(") ")
518                                                         .append(NameUtils.getSafeName(graph, r));
519                                 } else {
520                                         return resourcePath0(graph, owner, result)
521                                                         .append(" -(")
522                                                         .append(NameUtils.getSafeName(graph, predicate, true))
523                                                         .append(")-> ")
524                                                         .append(NameUtils.getSafeName(graph, r));
525                                 }
526                         }
527                 }
528                 return resourcePath0(graph, owner, result)
529                                 .append(" ... ")
530                                 .append(NameUtils.getSafeName(graph, r));
531         }
532
533 }