--- /dev/null
+/*******************************************************************************\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