import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Pattern;
import org.simantics.databoard.Bindings;
-import org.simantics.databoard.Datatypes;
import org.simantics.databoard.binding.Binding;
import org.simantics.databoard.binding.mutable.Variant;
import org.simantics.databoard.container.DataContainers;
-import org.simantics.databoard.type.Datatype;
+import org.simantics.databoard.parser.DataValuePrinter;
+import org.simantics.databoard.parser.PrintFormat;
+import org.simantics.databoard.parser.repository.DataValueRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import gnu.trove.list.array.TIntArrayList;
+import gnu.trove.map.hash.TIntIntHashMap;
import gnu.trove.map.hash.TIntObjectHashMap;
+import gnu.trove.procedure.TIntIntProcedure;
import gnu.trove.set.hash.TLongHashSet;
/**
* @author Antti Villberg
* @since 1.24.0
*/
-public class PrettyPrintTG extends TransferableGraphUtils {
+public class PrettyPrintTG {
+ private static final Logger LOGGER = LoggerFactory.getLogger(PrettyPrintTG.class);
+
int blankCounter = 0;
MessageDigest m;
final int resource;
boolean newResource = false;
+ int parent;
+
+ boolean inlined = false;
+
// -1 = no owner, -2 = multiple owners
- int owner = -1;
- int ownerPredicate = 0;
+
+ // Set<ResourceInfo> ownedBy
+ Set<ResourceInfo> ownedBy = new HashSet<>();
+
+ // A Map<Integer, Integer> containing information about resource that this resource owns and what are the predicates for forming this ownership
+ TIntIntHashMap ownedResourcesWithPredicates = new TIntIntHashMap();
+
+// int owner = -1;
+// int ownerPredicate = 0;
String aliasURI = null;
TIntArrayList owned = new TIntArrayList();
//TIntObjectHashMap<TIntHashSet> statements = new TIntObjectHashMap<TIntHashSet>();
- public ResourceInfo(boolean hasURI, String name, int resource) {
+ public ResourceInfo(boolean hasURI, String name, int resource, int parent) {
this.hasURI = hasURI;
this.name = name;
this.resource = resource;
+ this.parent = parent;
+ }
+
+ @Override
+ public String toString() {
+ return name + (aliasURI != null ? " = <" + aliasURI + ">" : "");
}
}
else return name;
}
- ResourceInfo recurseURI(TransferableGraph1 graph, Identity parent, String parentName) {
- String name = parentName + "." + tgNodeName(getName(parent));
- ResourceInfo info = new ResourceInfo(true, name, parent.resource);
+ ResourceInfo recurseURI(TransferableGraph1 graph, Identity parent, String parentName, int parentId) {
+ String name = parentName + "." + tgNodeName(TransferableGraphUtils.getName(parent));
+ ResourceInfo info = new ResourceInfo(true, name, parent.resource, parentId);
infos.put(parent.resource, info);
- for(Identity child : getChildren(graph, parent)) {
- recurseURI(graph, child, name);
+ for(Identity child : TransferableGraphUtils.getChildren(graph, parent)) {
+ recurseURI(graph, child, name, info.resource);
}
return info;
}
void discoverBlank(TransferableGraph1 graph, int resource, TIntArrayList todo) throws Exception {
- TIntArrayList statements = getStatements(graph, resource);
+ TIntArrayList statements = TransferableGraphUtils.getStatements(graph, resource);
for(int i=0;i<statements.size();i+=2) {
int object = statements.get(i+1);
- Identity objectId = getIdentity(graph, object);
+ Identity objectId = TransferableGraphUtils.getIdentity(graph, object);
if(objectId != null) {
if(objectId.definition instanceof External) continue;
}
Value value = TransferableGraphUtils.findValue(graph, object);
if(value != null) {
- infos.put(object, new ResourceInfo(false, printValue(value), object));
+ infos.put(object, new ResourceInfo(false, printValue(value), object, resource));
continue;
}
ResourceInfo existing = infos.get(object);
if(existing == null) {
- existing = new ResourceInfo(false, "blank" + blankCounter++, object);
+ existing = new ResourceInfo(false, "blank" + blankCounter++, object, resource);
infos.put(object, existing);
todo.add(object);
}
}
void discoverOwners(TransferableGraph1 graph, ResourceInfo info) {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Discovering owners for " + info);
int resource = info.resource;
- TIntArrayList statements = getStatements(graph, resource);
+ TIntArrayList statements = TransferableGraphUtils.getStatements(graph, resource);
for(int i=0;i<statements.size();i+=2) {
int predicate = statements.get(i);
int object = statements.get(i+1);
ResourceInfo existing = infos.get(object);
- if(existing == null) continue;
- if(existing.owner == -1) {
- existing.owner = resource;
- existing.ownerPredicate = predicate;
- //System.err.println("First owner " + info.name + " => " + predicateURI + " " + existing.name);
- } else {
- existing.owner = -2;
- //System.err.println("Multiple owners " + info.name + " => " + predicateURI + " " + existing.name);
+ if(existing != null) {
+ // Add all owners here for now and resolve the best owner later
+ existing.ownedResourcesWithPredicates.put(resource, predicate);
+ // Check if predicate is inverse, this just resolves all predicates to be inverse with ending "Inverse"..
+ String predicateUri = rewritePredicateURI(graph, predicate);
+ if (!predicateUri.endsWith("Inverse")) {
+ existing.ownedBy.add(info);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug(" " + existing + " owns " + info + " with " + predicateUri);
+ }
+ }
}
}
-
}
- String printValue(Value value) throws Exception {
- Variant variant = value.value;
- Datatype dt = variant.getBinding().type();
- if(Datatypes.STRING.equals(dt)) {
- String s = (String)variant.getValue(Bindings.STRING);
- if(s.contains("\n")) {
- return "\"\"\"" + s + "\"\"\"";
- } else {
- return "\"" + s + "\"";
- }
- } else if(Datatypes.BOOLEAN.equals(dt)) {
- Boolean i = (Boolean)variant.getValue(Bindings.BOOLEAN);
- return i ? "true" : "false";
- } else if(Datatypes.INTEGER.equals(dt)) {
- Integer i = (Integer)variant.getValue(Bindings.INTEGER);
- return i.toString();
- } else if(Datatypes.LONG.equals(dt)) {
- Long i = (Long)variant.getValue(Bindings.LONG);
- return i.toString();
- } else {
- byte[] data = variant.getBinding().serializer().serialize(variant.getValue());
- m.reset();
- m.update(data, 0, data.length);
- return "\"" + new BigInteger(1, m.digest()).toString(16) + "\"";
- }
-
- }
+ DataValueRepository repo = new DataValueRepository();
+ DataValuePrinter printer = new DataValuePrinter(null, repo);
+
+ String printValue(Value value) throws Exception {
+ StringBuilder sb = new StringBuilder();
+ printer.setFormat(PrintFormat.SINGLE_LINE);
+ printer.setOutput(sb);
+
+ Variant variant = value.value;
+ printer.print(variant.getBinding(), variant.getValue());
+ String formattedOutput = sb.toString();
+ if (formattedOutput.length() > 100) {
+ // Ok, value too long, lets calculate a hash for it and store first 100 chars as comment
+ byte[] data = Bindings.getSerializerUnchecked(variant.getBinding()).serialize(variant.getValue());
+ m.reset();
+ m.update(data, 0, data.length);
+ String hash = "\"" + new BigInteger(1, m.digest()).toString(16) + "\"";
+ return hash + " // " + formattedOutput.substring(0, 100) + "..";
+ } else {
+ return formattedOutput;
+ }
+//
+// Variant variant = value.value;
+// Datatype dt = variant.getBinding().type();
+// if (Datatypes.STRING.equals(dt)) {
+// String s = (String) variant.getValue(Bindings.STRING);
+// if (s.contains("\n")) {
+// return "\"\"\"" + s + "\"\"\"";
+// } else {
+// return "\"" + s + "\"";
+// }
+// } else if (Datatypes.BOOLEAN.equals(dt)) {
+// Boolean i = (Boolean) variant.getValue(Bindings.BOOLEAN);
+// return i ? "true" : "false";
+// } else if (Datatypes.INTEGER.equals(dt)) {
+// Integer i = (Integer) variant.getValue(Bindings.INTEGER);
+// return i.toString();
+// } else if (Datatypes.LONG.equals(dt)) {
+// Long i = (Long) variant.getValue(Bindings.LONG);
+// return i.toString();
+// } else if (Datatypes.DOUBLE.equals(dt)) {
+// Double d = (Double) variant.getValue();
+// return d.toString();
+// } else if (Datatypes.FLOAT.equals(dt)) {
+// Float f = (Float) variant.getValue();
+// return f.toString();
+// } else if (Datatypes.STRING_ARRAY.equals(dt)) {
+// return Arrays.toString((String []) variant.getValue());
+// } else if (Datatypes.BOOLEAN_ARRAY.equals(dt)) {
+// return Arrays.toString((boolean []) variant.getValue());
+// } else if (Datatypes.INTEGER_ARRAY.equals(dt)) {
+// return Arrays.toString((int []) variant.getValue());
+// } else if (Datatypes.LONG_ARRAY.equals(dt)) {
+// return Arrays.toString((long []) variant.getValue());
+// } else if (Datatypes.DOUBLE_ARRAY.equals(dt)) {
+// return Arrays.toString((double []) variant.getValue());
+// } else if (Datatypes.FLOAT_ARRAY.equals(dt)) {
+// return Arrays.toString((float []) variant.getValue());
+// } else if (Datatypes.BYTE_ARRAY.equals(dt)) {
+// return Arrays.toString((byte []) variant.getValue());
+//// } else if (dt instanceof ArrayType) {
+//// return Arrays.toString((Object []) variant.getValue());
+// } else {
+// byte[] data = Bindings.getSerializerUnchecked(variant.getBinding()).serialize(variant.getValue());
+// m.reset();
+// m.update(data, 0, data.length);
+// return "\"" + new BigInteger(1, m.digest()).toString(16) + "\"";
+// }
+
+ }
// void fixInstanceOf(TransferableGraph1 graph, ResourceInfo info) {
// Identity id = getIdentity(graph, info.resource);
int parentId = ext.parent;
//if(parentId == 0) return ext.name;
// else {
- Identity id = getIdentity(tg, parentId);
+ Identity id = TransferableGraphUtils.getIdentity(tg, parentId);
if(id.definition instanceof External) {
return getExternalURI(tg, (External)id.definition) + "/" + name;
} else if(id.definition instanceof Root) {
}
public static String getExternalURI(TransferableGraph1 tg, int resource) {
- Identity id = getIdentity(tg, resource);
+ Identity id = TransferableGraphUtils.getIdentity(tg, resource);
if(id == null) return null;
if(id.definition instanceof External) {
External ext = (External)id.definition;
}
- void indent(int indent) {
- for(int i=0;i<indent;i++) output.append(" ");
+ static void indent(StringBuilder output, int indent) {
+ for(int i=0;i<indent;i++)
+ output.append(" ");
}
- void printBlank(TransferableGraph1 graph, String predicateURI2, ResourceInfo info, int indent) {
+ String printBlank(TransferableGraph1 graph, String predicateURI2, ResourceInfo info, int indent) {
- if(info.hasURI) return;
- indent(indent);
+ if(info.hasURI)
+ return null;
+
+ StringBuilder output = new StringBuilder();
+ indent(output, indent);
output.append(predicateURI2 + " " + info.name + "\n");
- if(info.owner < 0) {
- printURI(graph, info, false, indent);
+ if (info.ownedResourcesWithPredicates.isEmpty()) {
+ String uri = printURI(graph, info, false, indent, false);
+ if (uri != null)
+ output.append(uri);
}
-
+// if(info.owner < 0) {
+// printURI(graph, info, false, indent);
+// }
+ return output.toString();
}
- long longStm(int predicate, int object) {
+ static long longStm(int predicate, int object) {
return (predicate<<32) | (object & 0xffffffffL);
}
+
+ private void addInlineStatement(TransferableGraph1 graph, Map<String, Set<String>> statements, String predicate, ResourceInfo objectInfo, int indent) {
+ Set<String> objects = statements.get(predicate);
+ if(objects == null) {
+ objects = new TreeSet<>();
+ statements.put(predicate, objects);
+ }
+ String uri = printURI(graph, objectInfo, false, indent + 1, true);
+ if (uri != null) {
+ // TODO: this is not the right place to remove trailing newline
+ uri = uri.endsWith("\n") ? uri.substring(0, uri.length() - 2) : uri;
+ objects.add(uri);
+ }
+ objectInfo.inlined = true;
+ }
+
+
void addStatement(Map<String,Set<String>> statements, String predicate, String object) {
+ // TODO: fix this
+ if (predicate.endsWith("Inverse"))
+ return;
Set<String> objects = statements.get(predicate);
if(objects == null) {
objects = new TreeSet<>();
objects.add(object);
}
- void printURI(TransferableGraph1 graph, ResourceInfo info, boolean requireURI, int indent) {
+ String printURI(TransferableGraph1 graph, ResourceInfo info, boolean requireURI, int indent, boolean inline) {
- if(requireURI && !info.hasURI) return;
+ if(requireURI && !info.hasURI)
+ return null;
+
+ // Check if this ResourceInfo is already inlined with some other ResourceInfo
+ if (info.inlined)
+ return null;
Map<String,Set<String>> statements = new TreeMap<>();
- Identity consistsOf = findExternal(graph, "http://www.simantics.org/Layer0-1.1/ConsistsOf");
+ Identity consistsOf = TransferableGraphUtils.findExternal(graph, "http://www.simantics.org/Layer0-1.1/ConsistsOf");
TLongHashSet processed = new TLongHashSet();
for(int i=0;i<info.owned.size();i+=2) {
long stmId = longStm(info.owned.get(i), info.owned.get(i+1));
processed.add(stmId);
}
- TIntArrayList rawStatements = getStatements(graph, info.resource);
+ TIntArrayList rawStatements = TransferableGraphUtils.getStatements(graph, info.resource);
for(int i=0;i<rawStatements.size();i+=2) {
long stmId = longStm(rawStatements.get(i), rawStatements.get(i+1));
if(!processed.add(stmId)) continue;
if(objectInfo == null) {
String objectURI = rewritePredicateURI(graph, rawStatements.get(i+1));
addStatement(statements, predicateURI, objectURI);
+ } else if (objectInfo.ownedBy.size() == 1 && objectInfo.ownedBy.contains(info)) {
+ // inline printing with _
+ addInlineStatement(graph, statements, predicateURI, objectInfo, indent);
} else {
addStatement(statements, predicateURI, objectInfo.name);
}
}
- if(indent == 0) {
+ HashSet<ResourceInfo> debug = new HashSet<>();
+ info.ownedResourcesWithPredicates.forEachEntry(new TIntIntProcedure() {
+
+ @Override
+ public boolean execute(int owner, int predicate) {
+ ResourceInfo ownerInfo = infos.get(owner);
+ debug.add(ownerInfo);
+// ResourceInfo predicateInfo = infos.get(predicate);
+// debug.add(predicateInfo);
+ return true;
+ }
+ });
+
+ StringBuilder output = new StringBuilder();
+
+ if(indent == 0 || inline) {
if("ROOT".equals(info.name)) {
output.append("ROOT=<http:/>");
} else if (info.aliasURI != null) {
output.append(info.name + " = <" + info.aliasURI + ">");
} else {
- output.append(info.name);
+ if (inline)
+ System.out.println("asdasd");
+ output.append(inline ? "_" : info.name);
}
Set<String> instanceOfs = statements.get("L0.InstanceOf");
if(instanceOfs != null) {
if("L0.Inherits".equals(predicate)) continue;
if("L0.PartOf".equals(predicate)) continue;
Set<String> objects = entry.getValue();
+ indent(output, indent+1);
if(objects.size() == 1) {
- indent(indent+1);
output.append(predicate + " " + objects.iterator().next() + "\n");
} else{
- indent(indent+1);
output.append(predicate + "\n");
for(String object : objects) {
- indent(indent+1);
+ indent(output, indent+1);
output.append(" " + object + "\n");
}
}
for(int i=0;i<info.owned.size();i+=2) {
String predicateURI = rewritePredicateURI(graph, info.owned.get(i));
ResourceInfo ownedInfo = infos.get(info.owned.get(i+1));
- printBlank(graph, predicateURI, ownedInfo, indent+1);
+ String blank = printBlank(graph, predicateURI, ownedInfo, indent+1);
+ if (blank != null)
+ output.append(blank);
}
+ return output.toString();
}
- void prettyPrint(Path input, Path output) throws Exception {
+ void prettyPrint(Path input, Path output) throws Exception {
System.out.format("Converting exported shared ontology%n\t" + input.toString() + "%nto bundle-compatible ontology%n\t" + output.toString());
try (InputStream is = new BufferedInputStream(Files.newInputStream(input), 128*1024)) {
void prettyPrint(TransferableGraph1 graph) throws Exception {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Starting prettyPrint for TransferableGraph with " + graph.resourceCount + " resources, " + graph.identities + " identities, " + graph.statements.length + " statements and " + graph.values.length + " values");
+
for(Identity id : graph.identities) {
if(id.definition instanceof Internal) {
Internal internal = (Internal)id.definition;
Identity parent = TransferableGraphUtils.getIdentity(graph, internal.parent);
if(parent.definition instanceof External) {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Resolving internal identity " + id);
String name = "BASE";
- ResourceInfo info = new ResourceInfo(true, name, id.resource);
+ ResourceInfo info = new ResourceInfo(true, name, id.resource, -1);
info.aliasURI = TransferableGraphUtils.getURI(graph, id.resource);
info.newResource = true;
infos.put(id.resource, info);
- for(Identity child : getChildren(graph, id)) {
- recurseURI(graph, child, name);
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug(" which parent is external " + parent + " and has an aliasURI " + info.aliasURI) ;
+ for(Identity child : TransferableGraphUtils.getChildren(graph, id)) {
+ recurseURI(graph, child, name, info.resource);
}
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug(" and has " + (infos.size() - 1) + " children");
}
} else if (id.definition instanceof External) {
External ext = (External)id.definition;
// Try to detect shared libraries
if(ext.name.contains("@")) {
-
+
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Detected an external shared library " + ext);
+
int index = ext.name.indexOf('@');
String prefix = ext.name.substring(0, index);
int index2 = ext.name.indexOf('/', index);
String ontology = index2 == -1 ? ext.name : ext.name.substring(0, index2);
String uri = TransferableGraphUtils.getURI(graph, id.resource);
+
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug(" which was resolved as URI=" + uri + " and prefix " + prefix);
+
ontologies.put(uri, prefix);
} else if (ext.name.contains("-")) {
-
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Resolving possible ontology " + ext);
String uri = TransferableGraphUtils.getURI(graph, id.resource);
Matcher m = versionExtractPattern.matcher(uri);
if (m.matches()) {
if(!ontologies.containsKey(uri)) {
int index = ext.name.indexOf('-');
- String prefix = ext.name.substring(0, index);
- ontologies.put(uri, prefix);
+ String prefix = ext.name.substring(0, index);
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug(" and it was resolved as URI=" + uri + " and prefix " + prefix);
+ ontologies.put(uri, prefix);
}
}
-
}
-
-
-
}
}
// Discover other resources
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Discovering other resources..");
+
TIntArrayList todo = new TIntArrayList();
for(ResourceInfo info : infos.valueCollection())
todo.add(info.resource);
+
while(!todo.isEmpty()) {
int resource = todo.removeAt(todo.size()-1);
discoverBlank(graph, resource, todo);
discoverOwners(graph, info);
// for(ResourceInfo info : infos.valueCollection())
// fixInstanceOf(graph, info);
- for(ResourceInfo info : infos.valueCollection())
- if(info.owner >= 0) {
- ResourceInfo ownerInfo = infos.get(info.owner);
- ownerInfo.owned.add(info.ownerPredicate);
- ownerInfo.owned.add(info.resource);
- }
-
+
+ for (ResourceInfo info : infos.valueCollection()) {
+// Old implementation
+// if (info.owner >= 0) {
+// ResourceInfo ownerInfo = infos.get(info.owner);
+// System.out.println("originalOwner : " + info.owner + " originalPredicate: " + info.ownerPredicate);
+// ownerInfo.owned.add(info.ownerPredicate);
+// ownerInfo.owned.add(info.resource);
+// }
+
+ if (!info.ownedResourcesWithPredicates.isEmpty() && info.ownedResourcesWithPredicates.size() == 1) {
+ info.ownedResourcesWithPredicates.forEachEntry(new TIntIntProcedure() {
+
+ @Override
+ public boolean execute(int owner, int predicate) {
+ ResourceInfo ownerInfo = infos.get(owner);
+ ownerInfo.owned.add(predicate);
+ ownerInfo.owned.add(info.resource);
+ return false;
+ }
+ });
+ }
+ }
+
+ // Resolve inverses from ownedBy list
+ for (ResourceInfo info : infos.valueCollection()) {
+ for (int i = 0; i < info.owned.size(); i+=2) {
+ int object = info.owned.get(i+1);
+ ResourceInfo inf = infos.get(object);
+ if (inf != null) {
+ info.ownedBy.remove(inf);
+ }
+ }
+ }
+
TreeMap<String,ResourceInfo> order = new TreeMap<>();
for(ResourceInfo info : infos.valueCollection())
order.put(info.name, info);
- for(ResourceInfo info : order.values())
- printURI(graph, info, true, 0);
+ for(ResourceInfo info : order.values()) {
+ String uri = printURI(graph, info, true, 0, false);
+ if (uri != null)
+ output.append(uri);
+ }
- for(ResourceInfo info : order.values())
- if(!info.hasURI && info.owner < 0)
- printURI(graph, info, false, 0);
+ for (ResourceInfo info : order.values()) {
+ if (!info.hasURI && info.ownedResourcesWithPredicates.size() != 1) {
+ String uri = printURI(graph, info, false, 0, false);
+ if (uri != null)
+ output.append(uri);
+ }
+ }
+// for(ResourceInfo info : order.values())
+// if(!info.hasURI && info.owner < 0)
+// printURI(graph, info, false, 0);
StringBuilder refs = new StringBuilder();
for(String ontology : referencedOntologies) {
String key = ontologies.get(ontology);
refs.append(key + " = <" + ontology + ">\n");
}
+ if (!referencedOntologies.isEmpty())
+ refs.append("\n");
output.insert(0, refs.toString());
}
- public static String print(TransferableGraph1 tg) throws Exception {
+ public static String print(TransferableGraph1 tg) throws Exception {
StringBuilder b = new StringBuilder();
new PrettyPrintTG(b).prettyPrint(tg);
return b.toString();