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