]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.common/src/org/simantics/db/common/utils/NameUtils.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.db.common / src / org / simantics / db / common / utils / NameUtils.java
index 424e76fc7a6fd774172097ba77091b622343b767..be1423db5030e770f5e0043533d5ac127e3e0114 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.db.common.utils;\r
-\r
-import java.nio.CharBuffer;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.Comparator;\r
-import java.util.Formatter;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Locale;\r
-import java.util.Set;\r
-import java.util.TreeSet;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.binding.mutable.Variant;\r
-import org.simantics.databoard.util.binary.RandomAccessBinary;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Statement;\r
-import org.simantics.db.exception.BindingException;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.ServiceException;\r
-import org.simantics.db.exception.ValidationException;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.utils.datastructures.MapList;\r
-\r
-\r
-public final class NameUtils {\r
-\r
-       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
-               \r
-               if (proposition == null)\r
-                       throw new NullPointerException("null proposition");\r
-               if (propertyToList == null)\r
-                       throw new NullPointerException("null property to list");\r
-               if (result == null)\r
-                       result = new HashSet<String>();\r
-               \r
-               if (reservation != null) {\r
-                       String possibleURI = g.getPossibleURI(container);\r
-                       if(possibleURI != null) {\r
-                               result.addAll(reservation.getValuesUnsafe(possibleURI));\r
-                       }\r
-               }\r
-               \r
-               for (Resource r : g.getObjects(container, consistRelation)) {\r
-                       String name = g.getPossibleRelatedValue(r, propertyToList);\r
-                       if (name != null && name.startsWith(proposition))\r
-                               result.add(Versions.getBaseName(name));\r
-               }\r
-               \r
-               return result;\r
-               \r
-       }\r
-\r
-       public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource propertyToList, Set<String> result) throws DatabaseException {\r
-               return findReservedNames(g, proposition, container, consistRelation, propertyToList, result, null);\r
-       }\r
-\r
-       public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation, Set<String> result) throws DatabaseException {\r
-               Layer0 L0 = Layer0.getInstance(g);\r
-               return findReservedNames(g, proposition, container, consistRelation, L0.HasName, result);\r
-       }\r
-\r
-       public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation) throws DatabaseException {\r
-               Set<String> result = new HashSet<String>();\r
-               findReservedNames(g, proposition, container, consistRelation, result);\r
-               return result;\r
-       }\r
-\r
-       public static String findFreshName(ReadGraph g, String proposition, Resource container) throws DatabaseException {\r
-               Layer0 b = Layer0.getInstance(g);\r
-               return findFreshName(g, proposition, container, b.ConsistsOf);\r
-       }\r
-\r
-       public static String findFreshLabel(ReadGraph g, String proposition, Resource container) throws DatabaseException {\r
-               Layer0 L0 = Layer0.getInstance(g);\r
-               return _findFreshName(g, proposition, container, L0.ConsistsOf, L0.HasLabel, " ");\r
-       }\r
-\r
-       public static String findFreshEscapedName(ReadGraph g, String proposition, Resource container) throws DatabaseException {\r
-               Layer0 b = Layer0.getInstance(g);\r
-               return findFreshEscapedName(g, proposition, container, b.ConsistsOf);\r
-       }\r
-\r
-       public static final Comparator<Object> STRING_CHARBUFFER_COMPARATOR = new Comparator<Object>(){\r
-               @Override\r
-               public int compare(Object o1, Object o2) {\r
-                       String s1 = null;\r
-                       String s2 = null;\r
-                       if (o1 instanceof String)\r
-                               s1 = (String) o1;\r
-                       if (o2 instanceof String)\r
-                               s2 = (String) o2;\r
-                       if (s1 != null && s2 != null)\r
-                               return s1.compareTo((String) o2);\r
-\r
-                       if (s1 == null && s2 == null)\r
-                               return 0;\r
-\r
-                       if (s1 == null && (o1 instanceof CharBuffer))\r
-                               return -compare(s2, (CharBuffer) o1);\r
-                       if (s2 == null && (o2 instanceof CharBuffer))\r
-                               return compare(s1, (CharBuffer) o2);\r
-\r
-                       return 0;\r
-               }\r
-               int compare(String s, CharBuffer buf) {\r
-                       int len1 = s.length();\r
-                       int len2 = buf.position();\r
-                       int n = Math.min(len1, len2);\r
-                       int k = 0;\r
-                       while (k < n) {\r
-                               char c1 = s.charAt(k);\r
-                               char c2 = buf.get(k);\r
-                               if (c1 != c2) {\r
-                                       return c1 - c2;\r
-                               }\r
-                               k++;\r
-                       }\r
-                       return len1 - len2;\r
-               }\r
-       };\r
-\r
-       public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation) throws DatabaseException {\r
-               return _findFreshName(g, proposition, container, consistRelation, " ");\r
-       }\r
-\r
-       public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, String nameFormat) throws DatabaseException {\r
-               return findFreshName(g, proposition, container, consistRelation, Layer0.getInstance(g).HasName, nameFormat);\r
-       }\r
-\r
-       public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource nameProperty, String nameFormat) throws DatabaseException {\r
-               Set<String> reservedNames = new TreeSet<String>(STRING_CHARBUFFER_COMPARATOR);\r
-               findReservedNames(g, proposition, container, consistRelation, nameProperty, reservedNames);\r
-               return findFreshNameFormatted(proposition, reservedNames, nameFormat);\r
-       }\r
-\r
-       public static String findFreshEscapedName(ReadGraph g, String proposition, Resource container, Resource consistRelation) throws DatabaseException {\r
-               return _findFreshName(g, proposition, container, consistRelation, "_");\r
-       }\r
-       \r
-       /**\r
-        * Find a fresh name using the specified name proposition among an\r
-        * externally specified set of names using suffix numbers.\r
-        * \r
-        * @param g\r
-        * @param proposition\r
-        * @param reservedNames\r
-        * @param numberSeparator\r
-        * @return\r
-        * @throws DatabaseException\r
-        */\r
-       public static String findFreshName(ReadGraph g, String proposition, Set<String> reservedNames, String numberSeparator) throws DatabaseException {\r
-               // Trying to optimize away unnecessary allocation of new String instances\r
-               // when looking for fresh names for objects.\r
-               if (!reservedNames.contains(proposition))\r
-                       return proposition;\r
-\r
-               // Need to make sure that the set is using the correct comparator.\r
-               Set<String> used = new TreeSet<String>(STRING_CHARBUFFER_COMPARATOR);\r
-               used.addAll(reservedNames);\r
-               return findFreshNameNumbered(proposition, used, numberSeparator);\r
-       }\r
-\r
-       public static String findFreshInstanceName(ReadGraph g, Resource type, Resource container) throws DatabaseException {\r
-               String typeName = g.getPossibleRelatedValue(type, Layer0.getInstance(g).HasName);\r
-               if (typeName == null)\r
-                       typeName = "Entity";\r
-               return findFreshName(g, typeName, container);\r
-       }\r
-\r
-       public static String findFreshInstanceName(ReadGraph g, Resource type, Resource container, Resource relation) throws DatabaseException {\r
-               String typeName = g.getPossibleRelatedValue(type, Layer0.getInstance(g).HasName);\r
-               if (typeName == null)\r
-                       typeName = "Entity";\r
-               return findFreshName(g, typeName, container, relation);\r
-       }\r
-\r
-       private static String _findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, String numberSeparator) throws DatabaseException {\r
-               return _findFreshName(g, proposition, container, consistRelation, Layer0.getInstance(g).HasName, numberSeparator);\r
-       }\r
-\r
-       private static String _findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource nameProperty, String numberSeparator) throws DatabaseException {\r
-               return findFreshName(g, proposition, container, consistRelation, nameProperty, numberSeparator, null);\r
-       }\r
-       \r
-       public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource nameProperty, String numberSeparator, MapList<String, String> reservation) throws DatabaseException {\r
-               Set<String> reservedNames = new TreeSet<String>(STRING_CHARBUFFER_COMPARATOR);\r
-               findReservedNames(g, proposition, container, consistRelation, nameProperty, reservedNames, reservation);\r
-               return findFreshNameNumbered(proposition, reservedNames, numberSeparator);\r
-       }\r
-\r
-       public static String findFreshNameNumbered(String proposition, Set<String> reservedNames, String numberSeparator) {\r
-               // Trying to optimize away unnecessary allocation of new String instances\r
-               // when looking for fresh names for objects.\r
-               if (!reservedNames.contains(proposition))\r
-                       return proposition;\r
-\r
-               CharBuffer cb = CharBuffer.allocate(proposition.length() + 10);\r
-               cb.append(proposition);\r
-               cb.append(numberSeparator);\r
-               cb.mark();\r
-               int i = reservedNames.size() + 1;\r
-               while (true) {\r
-                       cb.reset();\r
-                       cb.append(String.valueOf(i));\r
-                       if (!reservedNames.contains(cb)) {\r
-                               // Construct a String from the CharBuffer\r
-                               cb.limit(cb.position());\r
-                               cb.rewind();\r
-                               return cb.toString();\r
-                       }\r
-                       ++i;\r
-               }\r
-       }\r
-\r
-       public static String findFreshNameFormatted(String proposition, Set<String> reservedNames, String nameFormat) {\r
-               if (!reservedNames.contains(proposition))\r
-                       return proposition;\r
-\r
-               // Trying to optimize away unnecessary allocation of new String instances\r
-               // when looking for fresh names for objects.\r
-               CharBuffer cb = CharBuffer.allocate(proposition.length() + 10);\r
-               cb.mark();\r
-\r
-               @SuppressWarnings("resource")\r
-               Formatter formatter = new Formatter(cb, Locale.US);\r
-\r
-               int i = reservedNames.size() + 1;\r
-               for (;; ++i) {\r
-                       cb.reset();\r
-                       formatter.format(nameFormat, proposition, i);\r
-                       if (!reservedNames.contains(cb)) {\r
-                               // Construct a String from the CharBuffer\r
-                               cb.limit(cb.position());\r
-                               cb.rewind();\r
-                               String result = cb.toString();\r
-                               return result;\r
-                       }\r
-               }\r
-       }\r
-\r
-       public static String getSafeName(ReadGraph graph, Resource resource, boolean id) throws ValidationException, ServiceException {\r
-\r
-               if(id && resource != null) {\r
-                       return getSafeName(graph, resource) + ":$" + resource.getResourceId();\r
-               } else {\r
-                       return getSafeName(graph, resource);\r
-               }\r
-\r
-       }\r
-\r
-       public static String getSafeName(ReadGraph graph, Collection<Resource> rs) throws ValidationException, ServiceException {\r
-\r
-               StringBuilder b = new StringBuilder();\r
-               b.append("{");\r
-               for(Resource r : rs) {\r
-                       b.append(getSafeName(graph, r));\r
-                       b.append(",");\r
-               }\r
-               b.append("}");\r
-               return b.toString();\r
-\r
-       }\r
-\r
-       public static String getSafeLabel(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {\r
-               return getSafeNameInternal(graph, resource, true);\r
-       }\r
-\r
-       public static String getSafeName(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {\r
-               return getSafeNameInternal(graph, resource, false);\r
-       }\r
-\r
-       private static Object truncate(Object array) {\r
-               if(array instanceof byte[]) {\r
-                       byte[] bytes = (byte[])array;\r
-                       if(bytes.length > 100)\r
-                               return Arrays.copyOfRange(bytes, 0, 100);\r
-               }\r
-               return array;\r
-       }\r
-\r
-       public static String getURIOrSafeNameInternal(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {\r
-               return getURIOrSafeNameInternal(graph, resource, false);\r
-       }\r
-\r
-       public static String getURIOrSafeNameInternal(ReadGraph graph, Resource resource, boolean tryLabel) throws ValidationException, ServiceException {\r
-               if (resource == null) return "null";\r
-               String uri = graph.getPossibleURI(resource);\r
-               if(uri != null) return uri;\r
-               else return getSafeNameInternal(graph, resource, tryLabel);\r
-       }\r
-\r
-       public static long getPossibleValueSize(ReadGraph graph, Resource resource) {\r
-               try {\r
-                       if(graph.hasValue(resource)) {\r
-                               RandomAccessBinary rab = graph.getRandomAccessBinary(resource);\r
-                               return rab.length();\r
-                       }\r
-               }catch (Exception e) {\r
-\r
-               }\r
-               return 0;\r
-       }\r
-\r
-       private static String getSafeNameInternal(ReadGraph graph, Resource resource, boolean tryLabel) throws ValidationException, ServiceException {\r
-               if(resource == null) return "null";\r
-               Layer0 b = Layer0.getInstance(graph);\r
-               if (graph.isInstanceOf(resource, b.Variant)) {\r
-                       try {\r
-                               Variant v = graph.getPossibleValue(resource, Bindings.VARIANT);\r
-                               return v.toString();\r
-                       } catch (BindingException e) {\r
-                       }\r
-               }\r
-               List<String> names = new ArrayList<String>(1);\r
-               if (tryLabel) {\r
-                       for(Resource nameResource : graph.getObjects(resource, b.HasLabel)) {\r
-                               if(graph.isInstanceOf(nameResource, b.Literal)) {\r
-                                       Object value = graph.getPossibleValue(nameResource);\r
-                                       if(value != null) {\r
-                                               String s = Literals.literalToString(value);\r
-                                               if (!s.isEmpty())\r
-                                                       names.add(s);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               if (names.isEmpty()) {\r
-                       for(Resource nameResource : graph.getObjects(resource, b.HasName)) {\r
-                               Object value = graph.getPossibleValue(nameResource);\r
-                               if(value != null) {\r
-                                       names.add(Literals.literalToString(value));\r
-                               }\r
-                       }\r
-               }\r
-               if(!names.isEmpty()) {\r
-                       if(names.size() == 1)\r
-                               return names.get(0);\r
-                       else {\r
-                               StringBuilder bb = new StringBuilder();\r
-                               bb.append('[');\r
-                               for(int i=0;i<names.size();++i) {\r
-                                       if(i>0)\r
-                                               bb.append(", ");\r
-                                       bb.append(names.get(i));\r
-                               }\r
-                               bb.append(']');\r
-                               return bb.toString();\r
-                       }\r
-               }\r
-               StringBuilder bb = new StringBuilder();\r
-               long valueSize = getPossibleValueSize(graph, resource);\r
-               //System.err.println("valueSize=" + valueSize);\r
-               if(valueSize > 0) {\r
-                       if(valueSize < 1e6) {\r
-                               Object val = graph.getPossibleValue(resource);\r
-                               if(val != null) {\r
-                                       val = truncate(val);\r
-                                       if(val instanceof double[])\r
-                                               bb.append(Arrays.toString((double[])val));\r
-                                       else if(val instanceof float[])\r
-                                               bb.append(Arrays.toString((float[])val));\r
-                                       else if(val instanceof int[])\r
-                                               bb.append(Arrays.toString((int[])val));\r
-                                       else if(val instanceof boolean[])\r
-                                               bb.append(Arrays.toString((boolean[])val));\r
-                                       else if(val instanceof long[])\r
-                                               bb.append(Arrays.toString((long[])val));\r
-                                       else if(val instanceof byte[])\r
-                                               bb.append(Arrays.toString((byte[])val));\r
-                                       else if(val instanceof String[])\r
-                                               bb.append(Arrays.toString((String[])val));\r
-                                       else\r
-                                               bb.append(val);\r
-                               } else {\r
-                                       bb.append('$').append(resource.getResourceId());\r
-                               }\r
-                       } else {\r
-                               bb.append('$').append(resource.getResourceId());\r
-                               bb.append("[" + valueSize + " bytes of value]");\r
-                       }\r
-               } else {\r
-                       bb.append('$').append(resource.getResourceId());\r
-               }\r
-               boolean ok = false;\r
-               for(Resource r : graph.getObjects(resource, b.InstanceOf)) {\r
-                       if(!r.equals(resource))\r
-                               bb.append(" : (" + getSafeName(graph, r) + ")");\r
-                       ok = true;\r
-               }\r
-               if(!ok) {\r
-                       for(Resource r : graph.getObjects(resource, b.Inherits)) {\r
-                               bb.append(" <T (" + getSafeName(graph, r) + ")");\r
-                               ok = true;\r
-                       }\r
-                       if(!ok) {\r
-                               for(Resource r : graph.getObjects(resource, b.SubrelationOf)) {\r
-                                       bb.append(" <R (" + getSafeName(graph, r) + ")");\r
-                                       ok = true;\r
-                               }\r
-                       }\r
-               }\r
-               return bb.toString();\r
-       }\r
-\r
-       public static String toString(ReadGraph graph, Statement stm) throws DatabaseException {\r
-               return getSafeName(graph, stm.getSubject()) + ", " +\r
-                               getSafeName(graph, stm.getPredicate()) + ", " +\r
-                               getSafeName(graph, stm.getObject());\r
-       }\r
-\r
-       public static String toString(ReadGraph graph, Statement stm, boolean ids) throws DatabaseException {\r
-               return getSafeName(graph, stm.getSubject(), ids) + ", " +\r
-                               getSafeName(graph, stm.getPredicate(), ids) + ", " +\r
-                               getSafeName(graph, stm.getObject(), ids);\r
-       }\r
-\r
-       public static String toIdString(ReadGraph graph, Statement stm) throws DatabaseException {\r
-               return stm.getSubject() + ", " + stm.getPredicate() + ", " + stm.getObject();\r
-       }\r
-\r
-       /**\r
-        * Convert a collection of resources into a String in the same manner as\r
-        * {@link Arrays#toString(Object[])} does but by consulting\r
-        * {@link #getSafeName(ReadGraph, Resource)} for each resource.\r
-        * \r
-        * @param g database accessor\r
-        * @param c the collection of resources to translate to named strings\r
-        * @return string representation of the resource collection\r
-        * @throws DatabaseException\r
-        */\r
-       public static String toString(ReadGraph g, Collection<Resource> c) throws DatabaseException {\r
-               return toString(g, c, false);\r
-       }\r
-\r
-       /**\r
-        * Convert a collection of resources into a String in the same manner as\r
-        * {@link Arrays#toString(Object[])} does but by consulting\r
-        * {@link #getSafeName(ReadGraph, Resource)} for each resource.\r
-        * \r
-        * @param g database accessor\r
-        * @param c the collection of resources to translate to named strings\r
-        * @param ids <code>true</code> to print the ID of each resource after its\r
-        *        name separated by ':'\r
-        * @return string representation of the resource collection\r
-        * @throws DatabaseException\r
-        */\r
-       public static String toString(ReadGraph g, Collection<Resource> c, boolean ids) throws DatabaseException {\r
-               StringBuilder sb = new StringBuilder();\r
-               sb.append('[');\r
-               boolean first = true;\r
-               for (Resource r : c) {\r
-                       if (!first)\r
-                               sb.append(", ");\r
-                       first = false;\r
-                       sb.append(getSafeName(g, r, ids));\r
-               }\r
-               return sb.append(']').toString();\r
-       }\r
-\r
-       /**\r
-        * @param graph\r
-        * @param r\r
-        * @return\r
-        * @throws DatabaseException\r
-        */\r
-       public static String resourcePath(ReadGraph graph, Resource r) throws DatabaseException {\r
-               return resourcePath0(graph, r, new StringBuilder(80)).toString();\r
-       }\r
-\r
-       /**\r
-        * @param graph\r
-        * @param r\r
-        * @return\r
-        * @throws DatabaseException\r
-        */\r
-       private static StringBuilder resourcePath0(ReadGraph graph, Resource r, StringBuilder result) throws DatabaseException {\r
-               String uri = graph.getPossibleURI(r);\r
-               if (uri != null)\r
-                       return result.append(uri);\r
-               Resource owner = null;\r
-               try {\r
-                       owner = CommonDBUtils.getPossibleOwner(graph, r);\r
-                       if (owner == null)\r
-                               return result.append(NameUtils.getSafeName(graph, r));\r
-               } catch (DatabaseException e) {\r
-                       // Owner resource not found by CommonDBUtils.getPossibleOwner.\r
-                       return result.append(NameUtils.getSafeName(graph, r));\r
-               }\r
-               // See if there's a statement between r and owner.\r
-               Layer0 L0 = Layer0.getInstance(graph);\r
-               for (Statement stm : graph.getStatements(owner, L0.IsWeaklyRelatedTo)) {\r
-                       if (stm.getObject().equals(r)) {\r
-                               Resource predicate = stm.getPredicate();\r
-                               if (predicate.equals(L0.ConsistsOf)) {\r
-                                       return resourcePath0(graph, owner, result)\r
-                                                       .append(" / ")\r
-                                                       .append(NameUtils.getSafeName(graph, r));\r
-                               } else if (graph.isSubrelationOf(predicate, L0.HasProperty)) {\r
-                                       return resourcePath0(graph, owner, result)\r
-                                                       .append(" #(")\r
-                                                       .append(NameUtils.getSafeName(graph, predicate, true))\r
-                                                       .append(") ")\r
-                                                       .append(NameUtils.getSafeName(graph, r));\r
-                               } else {\r
-                                       return resourcePath0(graph, owner, result)\r
-                                                       .append(" -(")\r
-                                                       .append(NameUtils.getSafeName(graph, predicate, true))\r
-                                                       .append(")-> ")\r
-                                                       .append(NameUtils.getSafeName(graph, r));\r
-                               }\r
-                       }\r
-               }\r
-               return resourcePath0(graph, owner, result)\r
-                               .append(" ... ")\r
-                               .append(NameUtils.getSafeName(graph, r));\r
-       }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.db.common.utils;
+
+import java.nio.CharBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Formatter;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.mutable.Variant;
+import org.simantics.databoard.util.binary.RandomAccessBinary;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Statement;
+import org.simantics.db.exception.BindingException;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.exception.ValidationException;
+import org.simantics.layer0.Layer0;
+import org.simantics.utils.datastructures.MapList;
+
+
+public final class NameUtils {
+
+       public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource propertyToList, Set<String> result, MapList<String,String> reservation) throws DatabaseException {
+               
+               if (proposition == null)
+                       throw new NullPointerException("null proposition");
+               if (propertyToList == null)
+                       throw new NullPointerException("null property to list");
+               if (result == null)
+                       result = new HashSet<String>();
+               
+               if (reservation != null) {
+                       String possibleURI = g.getPossibleURI(container);
+                       if(possibleURI != null) {
+                               result.addAll(reservation.getValuesUnsafe(possibleURI));
+                       }
+               }
+               
+               for (Resource r : g.getObjects(container, consistRelation)) {
+                       String name = g.getPossibleRelatedValue(r, propertyToList);
+                       if (name != null && name.startsWith(proposition))
+                               result.add(Versions.getBaseName(name));
+               }
+               
+               return result;
+               
+       }
+
+       public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource propertyToList, Set<String> result) throws DatabaseException {
+               return findReservedNames(g, proposition, container, consistRelation, propertyToList, result, null);
+       }
+
+       public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation, Set<String> result) throws DatabaseException {
+               Layer0 L0 = Layer0.getInstance(g);
+               return findReservedNames(g, proposition, container, consistRelation, L0.HasName, result);
+       }
+
+       public static Set<String> findReservedNames(ReadGraph g, String proposition, Resource container, Resource consistRelation) throws DatabaseException {
+               Set<String> result = new HashSet<String>();
+               findReservedNames(g, proposition, container, consistRelation, result);
+               return result;
+       }
+
+       public static String findFreshName(ReadGraph g, String proposition, Resource container) throws DatabaseException {
+               Layer0 b = Layer0.getInstance(g);
+               return findFreshName(g, proposition, container, b.ConsistsOf);
+       }
+
+       public static String findFreshLabel(ReadGraph g, String proposition, Resource container) throws DatabaseException {
+               Layer0 L0 = Layer0.getInstance(g);
+               return _findFreshName(g, proposition, container, L0.ConsistsOf, L0.HasLabel, " ");
+       }
+
+       public static String findFreshEscapedName(ReadGraph g, String proposition, Resource container) throws DatabaseException {
+               Layer0 b = Layer0.getInstance(g);
+               return findFreshEscapedName(g, proposition, container, b.ConsistsOf);
+       }
+
+       public static final Comparator<Object> STRING_CHARBUFFER_COMPARATOR = new Comparator<Object>(){
+               @Override
+               public int compare(Object o1, Object o2) {
+                       String s1 = null;
+                       String s2 = null;
+                       if (o1 instanceof String)
+                               s1 = (String) o1;
+                       if (o2 instanceof String)
+                               s2 = (String) o2;
+                       if (s1 != null && s2 != null)
+                               return s1.compareTo((String) o2);
+
+                       if (s1 == null && s2 == null)
+                               return 0;
+
+                       if (s1 == null && (o1 instanceof CharBuffer))
+                               return -compare(s2, (CharBuffer) o1);
+                       if (s2 == null && (o2 instanceof CharBuffer))
+                               return compare(s1, (CharBuffer) o2);
+
+                       return 0;
+               }
+               int compare(String s, CharBuffer buf) {
+                       int len1 = s.length();
+                       int len2 = buf.position();
+                       int n = Math.min(len1, len2);
+                       int k = 0;
+                       while (k < n) {
+                               char c1 = s.charAt(k);
+                               char c2 = buf.get(k);
+                               if (c1 != c2) {
+                                       return c1 - c2;
+                               }
+                               k++;
+                       }
+                       return len1 - len2;
+               }
+       };
+
+       public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation) throws DatabaseException {
+               return _findFreshName(g, proposition, container, consistRelation, " ");
+       }
+
+       public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, String nameFormat) throws DatabaseException {
+               return findFreshName(g, proposition, container, consistRelation, Layer0.getInstance(g).HasName, nameFormat);
+       }
+
+       public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource nameProperty, String nameFormat) throws DatabaseException {
+               Set<String> reservedNames = new TreeSet<String>(STRING_CHARBUFFER_COMPARATOR);
+               findReservedNames(g, proposition, container, consistRelation, nameProperty, reservedNames);
+               return findFreshNameFormatted(proposition, reservedNames, nameFormat);
+       }
+
+       public static String findFreshEscapedName(ReadGraph g, String proposition, Resource container, Resource consistRelation) throws DatabaseException {
+               return _findFreshName(g, proposition, container, consistRelation, "_");
+       }
+       
+       /**
+        * Find a fresh name using the specified name proposition among an
+        * externally specified set of names using suffix numbers.
+        * 
+        * @param g
+        * @param proposition
+        * @param reservedNames
+        * @param numberSeparator
+        * @return
+        * @throws DatabaseException
+        */
+       public static String findFreshName(ReadGraph g, String proposition, Set<String> reservedNames, String numberSeparator) throws DatabaseException {
+               // Trying to optimize away unnecessary allocation of new String instances
+               // when looking for fresh names for objects.
+               if (!reservedNames.contains(proposition))
+                       return proposition;
+
+               // Need to make sure that the set is using the correct comparator.
+               Set<String> used = new TreeSet<String>(STRING_CHARBUFFER_COMPARATOR);
+               used.addAll(reservedNames);
+               return findFreshNameNumbered(proposition, used, numberSeparator);
+       }
+
+       public static String findFreshInstanceName(ReadGraph g, Resource type, Resource container) throws DatabaseException {
+               String typeName = g.getPossibleRelatedValue(type, Layer0.getInstance(g).HasName);
+               if (typeName == null)
+                       typeName = "Entity";
+               return findFreshName(g, typeName, container);
+       }
+
+       public static String findFreshInstanceName(ReadGraph g, Resource type, Resource container, Resource relation) throws DatabaseException {
+               String typeName = g.getPossibleRelatedValue(type, Layer0.getInstance(g).HasName);
+               if (typeName == null)
+                       typeName = "Entity";
+               return findFreshName(g, typeName, container, relation);
+       }
+
+       private static String _findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, String numberSeparator) throws DatabaseException {
+               return _findFreshName(g, proposition, container, consistRelation, Layer0.getInstance(g).HasName, numberSeparator);
+       }
+
+       private static String _findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource nameProperty, String numberSeparator) throws DatabaseException {
+               return findFreshName(g, proposition, container, consistRelation, nameProperty, numberSeparator, null);
+       }
+       
+       public static String findFreshName(ReadGraph g, String proposition, Resource container, Resource consistRelation, Resource nameProperty, String numberSeparator, MapList<String, String> reservation) throws DatabaseException {
+               Set<String> reservedNames = new TreeSet<String>(STRING_CHARBUFFER_COMPARATOR);
+               findReservedNames(g, proposition, container, consistRelation, nameProperty, reservedNames, reservation);
+               return findFreshNameNumbered(proposition, reservedNames, numberSeparator);
+       }
+
+       public static String findFreshNameNumbered(String proposition, Set<String> reservedNames, String numberSeparator) {
+               // Trying to optimize away unnecessary allocation of new String instances
+               // when looking for fresh names for objects.
+               if (!reservedNames.contains(proposition))
+                       return proposition;
+
+               CharBuffer cb = CharBuffer.allocate(proposition.length() + 10);
+               cb.append(proposition);
+               cb.append(numberSeparator);
+               cb.mark();
+               int i = reservedNames.size() + 1;
+               while (true) {
+                       cb.reset();
+                       cb.append(String.valueOf(i));
+                       if (!reservedNames.contains(cb)) {
+                               // Construct a String from the CharBuffer
+                               cb.limit(cb.position());
+                               cb.rewind();
+                               return cb.toString();
+                       }
+                       ++i;
+               }
+       }
+
+       public static String findFreshNameFormatted(String proposition, Set<String> reservedNames, String nameFormat) {
+               if (!reservedNames.contains(proposition))
+                       return proposition;
+
+               // Trying to optimize away unnecessary allocation of new String instances
+               // when looking for fresh names for objects.
+               CharBuffer cb = CharBuffer.allocate(proposition.length() + 10);
+               cb.mark();
+
+               @SuppressWarnings("resource")
+               Formatter formatter = new Formatter(cb, Locale.US);
+
+               int i = reservedNames.size() + 1;
+               for (;; ++i) {
+                       cb.reset();
+                       formatter.format(nameFormat, proposition, i);
+                       if (!reservedNames.contains(cb)) {
+                               // Construct a String from the CharBuffer
+                               cb.limit(cb.position());
+                               cb.rewind();
+                               String result = cb.toString();
+                               return result;
+                       }
+               }
+       }
+
+       public static String getSafeName(ReadGraph graph, Resource resource, boolean id) throws ValidationException, ServiceException {
+
+               if(id && resource != null) {
+                       return getSafeName(graph, resource) + ":$" + resource.getResourceId();
+               } else {
+                       return getSafeName(graph, resource);
+               }
+
+       }
+
+       public static String getSafeName(ReadGraph graph, Collection<Resource> rs) throws ValidationException, ServiceException {
+
+               StringBuilder b = new StringBuilder();
+               b.append("{");
+               for(Resource r : rs) {
+                       b.append(getSafeName(graph, r));
+                       b.append(",");
+               }
+               b.append("}");
+               return b.toString();
+
+       }
+
+       public static String getSafeLabel(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {
+               return getSafeNameInternal(graph, resource, true);
+       }
+
+       public static String getSafeName(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {
+               return getSafeNameInternal(graph, resource, false);
+       }
+
+       private static Object truncate(Object array) {
+               if(array instanceof byte[]) {
+                       byte[] bytes = (byte[])array;
+                       if(bytes.length > 100)
+                               return Arrays.copyOfRange(bytes, 0, 100);
+               }
+               return array;
+       }
+
+       public static String getURIOrSafeNameInternal(ReadGraph graph, Resource resource) throws ValidationException, ServiceException {
+               return getURIOrSafeNameInternal(graph, resource, false);
+       }
+
+       public static String getURIOrSafeNameInternal(ReadGraph graph, Resource resource, boolean tryLabel) throws ValidationException, ServiceException {
+               if (resource == null) return "null";
+               String uri = graph.getPossibleURI(resource);
+               if(uri != null) return uri;
+               else return getSafeNameInternal(graph, resource, tryLabel);
+       }
+
+       public static long getPossibleValueSize(ReadGraph graph, Resource resource) {
+               try {
+                       if(graph.hasValue(resource)) {
+                               RandomAccessBinary rab = graph.getRandomAccessBinary(resource);
+                               return rab.length();
+                       }
+               }catch (Exception e) {
+
+               }
+               return 0;
+       }
+
+       private static String getSafeNameInternal(ReadGraph graph, Resource resource, boolean tryLabel) throws ValidationException, ServiceException {
+               if(resource == null) return "null";
+               Layer0 b = Layer0.getInstance(graph);
+               if (graph.isInstanceOf(resource, b.Variant)) {
+                       try {
+                               Variant v = graph.getPossibleValue(resource, Bindings.VARIANT);
+                               return v.toString();
+                       } catch (BindingException e) {
+                       }
+               }
+               List<String> names = new ArrayList<String>(1);
+               if (tryLabel) {
+                       for(Resource nameResource : graph.getObjects(resource, b.HasLabel)) {
+                               if(graph.isInstanceOf(nameResource, b.Literal)) {
+                                       Object value = graph.getPossibleValue(nameResource);
+                                       if(value != null) {
+                                               String s = Literals.literalToString(value);
+                                               if (!s.isEmpty())
+                                                       names.add(s);
+                                       }
+                               }
+                       }
+               }
+               if (names.isEmpty()) {
+                       for(Resource nameResource : graph.getObjects(resource, b.HasName)) {
+                               Object value = graph.getPossibleValue(nameResource);
+                               if(value != null) {
+                                       names.add(Literals.literalToString(value));
+                               }
+                       }
+               }
+               if(!names.isEmpty()) {
+                       if(names.size() == 1)
+                               return names.get(0);
+                       else {
+                               StringBuilder bb = new StringBuilder();
+                               bb.append('[');
+                               for(int i=0;i<names.size();++i) {
+                                       if(i>0)
+                                               bb.append(", ");
+                                       bb.append(names.get(i));
+                               }
+                               bb.append(']');
+                               return bb.toString();
+                       }
+               }
+               StringBuilder bb = new StringBuilder();
+               long valueSize = getPossibleValueSize(graph, resource);
+               //System.err.println("valueSize=" + valueSize);
+               if(valueSize > 0) {
+                       if(valueSize < 1e6) {
+                               Object val = graph.getPossibleValue(resource);
+                               if(val != null) {
+                                       val = truncate(val);
+                                       if(val instanceof double[])
+                                               bb.append(Arrays.toString((double[])val));
+                                       else if(val instanceof float[])
+                                               bb.append(Arrays.toString((float[])val));
+                                       else if(val instanceof int[])
+                                               bb.append(Arrays.toString((int[])val));
+                                       else if(val instanceof boolean[])
+                                               bb.append(Arrays.toString((boolean[])val));
+                                       else if(val instanceof long[])
+                                               bb.append(Arrays.toString((long[])val));
+                                       else if(val instanceof byte[])
+                                               bb.append(Arrays.toString((byte[])val));
+                                       else if(val instanceof String[])
+                                               bb.append(Arrays.toString((String[])val));
+                                       else
+                                               bb.append(val);
+                               } else {
+                                       bb.append('$').append(resource.getResourceId());
+                               }
+                       } else {
+                               bb.append('$').append(resource.getResourceId());
+                               bb.append("[" + valueSize + " bytes of value]");
+                       }
+               } else {
+                       bb.append('$').append(resource.getResourceId());
+               }
+               boolean ok = false;
+               for(Resource r : graph.getObjects(resource, b.InstanceOf)) {
+                       if(!r.equals(resource))
+                               bb.append(" : (" + getSafeName(graph, r) + ")");
+                       ok = true;
+               }
+               if(!ok) {
+                       for(Resource r : graph.getObjects(resource, b.Inherits)) {
+                               bb.append(" <T (" + getSafeName(graph, r) + ")");
+                               ok = true;
+                       }
+                       if(!ok) {
+                               for(Resource r : graph.getObjects(resource, b.SubrelationOf)) {
+                                       bb.append(" <R (" + getSafeName(graph, r) + ")");
+                                       ok = true;
+                               }
+                       }
+               }
+               return bb.toString();
+       }
+
+       public static String toString(ReadGraph graph, Statement stm) throws DatabaseException {
+               return getSafeName(graph, stm.getSubject()) + ", " +
+                               getSafeName(graph, stm.getPredicate()) + ", " +
+                               getSafeName(graph, stm.getObject());
+       }
+
+       public static String toString(ReadGraph graph, Statement stm, boolean ids) throws DatabaseException {
+               return getSafeName(graph, stm.getSubject(), ids) + ", " +
+                               getSafeName(graph, stm.getPredicate(), ids) + ", " +
+                               getSafeName(graph, stm.getObject(), ids);
+       }
+
+       public static String toIdString(ReadGraph graph, Statement stm) throws DatabaseException {
+               return stm.getSubject() + ", " + stm.getPredicate() + ", " + stm.getObject();
+       }
+
+       /**
+        * Convert a collection of resources into a String in the same manner as
+        * {@link Arrays#toString(Object[])} does but by consulting
+        * {@link #getSafeName(ReadGraph, Resource)} for each resource.
+        * 
+        * @param g database accessor
+        * @param c the collection of resources to translate to named strings
+        * @return string representation of the resource collection
+        * @throws DatabaseException
+        */
+       public static String toString(ReadGraph g, Collection<Resource> c) throws DatabaseException {
+               return toString(g, c, false);
+       }
+
+       /**
+        * Convert a collection of resources into a String in the same manner as
+        * {@link Arrays#toString(Object[])} does but by consulting
+        * {@link #getSafeName(ReadGraph, Resource)} for each resource.
+        * 
+        * @param g database accessor
+        * @param c the collection of resources to translate to named strings
+        * @param ids <code>true</code> to print the ID of each resource after its
+        *        name separated by ':'
+        * @return string representation of the resource collection
+        * @throws DatabaseException
+        */
+       public static String toString(ReadGraph g, Collection<Resource> c, boolean ids) throws DatabaseException {
+               StringBuilder sb = new StringBuilder();
+               sb.append('[');
+               boolean first = true;
+               for (Resource r : c) {
+                       if (!first)
+                               sb.append(", ");
+                       first = false;
+                       sb.append(getSafeName(g, r, ids));
+               }
+               return sb.append(']').toString();
+       }
+
+       /**
+        * @param graph
+        * @param r
+        * @return
+        * @throws DatabaseException
+        */
+       public static String resourcePath(ReadGraph graph, Resource r) throws DatabaseException {
+               return resourcePath0(graph, r, new StringBuilder(80)).toString();
+       }
+
+       /**
+        * @param graph
+        * @param r
+        * @return
+        * @throws DatabaseException
+        */
+       private static StringBuilder resourcePath0(ReadGraph graph, Resource r, StringBuilder result) throws DatabaseException {
+               String uri = graph.getPossibleURI(r);
+               if (uri != null)
+                       return result.append(uri);
+               Resource owner = null;
+               try {
+                       owner = CommonDBUtils.getPossibleOwner(graph, r);
+                       if (owner == null)
+                               return result.append(NameUtils.getSafeName(graph, r));
+               } catch (DatabaseException e) {
+                       // Owner resource not found by CommonDBUtils.getPossibleOwner.
+                       return result.append(NameUtils.getSafeName(graph, r));
+               }
+               // See if there's a statement between r and owner.
+               Layer0 L0 = Layer0.getInstance(graph);
+               for (Statement stm : graph.getStatements(owner, L0.IsWeaklyRelatedTo)) {
+                       if (stm.getObject().equals(r)) {
+                               Resource predicate = stm.getPredicate();
+                               if (predicate.equals(L0.ConsistsOf)) {
+                                       return resourcePath0(graph, owner, result)
+                                                       .append(" / ")
+                                                       .append(NameUtils.getSafeName(graph, r));
+                               } else if (graph.isSubrelationOf(predicate, L0.HasProperty)) {
+                                       return resourcePath0(graph, owner, result)
+                                                       .append(" #(")
+                                                       .append(NameUtils.getSafeName(graph, predicate, true))
+                                                       .append(") ")
+                                                       .append(NameUtils.getSafeName(graph, r));
+                               } else {
+                                       return resourcePath0(graph, owner, result)
+                                                       .append(" -(")
+                                                       .append(NameUtils.getSafeName(graph, predicate, true))
+                                                       .append(")-> ")
+                                                       .append(NameUtils.getSafeName(graph, r));
+                               }
+                       }
+               }
+               return resourcePath0(graph, owner, result)
+                               .append(" ... ")
+                               .append(NameUtils.getSafeName(graph, r));
+       }
+
+}