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