]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.graph.db/src/org/simantics/graph/db/TransferableGraphImportProcess.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.graph.db / src / org / simantics / graph / db / TransferableGraphImportProcess.java
1 package org.simantics.graph.db;\r
2 \r
3 import java.io.DataOutput;\r
4 import java.io.DataOutputStream;\r
5 import java.io.FileNotFoundException;\r
6 import java.io.FileOutputStream;\r
7 import java.io.IOException;\r
8 import java.util.HashSet;\r
9 import java.util.Map;\r
10 import java.util.Set;\r
11 \r
12 import org.simantics.databoard.Bindings;\r
13 import org.simantics.databoard.accessor.error.AccessorException;\r
14 import org.simantics.databoard.adapter.AdaptException;\r
15 import org.simantics.databoard.binding.mutable.Variant;\r
16 import org.simantics.db.ReadGraph;\r
17 import org.simantics.db.Resource;\r
18 import org.simantics.db.WriteOnlyGraph;\r
19 import org.simantics.db.common.WriteBindings;\r
20 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;\r
21 import org.simantics.db.common.uri.UnescapedChildMapOfResource;\r
22 import org.simantics.db.common.utils.Logger;\r
23 import org.simantics.db.common.utils.NameUtils;\r
24 import org.simantics.db.exception.DatabaseException;\r
25 import org.simantics.db.exception.ResourceNotFoundException;\r
26 import org.simantics.db.service.ClusterBuilder;\r
27 import org.simantics.db.service.ClusterBuilder.ResourceHandle;\r
28 import org.simantics.db.service.SerialisationSupport;\r
29 import org.simantics.graph.representation.Extensions;\r
30 import org.simantics.graph.representation.External;\r
31 import org.simantics.graph.representation.Identity;\r
32 import org.simantics.graph.representation.IdentityDefinition;\r
33 import org.simantics.graph.representation.Internal;\r
34 import org.simantics.graph.representation.Optional;\r
35 import org.simantics.graph.representation.Root;\r
36 import org.simantics.graph.representation.TransferableGraph1;\r
37 import org.simantics.graph.representation.TransferableGraphUtils;\r
38 import org.simantics.graph.representation.Value;\r
39 import org.simantics.graph.utils.TGResourceUtil;\r
40 import org.simantics.graph.utils.TGResourceUtil.LongAdapter;\r
41 \r
42 public class TransferableGraphImportProcess implements TransferableGraphImporter {\r
43         \r
44         public static String LOG_FILE = "transferableGraphs.log";\r
45         final static private boolean LOG = false;\r
46         \r
47         static DataOutput log;\r
48 \r
49         static {\r
50 \r
51                 if (LOG) {\r
52                         try {\r
53                                 FileOutputStream stream = new FileOutputStream(LOG_FILE);\r
54                                 log = new DataOutputStream(stream);\r
55                         } catch (FileNotFoundException e) {\r
56                                 e.printStackTrace();\r
57                         }\r
58                 }\r
59 \r
60         }\r
61         \r
62         private static void log(String line) {\r
63                 if (LOG) {\r
64                         try {\r
65                                 log.writeUTF(line + "\n");\r
66                         } catch (IOException e) {\r
67                                 e.printStackTrace();\r
68                         }\r
69                 }\r
70         }\r
71         \r
72         TransferableGraph1 tg;\r
73         IImportAdvisor advisor;\r
74         TGStatusMonitor monitor;\r
75         final TGResourceUtil resourceUtil = new TGResourceUtil();\r
76         \r
77         Resource[] resources;\r
78         ResourceHandle[] handles;\r
79         \r
80         Set<String> missingExternals = new HashSet<String>(); \r
81         \r
82         // Builtins\r
83         Resource RootLibrary;\r
84         Resource String;\r
85         Resource Library;\r
86         \r
87         Resource InstanceOf;\r
88         Resource ConsistsOf;\r
89         Resource PartOf;\r
90         Resource HasName;\r
91         Resource NameOf;        \r
92                                 \r
93         public TransferableGraphImportProcess(TransferableGraph1 tg, IImportAdvisor advisor, TGStatusMonitor monitor) {\r
94                 this.tg = tg;\r
95                 this.advisor = advisor;\r
96                 this.monitor = monitor;\r
97         }\r
98         \r
99     public TransferableGraphImportProcess(TransferableGraph1 tg, IImportAdvisor advisor) {\r
100         this(tg, advisor, null);\r
101     }\r
102 \r
103         public void findBuiltins(WriteOnlyGraph g) throws DatabaseException {\r
104                 RootLibrary = g.getBuiltin("http:/");\r
105                 String = g.getBuiltin(CoreInitialization.LAYER0 + "String");\r
106                 Library = g.getBuiltin(CoreInitialization.LAYER0 + "Library");\r
107                 InstanceOf = g.getBuiltin(CoreInitialization.LAYER0 + "InstanceOf");\r
108                 ConsistsOf = g.getBuiltin(CoreInitialization.LAYER0 + "ConsistsOf");\r
109                 PartOf = g.getBuiltin(CoreInitialization.LAYER0 + "PartOf");\r
110                 HasName = g.getBuiltin(CoreInitialization.LAYER0 + "HasName");\r
111                 NameOf = g.getBuiltin(CoreInitialization.LAYER0 + "NameOf");\r
112         }\r
113         \r
114         public void findBuiltins(ReadGraph g) throws DatabaseException {\r
115                 RootLibrary = g.getBuiltin("http:/");\r
116                 String = g.getBuiltin(CoreInitialization.LAYER0 + "String");\r
117                 Library = g.getBuiltin(CoreInitialization.LAYER0 + "Library");\r
118                 InstanceOf = g.getBuiltin(CoreInitialization.LAYER0 + "InstanceOf");\r
119                 ConsistsOf = g.getBuiltin(CoreInitialization.LAYER0 + "ConsistsOf");\r
120                 PartOf = g.getBuiltin(CoreInitialization.LAYER0 + "PartOf");\r
121                 HasName = g.getBuiltin(CoreInitialization.LAYER0 + "HasName");\r
122                 NameOf = g.getBuiltin(CoreInitialization.LAYER0 + "NameOf");\r
123         }\r
124 \r
125         /* Preparation that is used when the core is empty. \r
126          */\r
127         void initialPrepare(WriteOnlyGraph graph) throws DatabaseException {\r
128                 findBuiltins(graph);\r
129                 \r
130                 resources = new Resource[tg.resourceCount];\r
131                 \r
132                 int Root = -1;\r
133                 int SimanticsDomain = -1;\r
134                 int Layer0 = -1;\r
135                 \r
136                 for(Identity identity : tg.identities) {\r
137                         if(identity.definition instanceof Internal) {\r
138                                 Internal def = (Internal)identity.definition;\r
139                                 Resource res = null;\r
140                                 if(def.parent == Layer0) {\r
141                                         try {\r
142                                                 res = graph.getBuiltin(CoreInitialization.LAYER0 + def.name);\r
143                                         } catch(ResourceNotFoundException e) {                                                                          \r
144                                         }\r
145                                 }\r
146                                 else if(def.parent == SimanticsDomain) {\r
147                                         if(def.name.equals("Layer0-1.1"))\r
148                                                 Layer0 = identity.resource;\r
149                                 }\r
150                                 else if(def.parent == Root) {\r
151                                         if(def.name.equals("www.simantics.org"))\r
152                                                 SimanticsDomain = identity.resource;\r
153                                 }\r
154 \r
155                                 if(res == null)\r
156                                         res = createChild(graph, resources[def.parent], def.name);\r
157                                 else\r
158                                         createChild(graph, res, resources[def.parent], def.name);\r
159                                 resources[identity.resource] = res;\r
160                         }\r
161                         else if(identity.definition instanceof Root) {\r
162                                 Root = identity.resource;\r
163                                 resources[identity.resource] = RootLibrary;                             \r
164                         } \r
165                 }\r
166         }\r
167         \r
168         void addMissing(String external) {\r
169                 Set<String> removals = new HashSet<String>();\r
170                 for(String ext : missingExternals) if(ext.startsWith(external)) return;\r
171                 for(String ext : missingExternals) if(external.startsWith(ext)) removals.add(ext);\r
172                 missingExternals.removeAll(removals);\r
173                 missingExternals.add(external);\r
174         }\r
175         \r
176         void prepare(ReadGraph graph) throws DatabaseException {\r
177                 findBuiltins(graph);\r
178                 \r
179                 Resource[] resources = new Resource[tg.resourceCount];\r
180                 \r
181                 for(Identity identity : tg.identities) {\r
182                         IdentityDefinition definition = identity.definition;\r
183                         if(definition instanceof External) {\r
184                                 External def = (External)definition;\r
185                                 if(def.parent == -1) {\r
186                                         resources[identity.resource] = RootLibrary;\r
187                                 } else {\r
188                                         if("@inverse".equals(def.name)) {\r
189                                                 Resource parent = resources[def.parent];\r
190                                                 Resource child = graph.getInverse(parent);\r
191                                                 resources[identity.resource] = child;\r
192                                         } else {\r
193                                                 Resource parent = resources[def.parent];\r
194                                                 // TODO: escape should be removed when names become well-behaving\r
195                                                 if(parent != null) {\r
196                                                         Resource child = graph\r
197                                                         .syncRequest(new UnescapedChildMapOfResource(parent),\r
198                                                                 new TransientCacheAsyncListener<Map<String, Resource>>())\r
199                                                                 .get(def.name);\r
200                                                         if(child == null) {\r
201                                                                 String uri = graph.getPossibleURI(parent);\r
202                                                                 if(uri == null) {\r
203                                                                         addMissing(NameUtils.getSafeName(graph, parent) + " /" + def.name);\r
204                                                                 } else {\r
205                                                                         addMissing(graph.getURI(parent) + "/" + def.name);\r
206                                                                 }\r
207                                                         }\r
208                                                         resources[identity.resource] = child;\r
209                                                 } else {\r
210                                                     addMissing(TransferableGraphUtils.getURI(tg, def.parent) + "/" + def.name);\r
211                                                 }\r
212                                         }\r
213                                 }\r
214                         }\r
215                         else if(definition instanceof Internal) {\r
216                                 // Do not do anything for now\r
217                         }\r
218                         else if(definition instanceof Root) {\r
219                                 Root root = (Root)definition;\r
220                                 if(root.name.equals(""))\r
221                                         resources[identity.resource] = RootLibrary;\r
222                                 else {\r
223                                         Resource existing = advisor.analyzeRoot(graph, root);\r
224                                         if(existing != null)\r
225                                                 resources[identity.resource] = existing;\r
226                                 }\r
227                         }\r
228                         else if(definition instanceof Optional) {\r
229                                 External def = (External)definition;\r
230                                 Resource parent = resources[def.parent];\r
231                                 if(parent != null)\r
232                                         resources[identity.resource] = \r
233                                                 graph.syncRequest(new UnescapedChildMapOfResource(parent)).get(def.name);                               \r
234                         }\r
235                 }               \r
236                 \r
237                 this.resources = resources;\r
238                 \r
239                 if(!missingExternals.isEmpty()) throw new MissingDependencyException(this);\r
240                 \r
241         }\r
242 \r
243         Resource createChild(WriteOnlyGraph graph, Resource parent, String name) throws DatabaseException {\r
244                 Resource child = graph.newResource();\r
245                 //graph.claim(parent, ConsistsOf, PartOf, child);\r
246                 Resource nameResource = graph.newResource();\r
247                 graph.claim(nameResource, InstanceOf, null, String);\r
248                 graph.claimValue(nameResource, name, WriteBindings.STRING);\r
249                 graph.claim(child, HasName, NameOf, nameResource);\r
250                 return child;\r
251         }\r
252 \r
253         @Override\r
254         public Resource createChild(WriteOnlyGraph graph, Resource child, Resource parent, String name) throws DatabaseException {\r
255                 graph.claim(parent, ConsistsOf, PartOf, child);\r
256                 Resource nameResource = graph.newResource();\r
257                 graph.claim(nameResource, InstanceOf, null, String);\r
258                 graph.claimValue(nameResource, name, WriteBindings.STRING);\r
259                 graph.claim(child, HasName, NameOf, nameResource);\r
260                 return child;\r
261         }\r
262         \r
263         int[] getClustering() {\r
264                 Variant v = tg.extensions.get(Extensions.CLUSTERING);\r
265                 if(v == null) return null;\r
266                 try {\r
267                         return (int[])v.getValue(Bindings.INT_ARRAY);\r
268                 } catch (AdaptException e) {\r
269                         Logger.defaultLogError(e);\r
270                         return null;\r
271                 }\r
272         }\r
273 \r
274         class ResourceAdapter implements LongAdapter {\r
275             final SerialisationSupport ss;\r
276             final Value value;\r
277             Variant original;\r
278             ResourceAdapter(SerialisationSupport ss, Value value) {\r
279                 this.ss = ss;\r
280                 this.value = value;\r
281             }\r
282         @Override\r
283         public long adapt(long in) {\r
284             if(original == null) original = value.value.clone();\r
285             Resource res = handles[(int)in].resource(ss);\r
286             // Maybe throw?\r
287             if(res == null) return in;\r
288             return res.getResourceId();\r
289         }           \r
290         }\r
291         \r
292         Variant translate(SerialisationSupport ss, Value value, final ResourceHandle[] handles) throws DatabaseException {\r
293                 \r
294                 try {\r
295                     ResourceAdapter adapter = new ResourceAdapter(ss, value);\r
296                         resourceUtil.adaptValue( value.value.getBinding(), value.value.getValue(), adapter);\r
297                         Variant result = value.value;\r
298                         if(adapter.original != null) value.value = adapter.original;\r
299                         return result;\r
300                 } catch (AccessorException e) {\r
301                         e.printStackTrace();\r
302                 }               \r
303                 \r
304                 return value.value;\r
305                 \r
306         }\r
307         \r
308     class ResourceAdapter2 implements LongAdapter {\r
309         final Value value;\r
310         Variant original;\r
311         ResourceAdapter2(Value value) {\r
312             this.value = value;\r
313         }\r
314         @Override\r
315         public long adapt(long in) {\r
316             if(original == null) original = value.value.clone();\r
317             Resource res = resources[(int)in];\r
318             // Maybe throw?\r
319             if(res == null) return in;\r
320             return res.getResourceId();\r
321         }           \r
322     }\r
323 \r
324         Variant translate2(Value value, final Resource[] resources) throws DatabaseException {\r
325                 \r
326         try {\r
327             ResourceAdapter2 adapter = new ResourceAdapter2(value);\r
328             resourceUtil.adaptValue( value.value.getBinding(), value.value.getValue(), adapter);\r
329             Variant result = value.value;\r
330             if(adapter.original != null) value.value = adapter.original;\r
331             return result;\r
332         } catch (AccessorException e) {\r
333             e.printStackTrace();\r
334         }       \r
335         \r
336         return value.value;\r
337                 \r
338         }\r
339 \r
340         void write(WriteOnlyGraph graph) throws DatabaseException {\r
341 \r
342                 Resource[] resources = this.resources;\r
343 \r
344                 this.handles = new ResourceHandle[resources.length];\r
345                 \r
346                 ResourceHandle[] handles = this.handles; \r
347 \r
348                 int[] clustering = getClustering();\r
349 \r
350                 // Internal identities          \r
351                 for(Identity identity : tg.identities) {\r
352                         IdentityDefinition definition = identity.definition;\r
353                         if(resources[identity.resource] != null)\r
354                                 continue;\r
355                         if(definition instanceof External) {\r
356                                 // Already done everything\r
357                         }\r
358                         else if(definition instanceof Internal) {\r
359                                 Internal def = (Internal)definition;\r
360                                 resources[identity.resource] = \r
361                                         createChild(graph, resources[def.parent], def.name);\r
362                         }\r
363                         else if(definition instanceof Root) {\r
364                                 Root root = (Root)definition;                           \r
365                                 resources[identity.resource] = advisor.createRoot(graph, root);                                 \r
366                         }\r
367                         else if(definition instanceof Optional) {\r
368                                 Optional def = (Optional)definition;\r
369                                 Resource child = createChild(graph, resources[def.parent], def.name);\r
370                                 graph.claim(child, InstanceOf, null, Library); // ???\r
371                                 resources[identity.resource] = child;                                   \r
372                         }\r
373                 }               \r
374 \r
375                 ClusterBuilder builder = graph.getService(ClusterBuilder.class);\r
376                 SerialisationSupport ss = graph.getService(SerialisationSupport.class);\r
377 \r
378                 if(clustering != null) {\r
379                         \r
380                 int i = 0;\r
381                         for(int c : clustering) {\r
382                                 builder.newCluster();\r
383                                 for(int r=0;r<c;r++, i++)\r
384                                         if(resources[i] == null)\r
385                                                 handles[i] = builder.newResource();\r
386                                         else \r
387                                                 handles[i] = builder.resource(resources[i]);\r
388 \r
389                         }\r
390 \r
391                         for(;i<resources.length;++i)\r
392                                 if(resources[i] == null)\r
393                                         handles[i] = builder.newResource();\r
394                                 else \r
395                                         handles[i] = builder.resource(resources[i]);\r
396                         \r
397                 } else {\r
398                 \r
399                         // Create blank resources\r
400                         for(int i=0;i<resources.length;++i)\r
401                                 if(resources[i] == null)\r
402                                         handles[i] = builder.newResource();\r
403                                 else \r
404                                         handles[i] = builder.resource(resources[i]);\r
405 \r
406                 }\r
407                 \r
408                 // Write statements\r
409                 int[] statements = tg.statements;\r
410                 \r
411 //              int internals = tg.resourceCount - tg.identities.length;\r
412                 \r
413                 for(int i=0;i<statements.length;i+=4) {\r
414 \r
415                         int sub = statements[i];\r
416                         int pred = statements[i+1];\r
417                         int inv = statements[i+2];\r
418                         int obj = statements[i+3];\r
419 \r
420                         ResourceHandle subject = handles[sub];\r
421                         ResourceHandle predicate = handles[pred];\r
422                         ResourceHandle object = handles[obj];\r
423 \r
424                         if(resources[sub] == null) {\r
425                                 subject.addStatement(graph, predicate, object); \r
426                         } else {\r
427                                 graph.claim(\r
428                                                 handles[sub].resource(ss),\r
429                                                 handles[pred].resource(ss),\r
430                                                 null, handles[obj].resource(ss));\r
431                         }\r
432                         \r
433                         if(inv >= 0) {\r
434                                 \r
435                                 if(resources[obj] == null) {\r
436                                         ResourceHandle inverse = handles[inv];\r
437                                         object.addStatement(graph, inverse, subject);   \r
438                                 } else {\r
439                                     Resource s = handles[obj].resource(ss);\r
440                                     if(!graph.isImmutable(s))\r
441                                         graph.claim(\r
442                                                         s,\r
443                                                         handles[inv].resource(ss),\r
444                                                         null, handles[sub].resource(ss));\r
445                                 }\r
446                                 \r
447                         }\r
448                         \r
449                         if(LOG) {\r
450                                 log("[STATEMENT] " + resources[statements[i]].getResourceId() + ", " + resources[statements[i+1]].getResourceId() + ", " + resources[statements[i+3]].getResourceId());\r
451                         }\r
452                         \r
453                 }\r
454                                 \r
455                 // Write values\r
456                 for(Value value : tg.values) {\r
457                         Variant variant = translate(ss, value, handles);\r
458                         int file = value.resource & 0x80000000;\r
459                         int resource = value.resource & 0x7FFFFFFF;\r
460                         if (file != 0) {\r
461                             throw new UnsupportedOperationException();\r
462                                 //graph.claimValue(handles[resource].resource(), value.value, Bindings.BYTE_ARRAY);\r
463                         } else {\r
464                                 graph.claimValue(handles[resource].resource(ss), variant.getValue(), variant.getBinding());\r
465                         }\r
466                 }\r
467         }\r
468 \r
469         private int updatePercentage(int percentage, int done, int total) {\r
470             if(monitor != null && (done & 63) == 0) {\r
471                 int current = 100*done / total;\r
472                 if(current > percentage) {\r
473                     percentage = current;\r
474                     monitor.status(percentage);\r
475                 }\r
476             }\r
477         return percentage;\r
478         }\r
479         \r
480         void write2(WriteOnlyGraph graph) throws DatabaseException {\r
481                 Resource[] resources = this.resources;\r
482                 \r
483                 // Internal identities          \r
484                 for(Identity identity : tg.identities) {\r
485                         IdentityDefinition definition = identity.definition;\r
486                         if(resources[identity.resource] != null)\r
487                                 continue;\r
488                         if(definition instanceof External) {\r
489                                 // Already done everything\r
490                         }\r
491                         else if(definition instanceof Internal) {\r
492                                 Internal def = (Internal)definition;\r
493                                 resources[identity.resource] = \r
494                                         createChild(graph, resources[def.parent], def.name);\r
495                         }\r
496                         else if(definition instanceof Root) {                           \r
497                                 Root root = (Root)definition;                           \r
498                                 resources[identity.resource] = advisor.createRoot(graph, root);                                 \r
499                         }\r
500                         else if(definition instanceof Optional) {\r
501                                 Optional def = (Optional)definition;\r
502                                 Resource child = createChild(graph, resources[def.parent], def.name);\r
503                                 graph.claim(child, InstanceOf, null, Library); // ???\r
504                                 resources[identity.resource] = child;                                   \r
505                         }\r
506                 }               \r
507                 \r
508                 // Create blank resources\r
509                 for(int i=0;i<resources.length;++i)\r
510                         if(resources[i] == null)\r
511                                 resources[i] = graph.newResource();\r
512                 \r
513                 int total = tg.statements.length + tg.values.length;\r
514                 int done = 0;\r
515                 int percentage = 0;\r
516                 \r
517                 // Write statements\r
518                 int[] statements = tg.statements;\r
519                 \r
520                 for(int i=0;i<statements.length;i+=4) {\r
521                         int inv = statements[i+2];\r
522                         graph.claim(\r
523                                         resources[statements[i]],\r
524                                         resources[statements[i+1]],\r
525                                         inv < 0 ? null : resources[inv],\r
526                                         resources[statements[i+3]]\r
527                                         );\r
528                         if(LOG) {\r
529                                 log("[STATEMENT] " + resources[statements[i]].getResourceId() + ", " + resources[statements[i+1]].getResourceId() + ", " + resources[statements[i+3]].getResourceId());\r
530                         }\r
531                         percentage = updatePercentage(percentage, done++, total);\r
532                 }\r
533 \r
534                 // Write values\r
535                 for(Value value : tg.values) {\r
536                         Variant variant = translate2(value, resources);\r
537                         int file = value.resource & 0x80000000;\r
538                         int resource = value.resource & 0x7FFFFFFF;\r
539                         if (file != 0) {\r
540                             throw new UnsupportedOperationException();\r
541                                 //graph.claimValue(resources[resource], value.value, Bindings.BYTE_ARRAY);\r
542                         } else {\r
543                             graph.claimValue(resources[resource], variant.getValue(), variant.getBinding());\r
544                         }\r
545             percentage = updatePercentage(percentage, done++, total);\r
546                 }\r
547                 \r
548         }\r
549         \r
550         public long[] getResourceIds(SerialisationSupport serializer) throws DatabaseException {\r
551                 final int count = resources.length;\r
552                 long[] resourceIds = new long[count];\r
553                 if(handles != null) {\r
554                         for(int i=0;i<count;++i)\r
555                                 resourceIds[i] = serializer.getRandomAccessId(handles[i].resource(serializer));\r
556                 } else {\r
557                         for(int i=0;i<count;++i)\r
558                                 resourceIds[i] = serializer.getRandomAccessId(resources[i]);\r
559                 }\r
560                 return resourceIds;\r
561         }\r
562 }