--- /dev/null
+package org.simantics.graph.db;\r
+\r
+import java.io.DataOutput;\r
+import java.io.DataOutputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.util.HashSet;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.accessor.error.AccessorException;\r
+import org.simantics.databoard.adapter.AdaptException;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteOnlyGraph;\r
+import org.simantics.db.common.WriteBindings;\r
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;\r
+import org.simantics.db.common.uri.UnescapedChildMapOfResource;\r
+import org.simantics.db.common.utils.Logger;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.ResourceNotFoundException;\r
+import org.simantics.db.service.ClusterBuilder;\r
+import org.simantics.db.service.ClusterBuilder.ResourceHandle;\r
+import org.simantics.db.service.SerialisationSupport;\r
+import org.simantics.graph.representation.Extensions;\r
+import org.simantics.graph.representation.External;\r
+import org.simantics.graph.representation.Identity;\r
+import org.simantics.graph.representation.IdentityDefinition;\r
+import org.simantics.graph.representation.Internal;\r
+import org.simantics.graph.representation.Optional;\r
+import org.simantics.graph.representation.Root;\r
+import org.simantics.graph.representation.TransferableGraph1;\r
+import org.simantics.graph.representation.TransferableGraphUtils;\r
+import org.simantics.graph.representation.Value;\r
+import org.simantics.graph.utils.TGResourceUtil;\r
+import org.simantics.graph.utils.TGResourceUtil.LongAdapter;\r
+\r
+public class TransferableGraphImportProcess implements TransferableGraphImporter {\r
+ \r
+ public static String LOG_FILE = "transferableGraphs.log";\r
+ final static private boolean LOG = false;\r
+ \r
+ static DataOutput log;\r
+\r
+ static {\r
+\r
+ if (LOG) {\r
+ try {\r
+ FileOutputStream stream = new FileOutputStream(LOG_FILE);\r
+ log = new DataOutputStream(stream);\r
+ } catch (FileNotFoundException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+\r
+ }\r
+ \r
+ private static void log(String line) {\r
+ if (LOG) {\r
+ try {\r
+ log.writeUTF(line + "\n");\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ }\r
+ \r
+ TransferableGraph1 tg;\r
+ IImportAdvisor advisor;\r
+ TGStatusMonitor monitor;\r
+ final TGResourceUtil resourceUtil = new TGResourceUtil();\r
+ \r
+ Resource[] resources;\r
+ ResourceHandle[] handles;\r
+ \r
+ Set<String> missingExternals = new HashSet<String>(); \r
+ \r
+ // Builtins\r
+ Resource RootLibrary;\r
+ Resource String;\r
+ Resource Library;\r
+ \r
+ Resource InstanceOf;\r
+ Resource ConsistsOf;\r
+ Resource PartOf;\r
+ Resource HasName;\r
+ Resource NameOf; \r
+ \r
+ public TransferableGraphImportProcess(TransferableGraph1 tg, IImportAdvisor advisor, TGStatusMonitor monitor) {\r
+ this.tg = tg;\r
+ this.advisor = advisor;\r
+ this.monitor = monitor;\r
+ }\r
+ \r
+ public TransferableGraphImportProcess(TransferableGraph1 tg, IImportAdvisor advisor) {\r
+ this(tg, advisor, null);\r
+ }\r
+\r
+ public void findBuiltins(WriteOnlyGraph g) throws DatabaseException {\r
+ RootLibrary = g.getBuiltin("http:/");\r
+ String = g.getBuiltin(CoreInitialization.LAYER0 + "String");\r
+ Library = g.getBuiltin(CoreInitialization.LAYER0 + "Library");\r
+ InstanceOf = g.getBuiltin(CoreInitialization.LAYER0 + "InstanceOf");\r
+ ConsistsOf = g.getBuiltin(CoreInitialization.LAYER0 + "ConsistsOf");\r
+ PartOf = g.getBuiltin(CoreInitialization.LAYER0 + "PartOf");\r
+ HasName = g.getBuiltin(CoreInitialization.LAYER0 + "HasName");\r
+ NameOf = g.getBuiltin(CoreInitialization.LAYER0 + "NameOf");\r
+ }\r
+ \r
+ public void findBuiltins(ReadGraph g) throws DatabaseException {\r
+ RootLibrary = g.getBuiltin("http:/");\r
+ String = g.getBuiltin(CoreInitialization.LAYER0 + "String");\r
+ Library = g.getBuiltin(CoreInitialization.LAYER0 + "Library");\r
+ InstanceOf = g.getBuiltin(CoreInitialization.LAYER0 + "InstanceOf");\r
+ ConsistsOf = g.getBuiltin(CoreInitialization.LAYER0 + "ConsistsOf");\r
+ PartOf = g.getBuiltin(CoreInitialization.LAYER0 + "PartOf");\r
+ HasName = g.getBuiltin(CoreInitialization.LAYER0 + "HasName");\r
+ NameOf = g.getBuiltin(CoreInitialization.LAYER0 + "NameOf");\r
+ }\r
+\r
+ /* Preparation that is used when the core is empty. \r
+ */\r
+ void initialPrepare(WriteOnlyGraph graph) throws DatabaseException {\r
+ findBuiltins(graph);\r
+ \r
+ resources = new Resource[tg.resourceCount];\r
+ \r
+ int Root = -1;\r
+ int SimanticsDomain = -1;\r
+ int Layer0 = -1;\r
+ \r
+ for(Identity identity : tg.identities) {\r
+ if(identity.definition instanceof Internal) {\r
+ Internal def = (Internal)identity.definition;\r
+ Resource res = null;\r
+ if(def.parent == Layer0) {\r
+ try {\r
+ res = graph.getBuiltin(CoreInitialization.LAYER0 + def.name);\r
+ } catch(ResourceNotFoundException e) { \r
+ }\r
+ }\r
+ else if(def.parent == SimanticsDomain) {\r
+ if(def.name.equals("Layer0-1.1"))\r
+ Layer0 = identity.resource;\r
+ }\r
+ else if(def.parent == Root) {\r
+ if(def.name.equals("www.simantics.org"))\r
+ SimanticsDomain = identity.resource;\r
+ }\r
+\r
+ if(res == null)\r
+ res = createChild(graph, resources[def.parent], def.name);\r
+ else\r
+ createChild(graph, res, resources[def.parent], def.name);\r
+ resources[identity.resource] = res;\r
+ }\r
+ else if(identity.definition instanceof Root) {\r
+ Root = identity.resource;\r
+ resources[identity.resource] = RootLibrary; \r
+ } \r
+ }\r
+ }\r
+ \r
+ void addMissing(String external) {\r
+ Set<String> removals = new HashSet<String>();\r
+ for(String ext : missingExternals) if(ext.startsWith(external)) return;\r
+ for(String ext : missingExternals) if(external.startsWith(ext)) removals.add(ext);\r
+ missingExternals.removeAll(removals);\r
+ missingExternals.add(external);\r
+ }\r
+ \r
+ void prepare(ReadGraph graph) throws DatabaseException {\r
+ findBuiltins(graph);\r
+ \r
+ Resource[] resources = new Resource[tg.resourceCount];\r
+ \r
+ for(Identity identity : tg.identities) {\r
+ IdentityDefinition definition = identity.definition;\r
+ if(definition instanceof External) {\r
+ External def = (External)definition;\r
+ if(def.parent == -1) {\r
+ resources[identity.resource] = RootLibrary;\r
+ } else {\r
+ if("@inverse".equals(def.name)) {\r
+ Resource parent = resources[def.parent];\r
+ Resource child = graph.getInverse(parent);\r
+ resources[identity.resource] = child;\r
+ } else {\r
+ Resource parent = resources[def.parent];\r
+ // TODO: escape should be removed when names become well-behaving\r
+ if(parent != null) {\r
+ Resource child = graph\r
+ .syncRequest(new UnescapedChildMapOfResource(parent),\r
+ new TransientCacheAsyncListener<Map<String, Resource>>())\r
+ .get(def.name);\r
+ if(child == null) {\r
+ String uri = graph.getPossibleURI(parent);\r
+ if(uri == null) {\r
+ addMissing(NameUtils.getSafeName(graph, parent) + " /" + def.name);\r
+ } else {\r
+ addMissing(graph.getURI(parent) + "/" + def.name);\r
+ }\r
+ }\r
+ resources[identity.resource] = child;\r
+ } else {\r
+ addMissing(TransferableGraphUtils.getURI(tg, def.parent) + "/" + def.name);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else if(definition instanceof Internal) {\r
+ // Do not do anything for now\r
+ }\r
+ else if(definition instanceof Root) {\r
+ Root root = (Root)definition;\r
+ if(root.name.equals(""))\r
+ resources[identity.resource] = RootLibrary;\r
+ else {\r
+ Resource existing = advisor.analyzeRoot(graph, root);\r
+ if(existing != null)\r
+ resources[identity.resource] = existing;\r
+ }\r
+ }\r
+ else if(definition instanceof Optional) {\r
+ External def = (External)definition;\r
+ Resource parent = resources[def.parent];\r
+ if(parent != null)\r
+ resources[identity.resource] = \r
+ graph.syncRequest(new UnescapedChildMapOfResource(parent)).get(def.name); \r
+ }\r
+ } \r
+ \r
+ this.resources = resources;\r
+ \r
+ if(!missingExternals.isEmpty()) throw new MissingDependencyException(this);\r
+ \r
+ }\r
+\r
+ Resource createChild(WriteOnlyGraph graph, Resource parent, String name) throws DatabaseException {\r
+ Resource child = graph.newResource();\r
+ //graph.claim(parent, ConsistsOf, PartOf, child);\r
+ Resource nameResource = graph.newResource();\r
+ graph.claim(nameResource, InstanceOf, null, String);\r
+ graph.claimValue(nameResource, name, WriteBindings.STRING);\r
+ graph.claim(child, HasName, NameOf, nameResource);\r
+ return child;\r
+ }\r
+\r
+ @Override\r
+ public Resource createChild(WriteOnlyGraph graph, Resource child, Resource parent, String name) throws DatabaseException {\r
+ graph.claim(parent, ConsistsOf, PartOf, child);\r
+ Resource nameResource = graph.newResource();\r
+ graph.claim(nameResource, InstanceOf, null, String);\r
+ graph.claimValue(nameResource, name, WriteBindings.STRING);\r
+ graph.claim(child, HasName, NameOf, nameResource);\r
+ return child;\r
+ }\r
+ \r
+ int[] getClustering() {\r
+ Variant v = tg.extensions.get(Extensions.CLUSTERING);\r
+ if(v == null) return null;\r
+ try {\r
+ return (int[])v.getValue(Bindings.INT_ARRAY);\r
+ } catch (AdaptException e) {\r
+ Logger.defaultLogError(e);\r
+ return null;\r
+ }\r
+ }\r
+\r
+ class ResourceAdapter implements LongAdapter {\r
+ final SerialisationSupport ss;\r
+ final Value value;\r
+ Variant original;\r
+ ResourceAdapter(SerialisationSupport ss, Value value) {\r
+ this.ss = ss;\r
+ this.value = value;\r
+ }\r
+ @Override\r
+ public long adapt(long in) {\r
+ if(original == null) original = value.value.clone();\r
+ Resource res = handles[(int)in].resource(ss);\r
+ // Maybe throw?\r
+ if(res == null) return in;\r
+ return res.getResourceId();\r
+ } \r
+ }\r
+ \r
+ Variant translate(SerialisationSupport ss, Value value, final ResourceHandle[] handles) throws DatabaseException {\r
+ \r
+ try {\r
+ ResourceAdapter adapter = new ResourceAdapter(ss, value);\r
+ resourceUtil.adaptValue( value.value.getBinding(), value.value.getValue(), adapter);\r
+ Variant result = value.value;\r
+ if(adapter.original != null) value.value = adapter.original;\r
+ return result;\r
+ } catch (AccessorException e) {\r
+ e.printStackTrace();\r
+ } \r
+ \r
+ return value.value;\r
+ \r
+ }\r
+ \r
+ class ResourceAdapter2 implements LongAdapter {\r
+ final Value value;\r
+ Variant original;\r
+ ResourceAdapter2(Value value) {\r
+ this.value = value;\r
+ }\r
+ @Override\r
+ public long adapt(long in) {\r
+ if(original == null) original = value.value.clone();\r
+ Resource res = resources[(int)in];\r
+ // Maybe throw?\r
+ if(res == null) return in;\r
+ return res.getResourceId();\r
+ } \r
+ }\r
+\r
+ Variant translate2(Value value, final Resource[] resources) throws DatabaseException {\r
+ \r
+ try {\r
+ ResourceAdapter2 adapter = new ResourceAdapter2(value);\r
+ resourceUtil.adaptValue( value.value.getBinding(), value.value.getValue(), adapter);\r
+ Variant result = value.value;\r
+ if(adapter.original != null) value.value = adapter.original;\r
+ return result;\r
+ } catch (AccessorException e) {\r
+ e.printStackTrace();\r
+ } \r
+ \r
+ return value.value;\r
+ \r
+ }\r
+\r
+ void write(WriteOnlyGraph graph) throws DatabaseException {\r
+\r
+ Resource[] resources = this.resources;\r
+\r
+ this.handles = new ResourceHandle[resources.length];\r
+ \r
+ ResourceHandle[] handles = this.handles; \r
+\r
+ int[] clustering = getClustering();\r
+\r
+ // Internal identities \r
+ for(Identity identity : tg.identities) {\r
+ IdentityDefinition definition = identity.definition;\r
+ if(resources[identity.resource] != null)\r
+ continue;\r
+ if(definition instanceof External) {\r
+ // Already done everything\r
+ }\r
+ else if(definition instanceof Internal) {\r
+ Internal def = (Internal)definition;\r
+ resources[identity.resource] = \r
+ createChild(graph, resources[def.parent], def.name);\r
+ }\r
+ else if(definition instanceof Root) {\r
+ Root root = (Root)definition; \r
+ resources[identity.resource] = advisor.createRoot(graph, root); \r
+ }\r
+ else if(definition instanceof Optional) {\r
+ Optional def = (Optional)definition;\r
+ Resource child = createChild(graph, resources[def.parent], def.name);\r
+ graph.claim(child, InstanceOf, null, Library); // ???\r
+ resources[identity.resource] = child; \r
+ }\r
+ } \r
+\r
+ ClusterBuilder builder = graph.getService(ClusterBuilder.class);\r
+ SerialisationSupport ss = graph.getService(SerialisationSupport.class);\r
+\r
+ if(clustering != null) {\r
+ \r
+ int i = 0;\r
+ for(int c : clustering) {\r
+ builder.newCluster();\r
+ for(int r=0;r<c;r++, i++)\r
+ if(resources[i] == null)\r
+ handles[i] = builder.newResource();\r
+ else \r
+ handles[i] = builder.resource(resources[i]);\r
+\r
+ }\r
+\r
+ for(;i<resources.length;++i)\r
+ if(resources[i] == null)\r
+ handles[i] = builder.newResource();\r
+ else \r
+ handles[i] = builder.resource(resources[i]);\r
+ \r
+ } else {\r
+ \r
+ // Create blank resources\r
+ for(int i=0;i<resources.length;++i)\r
+ if(resources[i] == null)\r
+ handles[i] = builder.newResource();\r
+ else \r
+ handles[i] = builder.resource(resources[i]);\r
+\r
+ }\r
+ \r
+ // Write statements\r
+ int[] statements = tg.statements;\r
+ \r
+// int internals = tg.resourceCount - tg.identities.length;\r
+ \r
+ for(int i=0;i<statements.length;i+=4) {\r
+\r
+ int sub = statements[i];\r
+ int pred = statements[i+1];\r
+ int inv = statements[i+2];\r
+ int obj = statements[i+3];\r
+\r
+ ResourceHandle subject = handles[sub];\r
+ ResourceHandle predicate = handles[pred];\r
+ ResourceHandle object = handles[obj];\r
+\r
+ if(resources[sub] == null) {\r
+ subject.addStatement(graph, predicate, object); \r
+ } else {\r
+ graph.claim(\r
+ handles[sub].resource(ss),\r
+ handles[pred].resource(ss),\r
+ null, handles[obj].resource(ss));\r
+ }\r
+ \r
+ if(inv >= 0) {\r
+ \r
+ if(resources[obj] == null) {\r
+ ResourceHandle inverse = handles[inv];\r
+ object.addStatement(graph, inverse, subject); \r
+ } else {\r
+ Resource s = handles[obj].resource(ss);\r
+ if(!graph.isImmutable(s))\r
+ graph.claim(\r
+ s,\r
+ handles[inv].resource(ss),\r
+ null, handles[sub].resource(ss));\r
+ }\r
+ \r
+ }\r
+ \r
+ if(LOG) {\r
+ log("[STATEMENT] " + resources[statements[i]].getResourceId() + ", " + resources[statements[i+1]].getResourceId() + ", " + resources[statements[i+3]].getResourceId());\r
+ }\r
+ \r
+ }\r
+ \r
+ // Write values\r
+ for(Value value : tg.values) {\r
+ Variant variant = translate(ss, value, handles);\r
+ int file = value.resource & 0x80000000;\r
+ int resource = value.resource & 0x7FFFFFFF;\r
+ if (file != 0) {\r
+ throw new UnsupportedOperationException();\r
+ //graph.claimValue(handles[resource].resource(), value.value, Bindings.BYTE_ARRAY);\r
+ } else {\r
+ graph.claimValue(handles[resource].resource(ss), variant.getValue(), variant.getBinding());\r
+ }\r
+ }\r
+ }\r
+\r
+ private int updatePercentage(int percentage, int done, int total) {\r
+ if(monitor != null && (done & 63) == 0) {\r
+ int current = 100*done / total;\r
+ if(current > percentage) {\r
+ percentage = current;\r
+ monitor.status(percentage);\r
+ }\r
+ }\r
+ return percentage;\r
+ }\r
+ \r
+ void write2(WriteOnlyGraph graph) throws DatabaseException {\r
+ Resource[] resources = this.resources;\r
+ \r
+ // Internal identities \r
+ for(Identity identity : tg.identities) {\r
+ IdentityDefinition definition = identity.definition;\r
+ if(resources[identity.resource] != null)\r
+ continue;\r
+ if(definition instanceof External) {\r
+ // Already done everything\r
+ }\r
+ else if(definition instanceof Internal) {\r
+ Internal def = (Internal)definition;\r
+ resources[identity.resource] = \r
+ createChild(graph, resources[def.parent], def.name);\r
+ }\r
+ else if(definition instanceof Root) { \r
+ Root root = (Root)definition; \r
+ resources[identity.resource] = advisor.createRoot(graph, root); \r
+ }\r
+ else if(definition instanceof Optional) {\r
+ Optional def = (Optional)definition;\r
+ Resource child = createChild(graph, resources[def.parent], def.name);\r
+ graph.claim(child, InstanceOf, null, Library); // ???\r
+ resources[identity.resource] = child; \r
+ }\r
+ } \r
+ \r
+ // Create blank resources\r
+ for(int i=0;i<resources.length;++i)\r
+ if(resources[i] == null)\r
+ resources[i] = graph.newResource();\r
+ \r
+ int total = tg.statements.length + tg.values.length;\r
+ int done = 0;\r
+ int percentage = 0;\r
+ \r
+ // Write statements\r
+ int[] statements = tg.statements;\r
+ \r
+ for(int i=0;i<statements.length;i+=4) {\r
+ int inv = statements[i+2];\r
+ graph.claim(\r
+ resources[statements[i]],\r
+ resources[statements[i+1]],\r
+ inv < 0 ? null : resources[inv],\r
+ resources[statements[i+3]]\r
+ );\r
+ if(LOG) {\r
+ log("[STATEMENT] " + resources[statements[i]].getResourceId() + ", " + resources[statements[i+1]].getResourceId() + ", " + resources[statements[i+3]].getResourceId());\r
+ }\r
+ percentage = updatePercentage(percentage, done++, total);\r
+ }\r
+\r
+ // Write values\r
+ for(Value value : tg.values) {\r
+ Variant variant = translate2(value, resources);\r
+ int file = value.resource & 0x80000000;\r
+ int resource = value.resource & 0x7FFFFFFF;\r
+ if (file != 0) {\r
+ throw new UnsupportedOperationException();\r
+ //graph.claimValue(resources[resource], value.value, Bindings.BYTE_ARRAY);\r
+ } else {\r
+ graph.claimValue(resources[resource], variant.getValue(), variant.getBinding());\r
+ }\r
+ percentage = updatePercentage(percentage, done++, total);\r
+ }\r
+ \r
+ }\r
+ \r
+ public long[] getResourceIds(SerialisationSupport serializer) throws DatabaseException {\r
+ final int count = resources.length;\r
+ long[] resourceIds = new long[count];\r
+ if(handles != null) {\r
+ for(int i=0;i<count;++i)\r
+ resourceIds[i] = serializer.getRandomAccessId(handles[i].resource(serializer));\r
+ } else {\r
+ for(int i=0;i<count;++i)\r
+ resourceIds[i] = serializer.getRandomAccessId(resources[i]);\r
+ }\r
+ return resourceIds;\r
+ }\r
+}
\ No newline at end of file