package org.simantics.graph.representation; import java.io.BufferedInputStream; import java.io.DataInput; import java.io.DataInputStream; import java.io.InputStream; import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.regex.Matcher; 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 gnu.trove.list.array.TIntArrayList; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.set.hash.TLongHashSet; /** * @author Antti Villberg * @since 1.24.0 */ public class PrettyPrintTG extends TransferableGraphUtils { int blankCounter = 0; MessageDigest m; private final Pattern versionExtractPattern = Pattern.compile("^.*-(\\d+\\.\\d+)"); final StringBuilder output; final Map ontologies = new HashMap<>(knownOntologies); final Set referencedOntologies = new TreeSet<>(); static class ResourceInfo { final boolean hasURI; final String name; final int resource; boolean newResource = false; // -1 = no owner, -2 = multiple owners int owner = -1; int ownerPredicate = 0; String aliasURI = null; TIntArrayList owned = new TIntArrayList(); //TIntObjectHashMap statements = new TIntObjectHashMap(); public ResourceInfo(boolean hasURI, String name, int resource) { this.hasURI = hasURI; this.name = name; this.resource = resource; } } public PrettyPrintTG(StringBuilder b) throws NoSuchAlgorithmException { output = b; m = MessageDigest.getInstance("SHA-256"); } public PrettyPrintTG() throws NoSuchAlgorithmException { this(new StringBuilder()); } TIntObjectHashMap infos = new TIntObjectHashMap<>(); String tgNodeName(String name) { if(name.contains(" ")) return "\"" + name + "\""; 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); infos.put(parent.resource, info); for(Identity child : getChildren(graph, parent)) { recurseURI(graph, child, name); } return info; } void discoverBlank(TransferableGraph1 graph, int resource, TIntArrayList todo) throws Exception { TIntArrayList statements = getStatements(graph, resource); for(int i=0;i " + predicateURI + " " + existing.name); } else { existing.owner = -2; //System.err.println("Multiple owners " + info.name + " => " + predicateURI + " " + existing.name); } } } 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) + "\""; } } // void fixInstanceOf(TransferableGraph1 graph, ResourceInfo info) { // Identity id = getIdentity(graph, info.resource); // if(id == null) return; // if(id.definition instanceof Internal) { // Identity instanceOf = findExternal(graph, "http://www.simantics.org/Layer0-1.1/InstanceOf"); // Identity library = findExternal(graph, "http://www.simantics.org/Layer0-1.1/Library"); // info.statements.add(instanceOf.resource); // info.statements.add(library.resource); // } // } public static String getExternalURI(TransferableGraph1 tg, External ext) { String name = ext.name; if(name.contains(" ")) name = name.replace(" ", "_").replaceAll("@", "_");//name = "\"" + name + "\""; int parentId = ext.parent; //if(parentId == 0) return ext.name; // else { Identity id = getIdentity(tg, parentId); if(id.definition instanceof External) { return getExternalURI(tg, (External)id.definition) + "/" + name; } else if(id.definition instanceof Root) { Root root = (Root)id.definition; return "http:/" + root.name + "/" + name; } else { return null; } // } } public static String getExternalURI(TransferableGraph1 tg, int resource) { Identity id = getIdentity(tg, resource); if(id == null) return null; if(id.definition instanceof External) { External ext = (External)id.definition; return getExternalURI(tg, ext); } return null; } String rewritePredicateURI(TransferableGraph1 graph, int predicate) { String uri = getExternalURI(graph, predicate); if(uri == null) { ResourceInfo info = infos.get(predicate); if(info != null) return info.name; return "_"; } for(String ontology : ontologies.keySet()) { if(uri.contains(ontology)) { String key = ontologies.get(ontology); uri = uri.replace(ontology, key); referencedOntologies.add(ontology); } } uri = uri.replace("/", "."); return uri; } void indent(int indent) { for(int i=0;i> statements, String predicate, String object) { Set objects = statements.get(predicate); if(objects == null) { objects = new TreeSet<>(); statements.put(predicate, objects); } objects.add(object); } void printURI(TransferableGraph1 graph, ResourceInfo info, boolean requireURI, int indent) { if(requireURI && !info.hasURI) return; Map> statements = new TreeMap<>(); Identity consistsOf = findExternal(graph, "http://www.simantics.org/Layer0-1.1/ConsistsOf"); TLongHashSet processed = new TLongHashSet(); for(int i=0;i"); } else if (info.aliasURI != null) { output.append(info.name + " = <" + info.aliasURI + ">"); } else { output.append(info.name); } Set instanceOfs = statements.get("L0.InstanceOf"); if(instanceOfs != null) { for(String instanceOf : instanceOfs) { output.append(" : " + instanceOf); } } Set subrelationOfs = statements.get("L0.SubrelationOf"); if(subrelationOfs != null) { for(String subrelationOf : subrelationOfs) { output.append(" inherits = statements.get("L0.Inherits"); if(inherits != null) { for(String inherit : inherits) { output.append(" > entry : statements.entrySet()) { String predicate = entry.getKey(); if("L0.InstanceOf".equals(predicate)) continue; if("L0.SubrelationOf".equals(predicate)) continue; if("L0.Inherits".equals(predicate)) continue; if("L0.PartOf".equals(predicate)) continue; Set objects = entry.getValue(); 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); output.append(" " + object + "\n"); } } } for(int i=0;i knownOntologies = new HashMap<>(); static { knownOntologies.put("http://www.simantics.org/Layer0-1.1", "L0"); knownOntologies.put("http://www.simantics.org/Layer0X-1.1", "L0X"); knownOntologies.put("http://www.simantics.org/Modeling-1.2", "MOD"); knownOntologies.put("http://www.simantics.org/Diagram-2.2", "DIA"); knownOntologies.put("http://www.simantics.org/Structural-1.2", "STR"); knownOntologies.put("http://www.simantics.org/Document-1.2", "DOC"); knownOntologies.put("http://www.simantics.org/Documentation-1.2", "DOCU"); knownOntologies.put("http://www.simantics.org/G2D-1.1", "G2D"); knownOntologies.put("http://www.simantics.org/SelectionView-1.2", "SEL"); knownOntologies.put("http://www.simantics.org/Viewpoint-1.2", "VP"); knownOntologies.put("http://www.simantics.org/Image2-1.2", "IMAGE2"); knownOntologies.put("http://www.simantics.org/GraphFile-0.1", "GRAPHFILE"); knownOntologies.put("http://www.simantics.org/Project-1.2", "PROJECT"); knownOntologies.put("http://www.semantum.fi/Simupedia-1.0", "SIMUPEDIA"); knownOntologies.put("http://www.semantum.fi/SimupediaWorkbench-1.0", "SIMUPEDIA_WORKBENCH"); } void prettyPrint(TransferableGraph1 graph) throws Exception { 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) { String name = "BASE"; ResourceInfo info = new ResourceInfo(true, name, id.resource); 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); } } } else if (id.definition instanceof External) { External ext = (External)id.definition; // Try to detect shared libraries if(ext.name.contains("@")) { 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); ontologies.put(uri, prefix); } else if (ext.name.contains("-")) { 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); } } } } } // Discover 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); } for(ResourceInfo info : infos.valueCollection()) 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); } TreeMap 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()) 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"); } output.insert(0, refs.toString()); } public static String print(TransferableGraph1 tg) throws Exception { StringBuilder b = new StringBuilder(); new PrettyPrintTG(b).prettyPrint(tg); return b.toString(); } public static void main(String[] args) throws Exception { if (args.length < 1) { System.out.println("Required arguments: []"); } else if (args.length < 2) { Path input = Paths.get(args[0]); Path output = input.getParent().resolve(input.getName(input.getNameCount()-1) + ".fixed"); new PrettyPrintTG().prettyPrint(input, output); } else { new PrettyPrintTG().prettyPrint(Paths.get(args[0]), Paths.get(args[1])); } } }