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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.db.common.utils;
\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
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
40 public final class NameUtils {
\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
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
49 result = new HashSet<String>();
\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
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
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
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
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
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
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
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
98 public static final Comparator<Object> STRING_CHARBUFFER_COMPARATOR = new Comparator<Object>(){
\r
100 public int compare(Object o1, Object o2) {
\r
103 if (o1 instanceof String)
\r
105 if (o2 instanceof String)
\r
107 if (s1 != null && s2 != null)
\r
108 return s1.compareTo((String) o2);
\r
110 if (s1 == null && s2 == null)
\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
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
126 char c1 = s.charAt(k);
\r
127 char c2 = buf.get(k);
\r
133 return len1 - len2;
\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
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
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
151 public static String findFreshEscapedName(ReadGraph g, String proposition, Resource container, Resource consistRelation) throws DatabaseException {
\r
152 return _findFreshName(g, proposition, container, consistRelation, "_");
\r
156 * Find a fresh name using the specified name proposition among an
\r
157 * externally specified set of names using suffix numbers.
\r
160 * @param proposition
\r
161 * @param reservedNames
\r
162 * @param numberSeparator
\r
164 * @throws DatabaseException
\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
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
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
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
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
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
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
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
212 CharBuffer cb = CharBuffer.allocate(proposition.length() + 10);
\r
213 cb.append(proposition);
\r
214 cb.append(numberSeparator);
\r
216 int i = reservedNames.size() + 1;
\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
224 return cb.toString();
\r
230 public static String findFreshNameFormatted(String proposition, Set<String> reservedNames, String nameFormat) {
\r
231 if (!reservedNames.contains(proposition))
\r
232 return proposition;
\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
239 @SuppressWarnings("resource")
\r
240 Formatter formatter = new Formatter(cb, Locale.US);
\r
242 int i = reservedNames.size() + 1;
\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
250 String result = cb.toString();
\r
256 public static String getSafeName(ReadGraph graph, Resource resource, boolean id) throws ValidationException, ServiceException {
\r
258 if(id && resource != null) {
\r
259 return getSafeName(graph, resource) + ":$" + resource.getResourceId();
\r
261 return getSafeName(graph, resource);
\r
266 public static String getSafeName(ReadGraph graph, Collection<Resource> rs) throws ValidationException, ServiceException {
\r
268 StringBuilder b = new StringBuilder();
\r
270 for(Resource r : rs) {
\r
271 b.append(getSafeName(graph, r));
\r
275 return b.toString();
\r
279 public static String getSafeLabel(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {
\r
280 return getSafeNameInternal(graph, resource, true);
\r
283 public static String getSafeName(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {
\r
284 return getSafeNameInternal(graph, resource, false);
\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
296 public static String getURIOrSafeNameInternal(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {
\r
297 return getURIOrSafeNameInternal(graph, resource, false);
\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
307 public static long getPossibleValueSize(ReadGraph graph, Resource resource) {
\r
309 if(graph.hasValue(resource)) {
\r
310 RandomAccessBinary rab = graph.getRandomAccessBinary(resource);
\r
311 return rab.length();
\r
313 }catch (Exception e) {
\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
324 Variant v = graph.getPossibleValue(resource, Bindings.VARIANT);
\r
325 return v.toString();
\r
326 } catch (BindingException e) {
\r
329 List<String> names = new ArrayList<String>(1);
\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
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
350 if(!names.isEmpty()) {
\r
351 if(names.size() == 1)
\r
352 return names.get(0);
\r
354 StringBuilder bb = new StringBuilder();
\r
356 for(int i=0;i<names.size();++i) {
\r
359 bb.append(names.get(i));
\r
362 return bb.toString();
\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
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
390 bb.append('$').append(resource.getResourceId());
\r
393 bb.append('$').append(resource.getResourceId());
\r
394 bb.append("[" + valueSize + " bytes of value]");
\r
397 bb.append('$').append(resource.getResourceId());
\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
406 for(Resource r : graph.getObjects(resource, b.Inherits)) {
\r
407 bb.append(" <T (" + getSafeName(graph, r) + ")");
\r
411 for(Resource r : graph.getObjects(resource, b.SubrelationOf)) {
\r
412 bb.append(" <R (" + getSafeName(graph, r) + ")");
\r
417 return bb.toString();
\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
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
432 public static String toIdString(ReadGraph graph, Statement stm) throws DatabaseException {
\r
433 return stm.getSubject() + ", " + stm.getPredicate() + ", " + stm.getObject();
\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
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
446 public static String toString(ReadGraph g, Collection<Resource> c) throws DatabaseException {
\r
447 return toString(g, c, false);
\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
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
462 public static String toString(ReadGraph g, Collection<Resource> c, boolean ids) throws DatabaseException {
\r
463 StringBuilder sb = new StringBuilder();
\r
465 boolean first = true;
\r
466 for (Resource r : c) {
\r
470 sb.append(getSafeName(g, r, ids));
\r
472 return sb.append(']').toString();
\r
479 * @throws DatabaseException
\r
481 public static String resourcePath(ReadGraph graph, Resource r) throws DatabaseException {
\r
482 return resourcePath0(graph, r, new StringBuilder(80)).toString();
\r
489 * @throws DatabaseException
\r
491 private static StringBuilder resourcePath0(ReadGraph graph, Resource r, StringBuilder result) throws DatabaseException {
\r
492 String uri = graph.getPossibleURI(r);
\r
494 return result.append(uri);
\r
495 Resource owner = null;
\r
497 owner = CommonDBUtils.getPossibleOwner(graph, r);
\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
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
512 .append(NameUtils.getSafeName(graph, r));
\r
513 } else if (graph.isSubrelationOf(predicate, L0.HasProperty)) {
\r
514 return resourcePath0(graph, owner, result)
\r
516 .append(NameUtils.getSafeName(graph, predicate, true))
\r
518 .append(NameUtils.getSafeName(graph, r));
\r
520 return resourcePath0(graph, owner, result)
\r
522 .append(NameUtils.getSafeName(graph, predicate, true))
\r
524 .append(NameUtils.getSafeName(graph, r));
\r
528 return resourcePath0(graph, owner, result)
\r
530 .append(NameUtils.getSafeName(graph, r));
\r