]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/genericrelation/DependencyChangesWriter.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / genericrelation / DependencyChangesWriter.java
1 package org.simantics.db.layer0.genericrelation;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.List;
7 import java.util.Map;
8
9 import org.simantics.db.ReadGraph;
10 import org.simantics.db.Resource;
11 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
12 import org.simantics.db.common.request.IndexRoots;
13 import org.simantics.db.common.request.PossibleIndexRoot;
14 import org.simantics.db.exception.DatabaseException;
15 import org.simantics.db.layer0.genericrelation.DependencyChanges.Change;
16 import org.simantics.db.layer0.genericrelation.DependencyChanges.ChangeType;
17 import org.simantics.db.layer0.genericrelation.DependencyChanges.ComponentAddition;
18 import org.simantics.db.layer0.genericrelation.DependencyChanges.ComponentModification;
19 import org.simantics.db.layer0.genericrelation.DependencyChanges.ComponentRemoval;
20 import org.simantics.db.layer0.genericrelation.DependencyChanges.LinkChange;
21 import org.simantics.db.service.CollectionSupport;
22 import org.simantics.layer0.Layer0;
23
24 import gnu.trove.map.hash.THashMap;
25
26 public class DependencyChangesWriter {
27     ReadGraph g;
28     Layer0 l0;
29
30     THashMap<Resource, Change> changesByResource = new THashMap<>();
31     ArrayList<ComponentRemoval> removals = new ArrayList<>();
32
33     public DependencyChangesWriter(ReadGraph g) {
34         this.g = g;
35         this.l0 = Layer0.getInstance(g);
36     }
37
38     public void addComponentModification(Resource component) throws DatabaseException {
39         if (!component.isPersistent())
40             return;
41         if(!changesByResource.contains(component))
42             changesByResource.put(component, new ComponentModification(component));
43     }
44
45     public void addLinkChange(Resource component) throws DatabaseException {
46         if (!component.isPersistent())
47             return;
48         //if(!changesByResource.contains(component))
49             changesByResource.put(component, new LinkChange(component));
50     }
51
52     public void addComponentAddition(Resource parent, Resource component) throws DatabaseException {
53         if (!component.isPersistent())
54             return;
55         changesByResource.put(component, new ComponentAddition(component, parent));
56     }
57
58     public void addComponentRemoval(Resource parent, Resource component) throws DatabaseException {
59 //      System.err.println("addComponentRemoval " + component);
60         // NOTE: removals are registered by their parent resource because the
61         // (component, PartOf, parent) link no longer exists and the model cannot
62         // be found otherwise.
63 //        changesByResource.put(parent, new ComponentRemoval(component, parent));
64         if (!component.isPersistent())
65             return;
66         removals.add(new ComponentRemoval(component, parent));
67     }
68
69     public DependencyChanges getResult() throws DatabaseException {
70         THashMap<Resource, ArrayList<Change>> changes = new THashMap<>();
71         CollectionSupport cs = g.getService(CollectionSupport.class);
72         List<Resource> keys = cs.asSortedList(changesByResource.keySet());
73         boolean hasUnresolved = false;
74         for(Resource key : keys) {
75             Change change = changesByResource.get(key);
76             // Default logic with simpler index root resolution.
77             Resource model = g.syncRequest(new PossibleIndexRoot(key), TransientCacheListener.<Resource>instance());
78             boolean modelFound = model != null;
79             if (model != null) {
80                 addChange(model, change, changes);
81             } else {
82                 // Very heavy fallback logic
83                 Collection<Resource> models = g.syncRequest(new IndexRoots(key), TransientCacheListener.<Collection<Resource>>instance());
84                 for(Resource m : models)
85                     addChange(m, change, changes);
86                 modelFound = !models.isEmpty();
87             }
88             if (modelFound && change.getType() == ChangeType.COMPONENT_ADDITION) {
89                 hasUnresolved = true;
90             }
91         }
92         if (!removals.isEmpty()) {
93             THashMap<Resource, ComponentRemoval> removedComponents = new THashMap<>(removals.size());
94             for(ComponentRemoval removal : removals)
95                 removedComponents.put(removal.component, removal);
96             for(ComponentRemoval removal : removals) {
97                 Resource parent = removal.parent;
98                 Collection<Resource> models = getModelsForRemoved(g, parent, removedComponents); 
99                 for(Resource model : models) {
100                     ArrayList<Change> modelChanges = changes.get(model);
101                     if(modelChanges == null) {
102                         modelChanges = new ArrayList<>();
103                         changes.put(model, modelChanges);
104                     }
105                     modelChanges.add(removal);
106                 }
107                 if(models.isEmpty() && !removedComponents.contains(parent)) {
108                     hasUnresolved = true;
109                 }
110             }
111         }
112
113         return new DependencyChanges(changes, hasUnresolved);
114     }
115
116     private void addChange(Resource model, Change change, Map<Resource, ArrayList<Change>> changes) {
117         ArrayList<Change> modelChanges = changes.get(model);
118         if(modelChanges == null) {
119             modelChanges = new ArrayList<>();
120             changes.put(model, modelChanges);
121         }
122         modelChanges.add(change);
123     }
124
125     private Collection<Resource> getModelsForRemoved(ReadGraph graph, Resource resource, THashMap<Resource, ComponentRemoval> removedComponents) throws DatabaseException {
126         ComponentRemoval removal = removedComponents.get(resource);
127         if(removal == null) {
128             Resource model = g.syncRequest(new PossibleIndexRoot(resource), TransientCacheListener.<Resource>instance());
129             if (model != null)
130                 return Collections.singleton(model);
131             return graph.syncRequest(new IndexRoots(resource), TransientCacheListener.<Collection<Resource>>instance());
132         }
133         return getModelsForRemoved(graph, removal.parent, removedComponents);
134     }
135     
136 }