+package org.simantics.graph.compiler;\r
+\r
+import gnu.trove.list.array.TIntArrayList;\r
+import gnu.trove.map.hash.TIntIntHashMap;\r
+import gnu.trove.map.hash.TIntObjectHashMap;\r
+import gnu.trove.set.hash.TIntHashSet;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.parser.unparsing.DataTypePrinter;\r
+import org.simantics.databoard.type.Datatype;\r
+import org.simantics.graph.query.CompositeGraph;\r
+import org.simantics.graph.query.IGraph;\r
+import org.simantics.graph.query.Path;\r
+import org.simantics.graph.query.Paths;\r
+import org.simantics.graph.query.Res;\r
+import org.simantics.graph.query.TransferableGraphConversion;\r
+import org.simantics.graph.query.UriUtils;\r
+import org.simantics.graph.representation.External;\r
+import org.simantics.graph.representation.Identity;\r
+import org.simantics.graph.representation.Internal;\r
+import org.simantics.graph.representation.LocalStatement;\r
+import org.simantics.graph.representation.Optional;\r
+import org.simantics.graph.representation.TransferableGraph1;\r
+import org.simantics.graph.representation.Value;\r
+import org.simantics.graph.store.GraphStore;\r
+import org.simantics.graph.store.IStatementProcedure;\r
+\r
+public class GraphUnparser {\r
+ IGraph graph;\r
+ GraphStore store;\r
+ StringBuilder b = new StringBuilder(); \r
+ \r
+ GraphUnparser(IGraph graph, GraphStore store) {\r
+ this.graph = graph;\r
+ this.store = store;\r
+ }\r
+ \r
+ ArrayList<Identity> uriRes = new ArrayList<Identity>();\r
+ TIntHashSet blankResources = new TIntHashSet(); \r
+ TIntObjectHashMap<String> refNames = new TIntObjectHashMap<String>();\r
+ TIntHashSet parentNameUsed = new TIntHashSet();\r
+ TIntObjectHashMap<String> parentNames = new TIntObjectHashMap<String>();\r
+ \r
+ TIntHashSet activeResources = new TIntHashSet(); // Resources that have statements \r
+ TIntObjectHashMap<ArrayList<LocalStatement>> localStatements = \r
+ new TIntObjectHashMap<ArrayList<LocalStatement>>();\r
+ TIntObjectHashMap<String> uris = new TIntObjectHashMap<String>(); \r
+ TIntObjectHashMap<String> literals = new TIntObjectHashMap<String>();\r
+ \r
+ int SimanticsDomain;\r
+ int Layer0;\r
+ int Inherits;\r
+ int InstanceOf;\r
+ int DataType;\r
+ int SubrelationOf;\r
+ \r
+ void handleIdentity(Identity id) {\r
+ int resource = id.resource;\r
+ int parent;\r
+ String name;\r
+ if(id.definition instanceof External) {\r
+ External def = (External)id.definition;\r
+ parent = def.parent;\r
+ name = def.name;\r
+ }\r
+ else if(id.definition instanceof Internal) {\r
+ Internal def = (Internal)id.definition;\r
+ parent = def.parent;\r
+ name = def.name;\r
+ }\r
+ else if(id.definition instanceof Optional) {\r
+ Optional def = (Optional)id.definition;\r
+ parent = def.parent;\r
+ name = def.name;\r
+ }\r
+ else\r
+ return;\r
+ \r
+ uris.put(id.resource, uris.get(parent) + "/" + name); \r
+ if(isIdentifier(name)) {\r
+ if(parentNames.containsKey(parent)) {\r
+ refNames.put(resource, parentNames.get(parent) + "." + name);\r
+ parentNameUsed.add(parent);\r
+ }\r
+ else\r
+ refNames.put(resource, "<" + uris.get(resource) + ">");\r
+ parentNames.put(resource, name);\r
+ }\r
+ else {\r
+ refNames.put(resource, "<" + uris.get(resource) + ">");\r
+ String[] parts = name.split("-");\r
+ if(isIdentifier(parts[0]))\r
+ parentNames.put(resource, parts[0]);\r
+ }\r
+ if(activeResources.remove(resource)) { \r
+ uriRes.add(id); \r
+ }\r
+ if(parent == 0) {\r
+ if(name.equals("www.simantics.org"))\r
+ SimanticsDomain = resource;\r
+ }\r
+ else if(parent == SimanticsDomain) {\r
+ if(name.equals("Layer0-1.0")) {\r
+ Layer0 = resource;\r
+ parentNames.put(resource, "L0");\r
+ }\r
+ }\r
+ else if(parent == Layer0) {\r
+ if(name.equals("InstanceOf"))\r
+ InstanceOf = resource;\r
+ else if(name.equals("Inherits"))\r
+ Inherits = resource;\r
+ else if(name.equals("SubrelationOf"))\r
+ SubrelationOf = resource;\r
+ else if(name.equals("DataType"))\r
+ DataType = resource;\r
+ }\r
+ }\r
+ \r
+ void run() {\r
+ final TIntIntHashMap refCount = new TIntIntHashMap(); \r
+ store.statements.forStatements(new IStatementProcedure() { \r
+ @Override\r
+ public void execute(int s, int p, int o) {\r
+ ArrayList<LocalStatement> localStatement;\r
+ if(activeResources.add(s)) {\r
+ localStatement = new ArrayList<LocalStatement>(2);\r
+ localStatements.put(s, localStatement);\r
+ }\r
+ else\r
+ localStatement = localStatements.get(s);\r
+ refCount.adjustOrPutValue(p, 1, 1);\r
+ refCount.adjustOrPutValue(o, 1, 1);\r
+ localStatement.add(new LocalStatement(p, o)); \r
+ }\r
+ }); \r
+ \r
+ Paths paths = new Paths("1.0");\r
+ \r
+ // Uris\r
+ uris.put(0, "http:/");\r
+ for(Identity id : store.identities.toArray())\r
+ handleIdentity(id);\r
+ /*Collections.sort(uriRes, new Comparator<Identity>() {\r
+ @Override\r
+ public int compare(Identity arg0, Identity arg1) {\r
+ int diff = arg0.parent - arg1.parent;\r
+ if(diff != 0)\r
+ return diff;\r
+ return arg0.name.compareTo(arg1.name); \r
+ } \r
+ });*/\r
+ \r
+ // Literals \r
+ Path dataTypeRes = UriUtils.uriToPath("http://www.simantics.org/Layer0-1.0/DataType");\r
+ for(Value value : store.values.toArray()) {\r
+ if(graph != null) {\r
+ Res res = store.idToRes(value.resource);\r
+ if(graph.rawGetObjects(res, paths.InstanceOf).contains(dataTypeRes)) {\r
+ Binding b = Bindings.getBindingUnchecked(Datatype.class);\r
+ try {\r
+ Datatype dt = (Datatype)value.value.getValue(b);\r
+ literals.put(value.resource, "@" + DataTypePrinter.toString(dt, false));\r
+ continue;\r
+ } catch (Exception e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } \r
+ }\r
+ else {\r
+ Datatype dt = graph.getDatatype(res);\r
+ if(dt != null) {\r
+ Binding b = Bindings.getBinding(dt);\r
+ try {\r
+ Object obj = value.value.getValue(b); \r
+ literals.put(value.resource, b.toString(obj));\r
+ continue;\r
+ } catch (Exception e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } \r
+ }\r
+ else {\r
+ literals.put(value.resource, "<" + value.value + ">");\r
+ }\r
+ \r
+ }\r
+ }\r
+ } \r
+ \r
+ // Blank resources\r
+ for(int id : activeResources.toArray())\r
+ if(refCount.get(id) == 1) {\r
+ activeResources.remove(id);\r
+ blankResources.add(id);\r
+ } \r
+ \r
+ int tempId = 0;\r
+ TIntArrayList otherResources = new TIntArrayList(); \r
+ for(int id : activeResources.toArray()) {\r
+ refNames.put(id, "r" + (++tempId));\r
+ otherResources.add(id);\r
+ }\r
+ \r
+ for(Identity uriRe : uriRes)\r
+ describeResource(0, uriRe.resource);\r
+ for(int id : otherResources.toArray())\r
+ describeResource(0, id);\r
+ }\r
+ \r
+ private void indent(int indentation) {\r
+ for(int i=0;i<indentation;++i)\r
+ b.append(" ");\r
+ }\r
+ \r
+ private void describeResource(int indentation, int resource) {\r
+ if(parentNameUsed.contains(resource)) {\r
+ b.append(parentNames.get(resource));\r
+ b.append(" = ");\r
+ } \r
+ if(literals.containsKey(resource)) { \r
+ if(refNames.get(resource) != null) {\r
+ refResource(resource); \r
+ b.append(" = ");\r
+ }\r
+ b.append(literals.get(resource));\r
+ }\r
+ else\r
+ refResource(resource);\r
+ ArrayList<LocalStatement> others = new ArrayList<LocalStatement>();\r
+ for(LocalStatement stat : localStatements.get(resource)) {\r
+ if(!blankResources.contains(stat.object) &&\r
+ (stat.predicate == InstanceOf ||\r
+ stat.predicate == Inherits ||\r
+ stat.predicate == SubrelationOf)) {\r
+ b.append(' ');\r
+ refPredicate(stat.predicate);\r
+ b.append(' ');\r
+ refResource(stat.object);\r
+ }\r
+ else\r
+ others.add(stat);\r
+ }\r
+ b.append('\n');\r
+ \r
+ for(LocalStatement stat : others) {\r
+ indent(indentation+1);\r
+ refPredicate(stat.predicate);\r
+ b.append(" ");\r
+ describeObject(indentation+1, stat.object);\r
+ }\r
+ }\r
+ \r
+ private void describeObject(int indentation, int resource) {\r
+ if(blankResources.contains(resource))\r
+ describeResource(indentation, resource);\r
+ else {\r
+ refResource(resource);\r
+ b.append('\n');\r
+ }\r
+ }\r
+ \r
+ private void refPredicate(int resource) {\r
+ if(resource == InstanceOf)\r
+ b.append(":");\r
+ else if(resource == Inherits)\r
+ b.append("<T");\r
+ else if(resource == SubrelationOf)\r
+ b.append("<R");\r
+ else\r
+ refResource(resource);\r
+ }\r
+ \r
+ private void refResource(int resource) {\r
+ String name = refNames.get(resource);\r
+ if(name == null)\r
+ b.append("_");\r
+ else\r
+ b.append(name);\r
+ }\r
+ \r
+ @Override\r
+ public String toString() {\r
+ return b.toString();\r
+ }\r
+ \r
+ static boolean isIdentifier(String name) {\r
+ if(name.isEmpty())\r
+ return false;\r
+ if(!Character.isJavaIdentifierStart(name.charAt(0)))\r
+ return false;\r
+ for(int i=1;i<name.length();++i)\r
+ if(!Character.isJavaIdentifierPart(name.charAt(i)))\r
+ return false;\r
+ return true;\r
+ }\r
+ \r
+ public static String unparse(Paths paths, TransferableGraph1 tg, Collection<TransferableGraph1> dependencies) {\r
+ CompositeGraph cg = TransferableGraphConversion.convert(paths, dependencies); \r
+ GraphStore store = TransferableGraphConversion.convert(tg);\r
+ cg.addFragment(store); \r
+ \r
+ GraphUnparser gu = new GraphUnparser(cg, store);\r
+ gu.run();\r
+ \r
+ return gu.toString();\r
+ }\r
+}\r