1 package org.simantics.graph.representation;
3 import java.io.BufferedInputStream;
4 import java.io.DataInput;
5 import java.io.DataInputStream;
6 import java.io.InputStream;
7 import java.math.BigInteger;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.nio.file.Paths;
11 import java.security.MessageDigest;
12 import java.security.NoSuchAlgorithmException;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
18 import java.util.Map.Entry;
20 import java.util.TreeMap;
21 import java.util.TreeSet;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24 import java.util.stream.Collectors;
26 import org.simantics.databoard.Bindings;
27 import org.simantics.databoard.binding.Binding;
28 import org.simantics.databoard.binding.mutable.Variant;
29 import org.simantics.databoard.container.DataContainers;
30 import org.simantics.databoard.parser.DataValuePrinter;
31 import org.simantics.databoard.parser.PrintFormat;
32 import org.simantics.databoard.parser.repository.DataValueRepository;
33 import org.simantics.databoard.util.URIStringUtils;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 import gnu.trove.list.array.TIntArrayList;
38 import gnu.trove.map.hash.THashMap;
39 import gnu.trove.map.hash.TIntIntHashMap;
40 import gnu.trove.map.hash.TIntObjectHashMap;
41 import gnu.trove.procedure.TIntIntProcedure;
42 import gnu.trove.set.hash.TLongHashSet;
45 * @author Antti Villberg
48 public class PrettyPrintTG {
50 private static final Logger LOGGER = LoggerFactory.getLogger(PrettyPrintTG.class);
52 private static final boolean DEBUG = false;
55 int newBlankCounter = 0;
56 Map<String, String> blankRewrites = new HashMap<>();
59 private final Pattern versionExtractPattern = Pattern.compile("^.*-(\\d+\\.\\d+)");
61 final StringBuilder output;
62 final Map<String, String> ontologies = new HashMap<>(knownOntologies);
63 final Set<String> referencedOntologies = new TreeSet<>();
65 private boolean ignoreIdentifiers;
67 private TransferableGraphQueries query;
69 static class ResourceInfo {
73 boolean newResource = false;
77 boolean inlined = false;
79 // -1 = no owner, -2 = multiple owners
81 // Set<ResourceInfo> ownedBy
82 Set<ResourceInfo> ownedBy = new HashSet<>();
84 // A Map<Integer, Integer> containing information about resource that
85 // this resource owns and what are the predicates for forming this
87 TIntIntHashMap ownedResourcesWithPredicates = new TIntIntHashMap();
90 // int ownerPredicate = 0;
91 String aliasURI = null;
92 TIntArrayList owned = new TIntArrayList();
94 // TIntObjectHashMap<TIntHashSet> statements = new
95 // TIntObjectHashMap<TIntHashSet>();
96 public ResourceInfo(boolean hasURI, String name, int resource, int parent) {
99 this.resource = resource;
100 this.parent = parent;
104 public String toString() {
105 return name + (aliasURI != null ? " = <" + aliasURI + ">" : "");
109 public PrettyPrintTG(TransferableGraph1 tg, StringBuilder b, boolean ignoreIdentifiers) throws NoSuchAlgorithmException {
111 m = MessageDigest.getInstance("SHA-256");
112 this.ignoreIdentifiers = ignoreIdentifiers;
114 this.query = new TransferableGraphQueries(tg);
117 public PrettyPrintTG(TransferableGraph1 tg) throws NoSuchAlgorithmException {
118 this(tg, new StringBuilder(), false);
121 TreeMap<String, ResourceInfo> orderedInfos = new TreeMap<>();
122 TIntObjectHashMap<ResourceInfo> infos = new TIntObjectHashMap<>();
124 private static String tgNodeName(String name) {
125 if (name.contains(" "))
126 return "\"" + name + "\"";
131 private ResourceInfo recurseURI(Map<String, ResourceInfo> infos, Identity identity, String parentName, int parentId) {
132 String name = parentName + "." + tgNodeName(TransferableGraphUtils.getName(identity));
133 int identityResource = identity.resource;
134 ResourceInfo info = new ResourceInfo(true, name, identityResource, parentId);
135 infos.put(name, info);
136 for (Identity child : query.getChildren(identity))
137 recurseURI(infos, child, name, identityResource);
142 * Sorts statements by predicateURI in natural order
148 private TreeMap<String, TreeSet<Integer>> sortByPredicateUniqueStatements(int resource) {
149 TreeMap<String, TreeSet<Integer>> results = new TreeMap<>();
150 TIntArrayList statements = query.getStatements(resource);
151 for (int i = 0; i < statements.size(); i += 2) {
152 int predicate = statements.get(i);
153 String predicateURI = query.getURI(predicate);
154 TreeSet<Integer> objects = results.get(predicateURI);
155 if (objects == null) {
156 objects = new TreeSet<>();
158 objects.add(statements.get(i + 1));
159 results.put(predicateURI, objects);
164 void discoverBlank(int resource, TIntArrayList todo) throws Exception {
165 // TIntArrayList statements =
166 // TransferableGraphUtils.getStatements(graph, resource);
167 // for(int i=0;i<statements.size();i+=2) {
168 for (TreeSet<Integer> objects : sortByPredicateUniqueStatements(resource).values()) {
169 for (int object : objects) {
170 // int object = statements.get(i+1);
171 Identity objectId = query.getIdentity(object);
172 if (objectId != null) {
173 if (objectId.definition instanceof External)
176 Value value = query.findValue(object);
178 infos.put(object, new ResourceInfo(false, printValue(value), object, resource));
180 ResourceInfo existing = infos.get(object);
181 if (existing == null) {
183 existing = new ResourceInfo(false, "blank" + blankCounter++, object, resource);
185 // System.out.println("created blank" + blankCounter + "
186 // with object " + object + " resource " + resource);
187 infos.put(object, existing);
195 private String makeHash(byte[] data) {
197 m.update(data, 0, data.length);
198 return new BigInteger(1, m.digest()).toString(16);
201 void discoverOwners(ResourceInfo info) {
202 log("Discovering owners for {}", info);
203 int resource = info.resource;
204 TIntArrayList statements = query.getStatements(resource);
205 for (int i = 0; i < statements.size(); i += 2) {
206 int predicate = statements.get(i);
207 int object = statements.get(i + 1);
208 ResourceInfo existing = infos.get(object);
209 if (existing != null) {
210 // Add all owners here for now and resolve the best owner later
212 // Check if predicate is inverse, this just resolves all
213 // predicates to be inverse with ending "Inverse"..
214 String predicateUri = rewritePredicateURI(predicate);
215 if (!predicateUri.endsWith("Inverse") && !predicateUri.endsWith("Of")) {
216 existing.ownedResourcesWithPredicates.put(resource, predicate);
217 // if (predicateUri.endsWith("Of")) {
218 // System.out.println("asd");
220 existing.ownedBy.add(info);
221 log(" {} owns {} with {}", existing, info, predicateUri);
224 // System.out.println("asd");
230 DataValueRepository repo = new DataValueRepository();
231 DataValuePrinter printer = new DataValuePrinter(null, repo);
233 String printValue(Value value) throws Exception {
234 StringBuilder sb = new StringBuilder();
235 printer.setFormat(PrintFormat.SINGLE_LINE);
236 printer.setOutput(sb);
238 Variant variant = value.value;
239 printer.print(variant.getBinding(), variant.getValue());
240 String formattedOutput = sb.toString();
241 if (formattedOutput.length() > 100) {
242 // Ok, value too long, lets calculate a hash for it and store first
243 // 100 chars as comment
244 byte[] data = Bindings.getSerializerUnchecked(variant.getBinding()).serialize(variant.getValue());
246 m.update(data, 0, data.length);
247 String hash = "\"" + new BigInteger(1, m.digest()).toString(16) + "\"";
248 return hash + " // " + formattedOutput.substring(0, 100) + "..";
250 return formattedOutput;
254 public String getExternalURI(External ext) {
255 String name = ext.name;
256 if (name.contains(" "))
257 name = name.replace(" ", "_").replaceAll("@", "_");// name = "\"" +
259 int parentId = ext.parent;
260 // if(parentId == 0) return ext.name;
262 Identity id = query.getIdentity(parentId);
263 if (id.definition instanceof External) {
264 return getExternalURI((External) id.definition) + "/" + URIStringUtils.escape(name);
265 } else if (id.definition instanceof Root) {
266 Root root = (Root) id.definition;
267 return "http:/" + URIStringUtils.escape(root.name) + "/" + URIStringUtils.escape(name);
274 public String getExternalURI(int resource) {
275 Identity id = query.getIdentity(resource);
278 if (id.definition instanceof External) {
279 External ext = (External) id.definition;
280 return getExternalURI(ext);
285 String rewritePredicateURI(int predicate) {
287 String uri = getExternalURI(predicate);
289 ResourceInfo info = infos.get(predicate);
295 for (String ontology : ontologies.keySet()) {
296 if (uri.contains(ontology)) {
297 String key = ontologies.get(ontology);
298 uri = uri.replace(ontology, key);
299 referencedOntologies.add(ontology);
303 uri = uri.replace("/", ".");
309 static void indent(StringBuilder output, int indent) {
310 for (int i = 0; i < indent; i++)
314 String printBlank(String predicateURI2, ResourceInfo info, int indent) {
319 StringBuilder output = new StringBuilder();
321 String infoName = info.name;
322 if (infoName.startsWith("blank")) {
323 infoName = getBlankRewrite(infoName);
326 if (ignoreIdentifiers) {
327 if (predicateURI2.contains("L0.identifier")) {
330 indent(output, indent);
331 output.append(predicateURI2 + " " + infoName + "\n");
334 indent(output, indent);
335 output.append(predicateURI2 + " " + infoName + "\n");
338 if (info.ownedResourcesWithPredicates.isEmpty()) {
340 System.out.print("printBlank");
341 String uri = printURI(info, false, indent, false);
345 // if(info.owner < 0) {
346 // printURI(graph, info, false, indent);
348 return output.toString();
351 private String getBlankRewrite(String infoName) {
352 String rewrite = blankRewrites.get(infoName);
353 if (rewrite == null) {
354 rewrite = "rblank" + newBlankCounter++;
356 System.out.println("rewrote " + infoName + " to " + rewrite);
357 blankRewrites.put(infoName, rewrite);
363 static long longStm(int predicate, int object) {
364 return ((predicate & 0xffffffffL) << 32) | (object & 0xffffffffL);
367 private void addInlineStatement(Map<String, Set<String>> statements, String predicate,
368 ResourceInfo objectInfo, int indent) {
369 Set<String> objects = statements.get(predicate);
370 if (objects == null) {
371 objects = new TreeSet<>();
372 statements.put(predicate, objects);
374 String uri = printURI(objectInfo, false, indent + 1, true);
376 // TODO: this is not the right place to remove trailing newline
377 uri = uri.endsWith("\n") ? uri.substring(0, uri.length() - 2) : uri;
380 objectInfo.inlined = true;
383 void addStatement(Map<String, Set<String>> statements, String predicate, String object) {
385 if (predicate.endsWith("Inverse"))
387 Set<String> objects = statements.get(predicate);
388 if (objects == null) {
389 objects = new TreeSet<>();
390 statements.put(predicate, objects);
395 String printURI(ResourceInfo info, boolean requireURI, int indent, boolean inline) {
397 if (requireURI && !info.hasURI)
400 // Check if this ResourceInfo is already inlined with some other
405 Map<String, Set<String>> statements = new TreeMap<>();
406 Identity consistsOf = query.findExternalByURI("http://www.simantics.org/Layer0-1.1/ConsistsOf");
407 // Identity partOf = TransferableGraphUtils.findExternal(graph,
408 // "http://www.simantics.org/Layer0-1.1/PartOf");
409 TLongHashSet processed = new TLongHashSet();
411 System.out.println("info.owned.size " + info.owned.size() + info.owned);
412 for (int i = 0; i < info.owned.size(); i += 2) {
413 int predicate = info.owned.get(i);
414 int object = info.owned.get(i + 1);
415 long stmId = longStm(predicate, object);
418 " " + stmId + " is already processed as it is owned (" + predicate + " " + object + ")");
419 processed.add(stmId);
422 TreeMap<String, List<Integer>> predicateURIs = new TreeMap<>();
424 TIntArrayList rawStatements = query.getStatements(info.resource);
427 "rawStatements size for " + info.name + " : " + rawStatements.size() + " " + rawStatements);
428 for (int i = 0; i < rawStatements.size(); i += 2) {
429 int predicate = rawStatements.get(i);
430 int object = rawStatements.get(i + 1);
431 long stmId = longStm(predicate, object);
432 if (!processed.add(stmId)) {
434 System.out.println(" " + stmId + " is already processed (" + (predicate & 0xffffffffL) + " "
435 + (object & 0xffffffffL) + ")");
439 System.out.println(" " + stmId + " is currently being processed (" + (predicate & 0xffffffffL) + " "
440 + (object & 0xffffffffL) + ")");
441 // if (partOf.resource == rawStatements.get(i))
443 if (consistsOf.resource == predicate) {
444 // if (!info.owned.isEmpty() && !info.name.startsWith("blank"))
447 System.out.println(" is consistsof " + predicate + " (" + consistsOf.resource + ")");
450 // // this will be inlined so lets indent
454 String predicateURI = rewritePredicateURI(predicate);
455 List<Integer> objects = predicateURIs.get(predicateURI);
456 if (objects == null) {
457 objects = new ArrayList<>();
458 predicateURIs.put(predicateURI, objects);
462 for (Entry<String, List<Integer>> entry : predicateURIs.entrySet()) {
463 String predicateURI = entry.getKey();
464 List<Integer> objects = entry.getValue();
465 for (int object : objects) {
466 ResourceInfo objectInfo = infos.get(object);
467 if (objectInfo == null) {
468 String objectURI = rewritePredicateURI(object);
470 System.out.println(" adding statement " + predicateURI + " " + objectURI);
471 addStatement(statements, predicateURI, objectURI);
472 } else if (objectInfo.ownedBy.size() == 1 && objectInfo.ownedBy.contains(info)) {
473 // inline printing with _
475 System.out.println(" adding inline statement " + predicateURI + " " + objectInfo.name);
476 addInlineStatement(statements, predicateURI, objectInfo, indent);
478 String objectName = objectInfo.name;
479 if (objectName.startsWith("blank")) {
480 objectName = getBlankRewrite(objectName);
483 System.out.println(" adding statement " + predicateURI + " " + objectName);
484 addStatement(statements, predicateURI, objectName);
491 "statements size for " + info.name + " : " + statements.size() + " " + statements.keySet());
493 StringBuilder output = new StringBuilder();
495 if (indent == 0 || inline) {
496 if ("ROOT".equals(info.name)) {
497 output.append("ROOT=<http:/>");
498 } else if (info.aliasURI != null) {
499 output.append(info.name + " = <" + info.aliasURI + ">");
501 String infoName = info.name;
502 if (infoName.startsWith("blank")) {
503 infoName = getBlankRewrite(infoName);
505 output.append(inline ? "_" : infoName);
507 Set<String> instanceOfs = statements.get("L0.InstanceOf");
508 if (instanceOfs != null) {
509 for (String instanceOf : instanceOfs) {
510 output.append(" : " + instanceOf);
513 Set<String> subrelationOfs = statements.get("L0.SubrelationOf");
514 if (subrelationOfs != null) {
515 for (String subrelationOf : subrelationOfs) {
516 output.append(" <R " + subrelationOf);
519 Set<String> inherits = statements.get("L0.Inherits");
520 if (inherits != null) {
521 for (String inherit : inherits) {
522 output.append(" <T " + inherit);
528 if (info.newResource)
529 output.append(" @L0.new\n");
531 for (Map.Entry<String, Set<String>> entry : statements.entrySet()) {
532 String predicate = entry.getKey();
533 if (ignoreIdentifiers) {
534 if (predicate.equals("L0.identifier")) {
538 if ("L0.InstanceOf".equals(predicate))
540 if ("L0.SubrelationOf".equals(predicate))
542 if ("L0.Inherits".equals(predicate))
544 if ("L0.PartOf".equals(predicate))
547 // predicates can be blank
548 if (predicate.startsWith("blan")) {
549 predicate = getBlankRewrite(predicate);
552 Set<String> objects = entry.getValue();
553 indent(output, indent + 1);
554 if (objects.size() == 1) {
555 output.append(predicate + " " + objects.iterator().next() + "\n");
557 output.append(predicate + "\n");
558 for (String object : objects) {
559 indent(output, indent + 1);
560 output.append(" " + object + "\n");
565 TreeMap<String, Set<Integer>> ownedOrdered = new TreeMap<>();
567 for (int i = 0; i < info.owned.size(); i += 2) {
568 String predicateURI = rewritePredicateURI(info.owned.get(i));
569 Set<Integer> owneds = ownedOrdered.get(predicateURI);
570 if (owneds == null) {
571 owneds = new TreeSet<>();
572 ownedOrdered.put(predicateURI, owneds);
574 owneds.add(info.owned.get(i + 1));
578 System.out.println(info.name + " : " + ownedOrdered.keySet());
580 for (Entry<String, Set<Integer>> entry : ownedOrdered.entrySet()) {
581 String predicateURI = entry.getKey();
582 Set<Integer> owneds = entry.getValue();
583 for (int owned : owneds) {
584 ResourceInfo ownedInfo = infos.get(owned);
586 String blank = printBlank(predicateURI, ownedInfo, indent + 1);
588 output.append(blank);
593 return output.toString();
596 static Map<String, String> knownOntologies = new HashMap<>();
599 knownOntologies.put("http://www.simantics.org/Layer0-1.1", "L0");
600 knownOntologies.put("http://www.simantics.org/Layer0X-1.1", "L0X");
601 knownOntologies.put("http://www.simantics.org/Modeling-1.2", "MOD");
602 knownOntologies.put("http://www.simantics.org/Diagram-2.2", "DIA");
603 knownOntologies.put("http://www.simantics.org/Structural-1.2", "STR");
604 knownOntologies.put("http://www.simantics.org/Document-1.2", "DOC");
605 knownOntologies.put("http://www.simantics.org/Documentation-1.2", "DOCU");
606 knownOntologies.put("http://www.simantics.org/G2D-1.1", "G2D");
607 knownOntologies.put("http://www.simantics.org/SelectionView-1.2", "SEL");
608 knownOntologies.put("http://www.simantics.org/Viewpoint-1.2", "VP");
609 knownOntologies.put("http://www.simantics.org/Image2-1.2", "IMAGE2");
610 knownOntologies.put("http://www.simantics.org/GraphFile-0.1", "GRAPHFILE");
611 knownOntologies.put("http://www.simantics.org/Project-1.2", "PROJECT");
612 knownOntologies.put("http://www.semantum.fi/Simupedia-1.0", "SIMUPEDIA");
613 knownOntologies.put("http://www.semantum.fi/SimupediaWorkbench-1.0", "SIMUPEDIA_WORKBENCH");
616 void prettyPrint() throws Exception {
617 log("Starting prettyPrint for TransferableGraph with {} resources, {} identities, {} statements and {} values",
618 query.getGraph().resourceCount, query.getGraph().identities, query.getGraph().statements.length, query.getGraph().values.length);
620 query.forIdentities(id -> {
621 int identityResource = id.resource;
622 if (id.definition instanceof Internal) {
623 Internal internal = (Internal) id.definition;
624 Identity parent = query.getIdentity(internal.parent);
625 if (parent.definition instanceof External || parent.definition instanceof Root) {
626 log("Resolving internal identity {}", id);
627 String name = "BASE";
628 ResourceInfo info = new ResourceInfo(true, name, identityResource, -1);
629 info.aliasURI = query.getURI(identityResource);
630 info.newResource = true;
631 orderedInfos.put(name, info);
632 // infos.put(id.resource, info);
633 log(" which parent is external {} and has an aliasURI {}", parent, info.aliasURI);
634 for (Identity child : query.getChildren(id))
635 recurseURI(orderedInfos, child, name, identityResource);
636 log(" and has {} children", infos.size());
638 } else if (id.definition instanceof External) {
639 External ext = (External) id.definition;
640 // Try to detect shared libraries
641 if (ext.name.contains("@")) {
643 log("Detected an external shared library {}", ext);
645 int index = ext.name.indexOf('@');
646 String prefix = ext.name.substring(0, index);
647 int index2 = ext.name.indexOf('/', index);
648 String ontology = index2 == -1 ? ext.name : ext.name.substring(0, index2);
649 String uri = query.getURI(identityResource);
651 log(" which was resolved as URI={} and prefix={}", uri, prefix);
653 ontologies.put(uri, prefix);
655 } else if (ext.name.contains("-")) {
656 log("Resolving possible ontology {}", ext);
657 String uri = query.getURI(identityResource);
658 Matcher m = versionExtractPattern.matcher(uri);
660 if (!ontologies.containsKey(uri)) {
661 int index = ext.name.indexOf('-');
662 String prefix = ext.name.substring(0, index);
663 log(" and it was resolved as URI={} and prefix {}", uri, prefix);
664 ontologies.put(uri, prefix);
672 // Discover other resources
673 log("Discovering other resources..");
675 TIntArrayList todo = new TIntArrayList();
676 for (ResourceInfo info : orderedInfos.values()) {
677 todo.add(info.resource);
679 // put orderedInfos to infos
680 infos.put(info.resource, info);
683 while (!todo.isEmpty()) {
684 int resource = todo.removeAt(todo.size() - 1);
685 discoverBlank(resource, todo);
687 for (ResourceInfo info : infos.valueCollection())
688 discoverOwners(info);
689 // for(ResourceInfo info : infos.valueCollection())
690 // fixInstanceOf(graph, info);
692 for (ResourceInfo info : infos.valueCollection()) {
693 // Old implementation
694 // if (info.owner >= 0) {
695 // ResourceInfo ownerInfo = infos.get(info.owner);
696 // System.out.println("originalOwner : " + info.owner + "
697 // originalPredicate: " + info.ownerPredicate);
698 // ownerInfo.owned.add(info.ownerPredicate);
699 // ownerInfo.owned.add(info.resource);
702 if (!info.ownedResourcesWithPredicates.isEmpty() && info.ownedResourcesWithPredicates.size() == 1) {
703 info.ownedResourcesWithPredicates.forEachEntry(new TIntIntProcedure() {
706 public boolean execute(int owner, int predicate) {
708 ResourceInfo ownerInfo = infos.get(owner);
709 ownerInfo.owned.add(predicate);
710 ownerInfo.owned.add(info.resource);
715 System.err.println("Here we are with " + info);
719 // Resolve inverses from ownedBy list
720 for (ResourceInfo info : infos.valueCollection()) {
721 for (int i = 0; i < info.owned.size(); i += 2) {
722 int object = info.owned.get(i + 1);
723 ResourceInfo inf = infos.get(object);
725 info.ownedBy.remove(inf);
730 Identity routeGraphConn = query.findExternalByURI("http://www.simantics.org/Diagram-2.2/RouteGraphConnection");
731 Identity instanceOf = query.findExternalByURI("http://www.simantics.org/Layer0-1.1/InstanceOf");
732 Identity diagramConnetionToConnection = query.findExternalByURI("http://www.simantics.org/Modeling-1.2/DiagramConnectionToConnection");
734 Identity elemTo = query.findExternalByURI("http://www.simantics.org/Modeling-1.2/ElementToComponent");
735 for (ResourceInfo infoo : infos.valueCollection()) {
736 if (elemTo != null) {
737 int elemToComponent = query.getPossibleObject(infoo.resource, elemTo);
738 if (elemToComponent != TransferableGraphUtils.NOT_FOUND) {
740 Identity component = query.getIdentity(elemToComponent);
741 Identity internal = query.getIdentity(infoo.resource);
742 if (internal.definition instanceof Internal && component.definition instanceof Internal) {
743 Internal iComponent = (Internal) component.definition;
744 infoo.name = infoo.name.substring(0, infoo.name.lastIndexOf(".") + 1) + iComponent.name;
749 if (instanceOf != null) {
750 int instOf = query.getPossibleObject( infoo.resource, instanceOf);
751 if (instOf != TransferableGraphUtils.NOT_FOUND && routeGraphConn != null) {
752 if (instOf == routeGraphConn.resource) {
753 // Found routegraphconnection, change name
754 // Lets go to configuration
756 int connection = query.getPossibleObject( infoo.resource,
757 diagramConnetionToConnection);
758 if (connection != TransferableGraphUtils.NOT_FOUND) {
759 // Gather all inverse statements to construct unique
761 List<String> nameParts = new ArrayList<>();
762 TIntArrayList statements = query.getStatements(connection);
763 for (int i = 0; i < statements.size(); i += 2) {
764 int predicate = statements.get(i);
765 Identity possibleInverse = query.getIdentity(predicate);
766 if (possibleInverse != null) {
767 int inverseRelation = TransferableGraphUtils.NOT_FOUND;
768 int parentId = TransferableGraphUtils.NOT_FOUND;
769 if (possibleInverse.definition instanceof Internal) {
770 Internal iPossibleInverse = (Internal) possibleInverse.definition;
771 if (iPossibleInverse.name.equals("Inverse")) {
772 inverseRelation = query.getPossibleObject(
773 connection, possibleInverse);
774 parentId = iPossibleInverse.parent;
776 log("Unsupported inverse relation found for {} {}", infoo, iPossibleInverse);
778 } else if (possibleInverse.definition instanceof External) {
779 External ePossibleInverse = (External) possibleInverse.definition;
780 if (ePossibleInverse.name.equals("Inverse")) {
781 inverseRelation = query.getPossibleObject(
782 connection, possibleInverse);
783 parentId = ePossibleInverse.parent;
785 log("This external inverse is unsupported for {} {}", infoo, ePossibleInverse);
788 log("This type of definition is not supported {}", infoo);
790 if (inverseRelation != TransferableGraphUtils.NOT_FOUND) {
791 // Ok found something
792 Identity object = query.getIdentity(inverseRelation);
793 Identity parent = query.getIdentity(parentId);
794 String objectName, parentName;
795 if (object.definition instanceof Internal) {
796 objectName = ((Internal) object.definition).name;
797 } else if (object.definition instanceof External) {
798 objectName = ((External) object.definition).name;
800 log("This type of definition is not supported {}", infoo);
801 throw new Error("UNSUPPORTED " + infoo);
803 if (parent.definition instanceof Internal) {
804 parentName = ((Internal) parent.definition).name;
805 } else if (parent.definition instanceof External) {
806 parentName = ((External) parent.definition).name;
808 log("This type of definition is not supported {}", infoo);
809 throw new Error("UNSUPPORTED " + infoo);
811 String fullName = parentName + "_" + objectName;
812 nameParts.add(fullName);
814 log("No inverse relation found for {}", infoo);
817 log("Did not find possible inverse relation for {}", infoo);
820 nameParts.sort((o1, o2) -> o1.compareTo(o2));
822 for (String namep : nameParts) {
825 infoo.name = infoo.name.substring(0, infoo.name.lastIndexOf(".") + 1) + name;
827 LOGGER.error("Could not find connection for " + infoo + ". Statements of graph below");
828 LOGGER.error("Subject -> Predicate : " + infoo.resource + " -> "
829 + diagramConnetionToConnection.resource);
835 for (ResourceInfo info : infos.valueCollection()) {
836 if (info.name.startsWith("blank")) {
837 info.name = "blank" + findHash(info);
841 TreeMap<String, ResourceInfo> order = new TreeMap<>();
842 for (ResourceInfo info : infos.valueCollection())
843 order.put(info.name, info);
845 for (ResourceInfo info : order.values()) {
847 System.out.print("info ");
848 String uri = printURI(info, true, 0, false);
853 TreeMap<String, ResourceInfo> rblanks = new TreeMap<>();
855 for (ResourceInfo info : order.values()) {
856 if (!info.hasURI && info.ownedResourcesWithPredicates.size() != 1) {
858 System.out.print("ownedResources ");
859 if (info.name.startsWith("blank")) {
860 // These will be printed later
861 rblanks.put(getBlankRewrite(info.name), info);
863 String uri = printURI(info, false, 0, false);
869 // Now print blanks in order
870 for (ResourceInfo info : rblanks.values()) {
871 if (!info.hasURI && info.ownedResourcesWithPredicates.size() != 1) {
873 System.out.print("ownedResources ");
874 String uri = printURI(info, false, 0, false);
880 // for(ResourceInfo info : order.values())
881 // if(!info.hasURI && info.owner < 0)
882 // printURI(graph, info, false, 0);
884 StringBuilder refs = new StringBuilder();
885 for (String ontology : referencedOntologies) {
886 String key = ontologies.get(ontology);
887 refs.append(key + " = <" + ontology + ">\n");
889 if (!referencedOntologies.isEmpty())
891 output.insert(0, refs.toString());
895 private String calculateHash(ResourceInfo info) {
896 StringBuilder statementHash = new StringBuilder();
897 TreeSet<String> parts = new TreeSet<>();
898 for (int i = 0; i < info.owned.size(); i += 2) {
899 int predicate = info.owned.get(i);
900 int object = info.owned.get(i + 1);
901 // Lets resolve a unique name for this based on the statements this
904 String predicatee = rewritePredicateURI(predicate);
905 ResourceInfo objInfo = infos.get(object);
906 parts.add(predicatee + "->" + objInfo.name + ";;;");
908 // Remove this from the list
909 List<ResourceInfo> filtered = info.ownedBy.stream().filter(ri -> !ri.name.startsWith("blank"))
910 .collect(Collectors.toList());
911 for (ResourceInfo ownedBy : filtered) {
912 parts.add(ownedBy.name);
915 ResourceInfo parentInfo = infos.get(info.parent);
916 if (parentInfo != null && !parentInfo.name.startsWith("blank")) {
917 parts.add("parent" + parentInfo.name);
919 // LOGGER.error("This should not happen");
921 for (String s : parts) {
922 statementHash.append(s);
924 String hash = makeHash(statementHash.toString().getBytes());
926 System.out.println(statementHash + " -> " + hash);
930 private String findHash(ResourceInfo info) {
931 if (info.name.startsWith("blank")) {
932 String hash = hashes.get(info.name);
934 String oldName = info.name;
936 System.out.print("calculating hash for " + oldName + " ");
937 hash = calculateHash(info);
938 if (hashes.put(oldName, hash) != null) {
939 System.err.println("!!!!A clash occured for " + info + " with hash " + hash);
948 private THashMap<String, String> hashes = new THashMap<>();
950 public static String print(TransferableGraph1 tg, boolean ignoreIdentifiers) throws Exception {
951 StringBuilder b = new StringBuilder();
952 new PrettyPrintTG(tg, b, ignoreIdentifiers).prettyPrint();
956 public static void main(String[] args) throws Exception {
957 if (args.length < 1) {
958 System.out.println("Required arguments: <input .sharedOntology file> [<output .tg file>]");
962 if (args.length < 2) {
963 input = Paths.get(args[0]);
964 output = input.getParent().resolve(input.getName(input.getNameCount() - 1) + ".fixed");
966 input = Paths.get(args[0]);
967 output = Paths.get(args[1]);
969 System.out.format("Converting exported shared ontology%n\t" + input.toString()
970 + "%nto bundle-compatible ontology%n\t" + output.toString());
971 try (InputStream is = new BufferedInputStream(Files.newInputStream(input), 128 * 1024)) {
972 DataInput dis = new DataInputStream(is);
973 org.simantics.databoard.container.DataContainer container = DataContainers.readFile(dis);
974 Binding binding = TransferableGraph1.BINDING;
975 TransferableGraph1 graph = (TransferableGraph1) container.content.getValue(binding);
976 new PrettyPrintTG(graph).prettyPrint();
980 private static void log(String string, Object... args) {
981 if (LOGGER.isDebugEnabled() && DEBUG)
982 LOGGER.debug(string, args);