]> gerrit.simantics Code Review - simantics/interop.git/blobdiff - org.simantics.interop.mapping/src/org/simantics/interop/mapping/Mapper.java
refs #3483
[simantics/interop.git] / org.simantics.interop.mapping / src / org / simantics / interop / mapping / Mapper.java
diff --git a/org.simantics.interop.mapping/src/org/simantics/interop/mapping/Mapper.java b/org.simantics.interop.mapping/src/org/simantics/interop/mapping/Mapper.java
new file mode 100644 (file)
index 0000000..6f700d3
--- /dev/null
@@ -0,0 +1,772 @@
+package org.simantics.interop.mapping;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.NullProgressMonitor;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.VirtualGraph;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.common.request.WriteResultRequest;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.layer0.util.SessionGarbageCollection;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.interop.mapping.data.GraphNode;\r
+import org.simantics.interop.mapping.data.Identifiable;\r
+import org.simantics.interop.mapping.data.Link;\r
+import org.simantics.interop.mapping.data.ResourceIdentifiable;\r
+import org.simantics.ui.jobs.SessionGarbageCollectorJob;\r
+import org.simantics.utils.datastructures.MapList;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+/**\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class Mapper {\r
+       \r
+       public static final boolean USE_SPLIT_TRANSACTIONS = false; // Split transactions\r
+       public static int OBJECTS_PER_TRANSACTION = 5000;           // number of objects handled per transaction (split mode) \r
+       private static boolean SLEEP_BETWEEN_WRITES = false;        // sleep between transactions (split mode)     \r
+       private static int SLEEP_TIME = 10;                         // time to sleep (ms)\r
+       private static boolean COLLECT_BETWEEN_WRITES = false;      // Run SessionGC between split transactions\r
+       private static boolean COLLECT_WITHIN_TRANSACTIONS = true;  // Run Collect within transactions (both modes)\r
+       public static int OBJECTS_BEFORE_COLLECT = 5000;            // number of objects that are handled before collect (non-split mode)\r
+       \r
+       private List<InitializedRule> initializedRules = new ArrayList<InitializedRule>();\r
+       private List<Pair<IdentificationRule, Pair<Integer,GenerationRule>>> generationRules;\r
+       private List<List<ModificationRule>> globalModificationRules;\r
+       private List<List<Pair<IdentificationRule, ModificationRule>>> modificationRules;\r
+       private List<Pair<ConnectionIdentificationRule, ConnectionGenerationRule>> connectionRules;\r
+\r
+       int maxGenPass = 0;\r
+       \r
+       public Mapper() {\r
+               long maxMemory = Runtime.getRuntime().maxMemory();\r
+               maxMemory /= (1024*1024);                            // Convert to MB;\r
+               int use = 290;                                       // Estimated memory usage of the system\r
+               int freeMem = (int)maxMemory-use;                                        // Free memory for mappings    \r
+               OBJECTS_BEFORE_COLLECT = (freeMem * freeMem) / 1000; //600M heap -> 84, 3000M heap -> 5645\r
+               if (OBJECTS_BEFORE_COLLECT < 2)\r
+                       OBJECTS_BEFORE_COLLECT = 2;\r
+               OBJECTS_PER_TRANSACTION = OBJECTS_BEFORE_COLLECT;\r
+               \r
+               \r
+               generationRules = new ArrayList<Pair<IdentificationRule,Pair<Integer,GenerationRule>>>();\r
+               modificationRules = new ArrayList<List<Pair<IdentificationRule,ModificationRule>>>();\r
+               globalModificationRules = new ArrayList<List<ModificationRule>>();\r
+               connectionRules = new ArrayList<Pair<ConnectionIdentificationRule, ConnectionGenerationRule>>();\r
+       }\r
+       \r
+       public void addRule(int pass, IdentificationRule idRule, GenerationRule genRule) {\r
+               if (idRule == null || genRule == null) throw new NullPointerException();\r
+               generationRules.add(new Pair<IdentificationRule, Pair<Integer,GenerationRule>>(idRule, new Pair<Integer,GenerationRule>(pass,genRule)));\r
+               maxGenPass = Math.max(maxGenPass, pass);\r
+               if (genRule instanceof InitializedRule)\r
+                       initializedRules.add((InitializedRule)genRule);\r
+       }\r
+       \r
+       public void addRule(IdentificationRule idRule, MappingRule mappingRule) {\r
+               addRule(0,idRule,mappingRule);\r
+       }\r
+       \r
+       public void addRule(int pass, IdentificationRule idRule, MappingRule mappingRule) {\r
+               if (idRule == null || mappingRule == null) throw new NullPointerException();\r
+               if (mappingRule instanceof ModificationRule) {\r
+                       while (pass >= modificationRules.size()) {\r
+                               modificationRules.add(new ArrayList<Pair<IdentificationRule,ModificationRule>>());\r
+                       }\r
+                       List<Pair<IdentificationRule,ModificationRule>> priList = modificationRules.get(pass);\r
+                       priList.add(new Pair<IdentificationRule, ModificationRule>(idRule, (ModificationRule)mappingRule));\r
+               }\r
+               if (mappingRule instanceof GenerationRule)\r
+                       generationRules.add(new Pair<IdentificationRule, Pair<Integer,GenerationRule>>(idRule, new Pair<Integer,GenerationRule>(pass,(GenerationRule)mappingRule)));\r
+               if (mappingRule instanceof InitializedRule)\r
+                       initializedRules.add((InitializedRule)mappingRule);\r
+       }\r
+       \r
+       public void addRule(IdentificationRule idRule, ModificationRule... modRules) {\r
+               addRule(0, idRule, modRules);\r
+       }\r
+\r
+       public void addRule(int pass, IdentificationRule idRule, ModificationRule... modRules) {\r
+               if (idRule == null) throw new NullPointerException();\r
+               \r
+               while (pass >= modificationRules.size()) {\r
+                       modificationRules.add(new ArrayList<Pair<IdentificationRule,ModificationRule>>());\r
+               }\r
+               List<Pair<IdentificationRule,ModificationRule>> priList = modificationRules.get(pass);\r
+               \r
+               for (ModificationRule modRule : modRules){\r
+                       if (modRule == null) throw new NullPointerException();  \r
+                       priList.add(new Pair<IdentificationRule, ModificationRule>(idRule, modRule));\r
+                       if (modRule instanceof InitializedRule)\r
+                               initializedRules.add((InitializedRule)modRule);\r
+               }\r
+       }\r
+       public void addRule(ModificationRule modRule) {\r
+               addRule(0, modRule);\r
+       }\r
+       \r
+       public void addRule(int pass, ModificationRule modRule) {\r
+               if (modRule == null) throw new NullPointerException();\r
+               while (pass >= globalModificationRules.size()) {\r
+                       globalModificationRules.add(new ArrayList<ModificationRule>());\r
+               }\r
+               List<ModificationRule> priList = globalModificationRules.get(pass);\r
+               priList.add(modRule);\r
+               if (modRule instanceof InitializedRule)\r
+                       initializedRules.add((InitializedRule)modRule);\r
+       }\r
+       \r
+       public void addRule(ConnectionIdentificationRule idRule, ConnectionGenerationRule genRule) {\r
+               if (idRule == null || genRule == null) throw new NullPointerException();\r
+               connectionRules.add(new Pair<ConnectionIdentificationRule, ConnectionGenerationRule>(idRule, genRule));\r
+               if (genRule instanceof InitializedRule)\r
+                       initializedRules.add((InitializedRule)genRule);\r
+       }\r
+       \r
+       /**\r
+        * Runs the mapping procedure. Disposes nodes after mapping is done.\r
+        * @param g\r
+        * @param model\r
+        * @param nodes\r
+        * @param monitor\r
+        * @throws Exception\r
+        */\r
+       public void map(WriteGraph g, Resource model, Collection<GraphNode<Identifiable>> nodes, IProgressMonitor monitor) throws Exception {\r
+               startMapping(null);\r
+               try {\r
+                       if (monitor == null)\r
+                               monitor = new NullProgressMonitor();\r
+                       \r
+                       for (InitializedRule rule : initializedRules)\r
+                               rule.initialize(g, model);\r
+                       \r
+                       applyModifications(g, nodes, monitor);\r
+                       monitor.worked(1);\r
+                       applyGenerations(g,nodes,monitor);\r
+                       monitor.worked(1);\r
+                       applyConnections(g,nodes,monitor);\r
+                       monitor.worked(1);\r
+               } finally {\r
+                       MappingTools.disposeNodes(nodes);\r
+                       endMapping();\r
+               }\r
+               \r
+       }\r
+       \r
+       /**\r
+        * Runs the mapping procedure. Disposes nodes after mapping is done.\r
+        * @param session\r
+        * @param model\r
+        * @param nodes\r
+        * @param monitor\r
+        * @throws Exception\r
+        */\r
+       public void map(Session session, Resource model, Collection<GraphNode<Identifiable>> nodes, IProgressMonitor monitor) throws Exception {\r
+               map(session, model, null, nodes, monitor);\r
+       }\r
+       \r
+       /**\r
+        * Runs the mapping procedure. Disposes nodes after mapping is done.\r
+        * @param session\r
+        * @param model\r
+        * @param vg\r
+        * @param nodes\r
+        * @param monitor\r
+        * @throws Exception\r
+        */\r
+       public void map(Session session, Resource model, VirtualGraph vg, Collection<GraphNode<Identifiable>> nodes, IProgressMonitor monitor) throws Exception {\r
+               startMapping(vg);\r
+               try {\r
+                       long time = System.currentTimeMillis();\r
+                       if (monitor == null)\r
+                               monitor = new NullProgressMonitor();\r
+                       \r
+                       initializeRules(session, vg, model);\r
+                       if (USE_SPLIT_TRANSACTIONS) {\r
+                               applyModifications(session, nodes, monitor);\r
+                               monitor.worked(1);\r
+                               applyGenerations(session, vg, nodes, monitor);\r
+                               monitor.worked(1);\r
+                               applyConnections(session, vg, nodes, monitor);\r
+                               monitor.worked(1);\r
+                       } else {\r
+                               applyModifications2(session, nodes, monitor);\r
+                               monitor.worked(1);\r
+                               applyGenerations2(session, vg, nodes, monitor);\r
+                               monitor.worked(1);\r
+                               applyConnections2(session, vg, nodes, monitor);\r
+                               monitor.worked(1);\r
+                       }\r
+                       long time2 = System.currentTimeMillis();\r
+                       System.out.println("Mapping took " + ((time2-time)/1000) + " seconds");\r
+               } finally {\r
+                       MappingTools.disposeNodes(nodes);\r
+                       if (COLLECT_BETWEEN_WRITES) {\r
+\r
+                               SessionGarbageCollection.gc(null, session, true, null);\r
+                       }\r
+                       endMapping();\r
+               }\r
+               \r
+       }\r
+       \r
+       \r
+       //private boolean autosaveEndabled = false;\r
+       private VirtualGraph vg;\r
+       \r
+       protected void startMapping(VirtualGraph vg) {\r
+                SessionGarbageCollectorJob.getInstance().setEnabled(false);\r
+                //autosaveEndabled = AutosaveCommands.getInstance().isEnabled();\r
+                //AutosaveCommands.getInstance().setEnabled(false);\r
+                this.vg = vg;\r
+       }\r
+       \r
+       protected void endMapping() {\r
+                SessionGarbageCollectorJob.getInstance().setEnabled(true).scheduleAfterQuietTime();\r
+               // AutosaveCommands.getInstance().setEnabled(autosaveEndabled);\r
+                vg = null;\r
+       }\r
+       \r
+       private void applyModifications(ReadGraph g, Collection<GraphNode<Identifiable>> nodes, IProgressMonitor monitor) throws Exception {\r
+               \r
+               // Apply global modification rules first\r
+               \r
+               int passCount = Math.max(globalModificationRules.size(),modificationRules.size());\r
+\r
+               for (int pass = 0; pass < passCount; pass++) {\r
+                       if (globalModificationRules.size() > pass) {\r
+                               int count = 0;\r
+                               List<ModificationRule> modRules = globalModificationRules.get(pass);\r
+                               int size = modRules.size();\r
+                               monitor.subTask("Running global modification rules: pass (" + (pass+1) + "/" + passCount + "), rule ("+ (++count) + "/" + size + ")");\r
+                               for (ModificationRule r : modRules) {\r
+                                       Collection<GraphNode<Identifiable>> ruleModified = r.modify(g, nodes);\r
+                                       if (ruleModified == null)\r
+                                               continue;\r
+                                       for (GraphNode<Identifiable> m : ruleModified) {\r
+                                               if (m.isDisposed()) {\r
+                                                       nodes.remove(m);\r
+                                               }\r
+                                               else if (!nodes.contains(m)) {\r
+                                                       nodes.add(m);\r
+                                               }\r
+                                       }\r
+                                       monitor.subTask("Running global modification rules: pass (" + (pass+1) + "/" + passCount + "), rule ("+ (++count) + "/" + size + ")");\r
+                                       if(monitor.isCanceled()) {\r
+                                               throw new CancelException("Cancel requested.");\r
+                                       }\r
+                                       if (COLLECT_WITHIN_TRANSACTIONS)\r
+                                               collect(g);\r
+                               }\r
+                       } if (modificationRules.size() > pass) {\r
+                               int count = 0;\r
+                               List<Pair<IdentificationRule, ModificationRule>> modRules = modificationRules.get(pass);\r
+                               int size = modRules.size();\r
+                               monitor.subTask("Running object modification rules: pass (" + (pass+1) + "/" + passCount + "), rule ("+ (++count) + "/" + size + ")");\r
+                               // Apply per object modification rules \r
+                               for (Pair<IdentificationRule, ModificationRule> modRule : modRules) {\r
+                                       Collection<GraphNode<Identifiable>> ruleModified = new ArrayList<GraphNode<Identifiable>>();\r
+                                       for (GraphNode<Identifiable> n : nodes) {\r
+                                               applyModifications(g, n, modRule, ruleModified);\r
+                                               if (COLLECT_WITHIN_TRANSACTIONS)\r
+                                                       collect2(g);\r
+                                       }\r
+                                       \r
+                                       for (GraphNode<Identifiable> m : ruleModified) {\r
+                                               if (m.isDisposed()) {\r
+                                                       nodes.remove(m);\r
+                                               }\r
+                                               else if (!nodes.contains(m)) {\r
+                                                       nodes.add(m);\r
+                                               }\r
+                                       }\r
+                                       monitor.subTask("Running object modification rules: pass (" + (pass+1) + "/" + passCount + "), rule ("+ (++count) + "/" + size + ")");\r
+                                       if(monitor.isCanceled()) {\r
+                                               throw new CancelException("Cancel requested.");\r
+                                       }\r
+                                       \r
+                               }\r
+                       }\r
+               }\r
+               \r
+       }\r
+       \r
+       \r
+       \r
+       private void applyGenerations(WriteGraph graph, Collection<GraphNode<Identifiable>> nodes, IProgressMonitor monitor) throws Exception {\r
+               \r
+               int size = nodes.size();\r
+               int count = 0;\r
+               monitor.subTask("Assigning generation rules ("+ count + "/" + size + ")");\r
+               // populate generation rules\r
+               for (GraphNode<Identifiable> n : nodes) {\r
+                       \r
+                       for (Pair<IdentificationRule,Pair<Integer,GenerationRule>> r : generationRules) {\r
+                               if (r.first.matches(graph, n)) {\r
+                                       MappingTools.assignGenerationRule(n, r.second.first,r.second.second);\r
+                               }\r
+                       }\r
+                       monitor.subTask("Assigning generation rules ("+ (++count) + "/" + size + ")");\r
+                       if(monitor.isCanceled()) {\r
+                               throw new CancelException("Cancel requested.");\r
+                       }\r
+                       if (COLLECT_WITHIN_TRANSACTIONS)\r
+                               collect2(graph);\r
+               }\r
+               \r
+               count = 0;\r
+               monitor.subTask("Generating objects ("+ count + "/" + size + ")");\r
+               \r
+               // apply generation rules.\r
+               //WriteWrapper g  = new WriteWrapper(graph);\r
+               \r
+               //Collection<GenerationRule> usedRules = new ArrayList<GenerationRule>();\r
+               for (int stage = 0; stage <= maxGenPass; stage++) {\r
+                       count = 0;\r
+                       for (GraphNode<Identifiable> n : nodes) {\r
+\r
+                               MapList<Integer,GenerationRule> priRules = n.getHint(MappingHints.KEY_GENERATION_RULES);\r
+                               List<GenerationRule> rules = priRules.getValues(stage);\r
+                               for (GenerationRule r : rules) {\r
+                                       r.generate(graph, n);\r
+                               }\r
+\r
+                               monitor.subTask("Generating objects, stage " + stage + " :  ("+ (++count) + "/" + size + ")");\r
+                               if(monitor.isCanceled()) {\r
+                                       throw new CancelException("Cancel requested.");\r
+                               }\r
+                               if (COLLECT_WITHIN_TRANSACTIONS)\r
+                                       collect2(graph);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       private void applyConnections(WriteGraph g, Collection<GraphNode<Identifiable>> nodes, IProgressMonitor monitor) throws Exception {\r
+               int size = nodes.size();\r
+               int count = 0;\r
+               \r
+               monitor.subTask("Generating connections ("+ count + "/" + size + ")");\r
+               \r
+               for (GraphNode<Identifiable> node : nodes) {\r
+                       applyConnections(g, node);\r
+                       monitor.subTask("Generating connections ("+ (++count) + "/" + size + ")");\r
+                       if(monitor.isCanceled()) {\r
+                               throw new CancelException("Cancel requested.");\r
+                       }\r
+                       if (COLLECT_WITHIN_TRANSACTIONS)\r
+                               collect2(g);\r
+               }\r
+       }\r
+       \r
+       \r
+       \r
+       protected String getName(ReadGraph g, Identifiable res) throws DatabaseException {\r
+               if (res instanceof ResourceIdentifiable)\r
+                       return NameUtils.getSafeName(g, ((ResourceIdentifiable)res).getResource());\r
+               else\r
+                       return res.toString();\r
+       }\r
+       \r
+       public class WriteWrapper extends WriteGraphProxy {\r
+               \r
+               \r
+               private Collection<Resource> createdResources = new ArrayList<Resource>();\r
+               \r
+               public WriteWrapper(WriteGraph graph) {\r
+                       super(graph);\r
+               }\r
+               \r
+               public Collection<Resource> getCreatedResources() {\r
+                       return createdResources;\r
+               }\r
+               \r
+               public void clearCreated() {\r
+                       createdResources = new ArrayList<Resource>();\r
+               }\r
+               \r
+               @Override\r
+               public Resource newResource() throws ServiceException {\r
+                       Resource res = graph.newResource();\r
+                       createdResources.add(res);\r
+                       return res;\r
+               }\r
+               \r
+               @Override\r
+               public Resource newResource(long clusterId) throws ServiceException {\r
+                       Resource res = graph.newResource(clusterId);\r
+                       createdResources.add(res);\r
+                       return res;\r
+               }\r
+               \r
+               \r
+       }\r
+       \r
+       private void initializeRules(Session session, VirtualGraph vg, final Resource model ) throws DatabaseException{\r
+               session.syncRequest(new WriteRequest(vg) {\r
+                       @Override\r
+                       public void perform(WriteGraph g) throws DatabaseException {\r
+                               for (InitializedRule rule : initializedRules)\r
+                                       rule.initialize(g, model);\r
+                               \r
+                       }\r
+               });\r
+               \r
+       }\r
+               \r
+       private void collect(ReadGraph g) throws DatabaseException {\r
+               if (vg != null)\r
+                       return;\r
+               SessionGarbageCollection.gc(g, 0, -1);\r
+       }\r
+       \r
+       int collect = 0;\r
+       \r
+       private void collect2(ReadGraph g) throws DatabaseException {\r
+               if (vg != null)\r
+                       return;\r
+               \r
+               if (collect == OBJECTS_BEFORE_COLLECT) {\r
+                       SessionGarbageCollection.gc(g, 0, -1);\r
+                       collect = 0;\r
+               } else {\r
+                       collect++;\r
+               }\r
+       }\r
+       \r
+       private void applyModifications(Session session, final Collection<GraphNode<Identifiable>> nodes, final IProgressMonitor monitor) throws Exception {\r
+               \r
+               \r
+               \r
+               int passCount = Math.max(globalModificationRules.size(),modificationRules.size());\r
+               \r
+               for (int pass = 0; pass <passCount; pass++) {\r
+                       // Apply global modification rules first\r
+                       if (globalModificationRules.size() > pass) {\r
+                               int count = 0;\r
+                               List<ModificationRule> modRules = globalModificationRules.get(pass);\r
+                               int size = modRules.size();\r
+                               monitor.subTask("Running global modification rules: pass (" + (pass+1) + "/" + passCount + "), rule ("+ (++count) + "/" + size + ")");\r
+                               for (final ModificationRule r : modRules) {\r
+                                       session.syncRequest(new ReadRequest() {\r
+                                               \r
+                                               @Override\r
+                                               public void run(ReadGraph g) throws DatabaseException {\r
+                                                       try {\r
+                                                               Collection<GraphNode<Identifiable>> ruleModified = r.modify(g, nodes);\r
+                                                               \r
+                                                               if (ruleModified == null)\r
+                                                                       return;\r
+                                                               for (GraphNode<Identifiable> m : ruleModified) {\r
+                                                                       if (m.isDisposed()) {\r
+                                                                               nodes.remove(m);\r
+                                                                       }\r
+                                                                       else if (!nodes.contains(m)) {\r
+                                                                               nodes.add(m);\r
+                                                                       }\r
+                                                               }\r
+                                                               if (COLLECT_WITHIN_TRANSACTIONS)\r
+                                                                       collect(g);\r
+                                                       } catch (Exception e) {\r
+                                                               throw new DatabaseException(e);\r
+                                                       }\r
+                                                       \r
+                                               }\r
+                                       });\r
+                                       //SessionGarbageCollection.gc(null, session, true, null);\r
+                                       monitor.subTask("Running global modification rules: pass (" + (pass+1) + "/" + passCount + "), rule ("+ (++count) + "/" + size + ")");\r
+                                       if(monitor.isCanceled()) {\r
+                                               throw new CancelException("Cancel requested.");\r
+                                       }\r
+                               }\r
+                       }\r
+                       if (modificationRules.size() > pass) {\r
+                               int count = 0;\r
+                               List<Pair<IdentificationRule, ModificationRule>> modRules = modificationRules.get(pass);\r
+                               int size = modRules.size();\r
+                               monitor.subTask("Running object modification rules: pass (" + (pass+1) + "/" + passCount + "), rule ("+ (++count) + "/" + size + ")");\r
+                               \r
+                               // Apply per object modification rules \r
+                               for (final Pair<IdentificationRule, ModificationRule> modRule : modRules) {\r
+                                       final Iterator<GraphNode<Identifiable>> iter = nodes.iterator();\r
+                                       final Collection<GraphNode<Identifiable>> ruleModified = new ArrayList<GraphNode<Identifiable>>();\r
+                                       while (iter.hasNext()) {\r
+                                               session.syncRequest(new ReadRequest() {\r
+                                                       \r
+                                                       @Override\r
+                                                       public void run(ReadGraph g) throws DatabaseException {\r
+                                                               try {\r
+                                                                       \r
+                                                                       int j = 0; \r
+                                                                       //for (GraphNode<Identifiable> n : nodes) {\r
+                                                                       while (iter.hasNext() && j < OBJECTS_PER_TRANSACTION) {\r
+                                                                               GraphNode<Identifiable> n = iter.next();\r
+                                                                               applyModifications(g, n, modRule, ruleModified);\r
+                                                                               j++;\r
+                                                                       }\r
+                                                                       if (COLLECT_WITHIN_TRANSACTIONS)\r
+                                                                               collect(g);\r
+                                                                       \r
+                                                               } catch (Exception e) {\r
+                                                                       throw new DatabaseException(e);\r
+                                                               }\r
+                                                               \r
+                                                       }\r
+                                               });\r
+                                       }\r
+                                       for (GraphNode<Identifiable> m : ruleModified) {\r
+                                               if (m.isDisposed()) {\r
+                                                       nodes.remove(m);\r
+                                               }\r
+                                               else if (!nodes.contains(m)) {\r
+                                                       nodes.add(m);\r
+                                               }\r
+                                       }\r
+                                       ruleModified.clear();\r
+                                       \r
+                                       //SessionGarbageCollection.gc(null, session, true, null);\r
+                                       monitor.subTask("Running object modification rules: pass (" + (pass+1) + "/" + passCount + "), rule ("+ (++count) + "/" + size + ")");\r
+                                       if(monitor.isCanceled()) {\r
+                                               throw new CancelException("Cancel requested.");\r
+                                       }\r
+                               }\r
+                       }       \r
+               }\r
+               \r
+       }\r
+       \r
+       private void applyModifications2(Session session, final Collection<GraphNode<Identifiable>> nodes, final IProgressMonitor monitor) throws Exception {\r
+               session.syncRequest(new ReadRequest() {\r
+                       \r
+                       @Override\r
+                       public void run(ReadGraph g) throws DatabaseException {\r
+                               try {\r
+                                       applyModifications(g, nodes, monitor);\r
+                               } catch (Exception e) {\r
+                                       throw new DatabaseException(e);\r
+                               }\r
+                               \r
+                       }\r
+               });\r
+       }\r
+       \r
+       private void applyGenerations(Session session, VirtualGraph vg, Collection<GraphNode<Identifiable>> nodes, IProgressMonitor monitor) throws Exception {\r
+               \r
+               int size = nodes.size();\r
+               int count = 0;\r
+               monitor.subTask("Assigning generation rules ("+ count + "/" + size + ")");\r
+               // populate generation rules\r
+\r
+               {\r
+                       final Iterator<GraphNode<Identifiable>> iter = nodes.iterator();\r
+                       while (iter.hasNext()) {\r
+                               int c = session.syncRequest(new Read<Integer>() {\r
+                                       \r
+                                       @Override\r
+                                       public Integer perform(ReadGraph graph)\r
+                                                       throws DatabaseException {\r
+                                               int j = 0;\r
+                                               while (iter.hasNext() && j < OBJECTS_PER_TRANSACTION) {\r
+                                                       GraphNode<Identifiable> n = iter.next();\r
+                                                       for (Pair<IdentificationRule,Pair<Integer,GenerationRule>> r : generationRules) {\r
+                                                               if (r.first.matches(graph, n)) {\r
+                                                                       MapList<Integer,GenerationRule> rules = n.getHint(MappingHints.KEY_GENERATION_RULES);\r
+                                                                       if (rules == null) {\r
+                                                                               rules = new MapList<Integer,GenerationRule>();  \r
+                                                                       }\r
+                                                                       rules.add(r.second.first,r.second.second);\r
+                                                                       n.setHint(MappingHints.KEY_GENERATION_RULES, rules);\r
+                                                               }\r
+                                                       }\r
+                                                       j++;\r
+                                               }\r
+                                               if (COLLECT_WITHIN_TRANSACTIONS)\r
+                                                       collect(graph);\r
+                                               return j;\r
+                                               \r
+                                       }\r
+                               });\r
+                               collect(session);\r
+                               monitor.subTask("Assigning generation rules ("+ (count+=c) + "/" + size + ")");\r
+                               if(monitor.isCanceled()) {\r
+                                       throw new CancelException("Cancel requested.");\r
+                               }\r
+                               sleep();\r
+                       }\r
+               }\r
+               \r
+               count = 0;\r
+               monitor.subTask("Generating objects ("+ (count) + "/" + size + ")");\r
+               \r
+               // apply generation rules.\r
+               \r
+               {\r
+                       for (int stage = 0; stage <= maxGenPass; stage++) {\r
+                               final int fStage = stage;\r
+                               count = 0;\r
+                               final Iterator<GraphNode<Identifiable>> iter = nodes.iterator();\r
+                               while (iter.hasNext()) {\r
+                                       int c = session.syncRequest(new WriteResultRequest<Integer>(vg) {\r
+                                               \r
+                                               @Override\r
+                                               public Integer perform(WriteGraph graph) throws DatabaseException {\r
+                                                       int j = 0;\r
+                                                       try {\r
+                                                               while (iter.hasNext() && j < OBJECTS_PER_TRANSACTION) {\r
+                                                                       GraphNode<Identifiable> n = iter.next();\r
+                                                                       \r
+                                                                       MapList<Integer,GenerationRule> priRules = n.getHint(MappingHints.KEY_GENERATION_RULES);\r
+                                                                       if (priRules == null) {\r
+                                                                               j++;\r
+                                                                               continue;\r
+                                                                       }\r
+                                                                       final List<GenerationRule> rules = priRules.getValues(fStage);\r
+                                                                       \r
+                                                                       if (fStage == 0 && rules.size() == 0)\r
+                                                                               System.out.println();\r
+                                                                       for (GenerationRule r : rules) {\r
+                                                                               r.generate(graph, n);\r
+\r
+                                                                       }\r
+\r
+                                                                               \r
+                                                                       j++;\r
+                                                                       \r
+                                                               }\r
+                                                               if (COLLECT_WITHIN_TRANSACTIONS)\r
+                                                                       collect(graph);\r
+                                                               return j;\r
+                                                       \r
+                                               } catch (Exception e) {\r
+                                                       throw new DatabaseException(e);\r
+                                               }\r
+                                       }});\r
+                                       collect(session);\r
+                                       monitor.subTask("Generating objects, stage " + stage + " :  ("+ (count+=c) + "/" + size + ")");\r
+                                       if(monitor.isCanceled()) {\r
+                                               throw new CancelException("Cancel requested.");\r
+                                       }\r
+                                       sleep();\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       private void applyGenerations2(Session session, VirtualGraph vg, final Collection<GraphNode<Identifiable>> nodes, final IProgressMonitor monitor) throws Exception {\r
+               session.syncRequest(new WriteRequest(vg) {\r
+                       \r
+                       @Override\r
+                       public void perform(WriteGraph graph) throws DatabaseException {\r
+                               try {\r
+                                       applyGenerations(graph, nodes, monitor);\r
+                               } catch (Exception e) {\r
+                                       throw new DatabaseException(e);\r
+                               }\r
+                               \r
+                       }\r
+               });\r
+       }\r
+       \r
+       private void collect(Session session) {\r
+               if (COLLECT_BETWEEN_WRITES)\r
+                       SessionGarbageCollection.gc(null, session, true, null);\r
+       }\r
+       \r
+       \r
+       private void sleep() {\r
+               if (SLEEP_BETWEEN_WRITES) {\r
+                       try {\r
+                               Thread.sleep(SLEEP_TIME);\r
+                       } catch (InterruptedException e) {\r
+                               \r
+                       }\r
+               }\r
+       }\r
+       \r
+       private void applyConnections(Session session, VirtualGraph vg, Collection<GraphNode<Identifiable>> nodes, IProgressMonitor monitor) throws Exception {\r
+               int size = nodes.size();\r
+               int count = 0;\r
+               \r
+               monitor.subTask("Generating connections ("+ count + "/" + size + ")");\r
+               \r
+               final Iterator<GraphNode<Identifiable>> iter = nodes.iterator();\r
+               while (iter.hasNext()) {\r
+                       int c = session.syncRequest(new WriteResultRequest<Integer>(vg) {\r
+                               \r
+                               @Override\r
+                               public Integer perform(WriteGraph g) throws DatabaseException {\r
+                                       int j = 0;\r
+                                       try {\r
+                                               while (iter.hasNext() && j < OBJECTS_PER_TRANSACTION) {\r
+                                                       GraphNode<Identifiable> node = iter.next();\r
+                                                       applyConnections(g, node);\r
+                                                       j++;\r
+                                               }\r
+                                               if (COLLECT_WITHIN_TRANSACTIONS)\r
+                                                       collect(g);\r
+                                               return j;\r
+                                               \r
+                                       } catch (Exception e) {\r
+                                               throw new DatabaseException(e);\r
+                                       }       \r
+                               }       \r
+                       });\r
+                       collect(session);\r
+                       monitor.subTask("Generating connections ("+ (count+=c) + "/" + size + ")");\r
+                       if(monitor.isCanceled()) {\r
+                               throw new CancelException("Cancel requested.");\r
+                       }\r
+                       sleep();\r
+               }\r
+       }\r
+       \r
+       private void applyConnections2(Session session, VirtualGraph vg, final Collection<GraphNode<Identifiable>> nodes, final IProgressMonitor monitor) throws Exception {\r
+               session.syncRequest(new WriteRequest(vg) {\r
+                       \r
+                       @Override\r
+                       public void perform(WriteGraph graph) throws DatabaseException {\r
+                               try {\r
+                                       applyConnections(graph, nodes, monitor);\r
+                               } catch (Exception e) {\r
+                                       throw new DatabaseException(e);\r
+                               }\r
+                               \r
+                       }\r
+               });\r
+       }\r
+\r
+       private void applyModifications(ReadGraph g, GraphNode<Identifiable> n, Pair<IdentificationRule, ModificationRule> modRule, Collection<GraphNode<Identifiable>> ruleModified) throws Exception {\r
+               if (!n.isDisposed() && modRule.first.matches(g, n)) { // we have to check \r
+                       Collection<GraphNode<Identifiable>> perRule = new ArrayList<GraphNode<Identifiable>>();\r
+                       perRule.add(n);\r
+                       ruleModified.addAll(modRule.second.modify(g, perRule));\r
+               }\r
+       }\r
+       \r
+       private void applyConnections(WriteGraph g, GraphNode<Identifiable> node) throws Exception {\r
+               for (Link<Identifiable> link : node.getLinks()) {\r
+                       if (link.isMain()) {\r
+                               \r
+                               for (Pair<ConnectionIdentificationRule, ConnectionGenerationRule> r : connectionRules) {\r
+                                       if (r.first.mathces(g, node, link.to(), link)) {\r
+                                               Logger.defaultLogInfo("Connecting " +  getName(g, node.getData()) + " to " + getName(g, link.to().getData()) + " " + link.getName() + "/"+link.getInverseName());\r
+                                               r.second.generate(g, node, link.to(), link);\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+}\r