]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.document.server/src/org/simantics/document/server/client/DocumentClient.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.document.server / src / org / simantics / document / server / client / DocumentClient.java
1 package org.simantics.document.server.client;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.Comparator;
7 import java.util.HashMap;
8 import java.util.HashSet;
9
10 import org.simantics.db.common.procedure.adapter.ListenerAdapter;
11 import org.simantics.db.common.procedure.adapter.ListenerSupport;
12 import org.simantics.db.layer0.variable.ProxyChildVariable;
13 import org.simantics.document.server.DocumentHistoryCollector;
14 import org.simantics.document.server.JSONObject;
15 import org.simantics.utils.datastructures.Pair;
16 import org.simantics.utils.threads.IThreadWorkQueue;
17
18 abstract public class DocumentClient implements Document {
19
20         protected HashMap<String, WidgetData> widgetData = new HashMap<String, WidgetData>();
21         private WidgetMapping mapping;
22     private CommandMapping commandMapping;
23         
24         public DocumentClient(WidgetMapping mapping, CommandMapping commandMapping) {
25                 this.mapping = mapping;
26                 this.commandMapping = commandMapping;
27         }
28
29         @Override
30         public WidgetManager<?, ?> getManager(JSONObject object) {
31                 return mapping.getWidget(object.getType());
32         }
33         
34         @Override
35         public WidgetData getWidget(String id) {
36                 return widgetData.get(id);
37         }
38         
39         abstract public IThreadWorkQueue thread();
40         
41         protected void updateDocument(Collection<JSONObject> objects) {
42
43                 ArrayList<WidgetData> updatedData = new ArrayList<WidgetData>();
44                 // Cache data
45                 for (JSONObject object : objects) {
46                         WidgetData datum = widgetData.get(object.getId());
47                         if(datum == null) {
48                                 datum = new WidgetData(this, null, object);
49                                 widgetData.put(object.getId(), datum);
50                         } else {
51                                 // This could replace changed information instead of replacing the whole object
52                                 datum.object = object;
53                         }
54                         updatedData.add(datum);
55                 }
56
57                 // Create widgets
58                 for(WidgetData datum : updatedData) {
59                         createElementIfNecessary(datum);
60                 }
61                 
62                 HashSet<WidgetData> updatedParents = new HashSet<WidgetData>(); 
63                 
64                 // Update parent hierarchy
65                 for(WidgetData datum : updatedData) {
66                         updateChildmaps(datum, updatedParents);
67                 }
68                 
69                 updateTree(updatedParents);
70                 
71                 // Set values
72                 for(WidgetData datum : updatedData) {
73                         datum.updateProperties();
74                         datum.updateCommands();
75                 }
76
77         }
78         
79         private void createElementIfNecessary(WidgetData data) {
80                 if(data.widget == null) { 
81                         data.widget = data.createElement();
82                 }
83         }
84
85         private void updateChildmaps(WidgetData data, HashSet<WidgetData> updates) {
86
87                 // Root
88                 if(data.object == null) return;
89                 
90 //              System.err.println("p:" + data.object);
91 //              Object o = data.object.getParent();
92                 
93                 WidgetData parent = widgetData.get(data.object.getParent()); 
94
95 //              System.out.println("parent:" + parent);
96
97                 if(parent == null) return;
98                 
99                 String parentOrd = data.object.getParentOrd();
100                 
101                 WidgetData existing = parent.childmap.get(parentOrd);
102                 if(!data.equals(existing)) {
103                         updates.add(parent);
104                         parent.childmap.put(parentOrd, data);
105                 }
106                 
107         }
108
109         protected void updateTree(HashSet<WidgetData> updates) {
110                 
111                 if(updates.isEmpty()) return;
112                 
113                 ArrayList<WidgetData> updateList = new ArrayList<WidgetData>(updates);
114                 Collections.sort(updateList, new Comparator<WidgetData>() {
115
116                         private boolean isParent(WidgetData data, WidgetData possibleParent) {
117                                 WidgetData parent = widgetData.get(data.object.getParent());
118                                 if(parent == null) return false;
119                                 else if(parent == possibleParent) return true;
120                                 else return isParent(parent, possibleParent);
121                         }
122                         
123                         @Override
124                         public int compare(WidgetData arg0, WidgetData arg1) {
125                                 if(arg0 == arg1) return 0;
126                                 else if( isParent(arg0, arg1) ) return 1;
127                                 else if( isParent(arg1, arg0) ) return -1;
128                                 else return 0;
129                         }
130                         
131                 });
132                         
133                 for(WidgetData d : updateList) d.updateChildren();
134                 
135         }
136         
137         public class DocumentListener extends ListenerAdapter<Integer> {
138
139                 int revision = -1;
140                 
141                 final private ListenerSupport support;
142                 final private String document;
143                 final private String input;
144                 private boolean performing = false;
145                 
146                 public DocumentListener(ListenerSupport support, String document, String input) {
147                         this.support = support;
148                         this.document = document;
149                         this.input = input;
150                 }
151                 
152                 public synchronized void perform() {
153                     if(performing) return;
154                     performing = true;
155                     try {
156                         Pair<Integer, Collection<JSONObject>> content = DocumentHistoryCollector.getContent(DocumentListener.this, document + "/" + ProxyChildVariable.CONTEXT_BEGIN  + input + "/" + ProxyChildVariable.CONTEXT_END, revision);
157                         revision = content.first;
158                         updateDocument(content.second);
159                     } finally {
160                         performing = false;
161                     }
162                 }
163                 
164                 Runnable updater = new Runnable() {
165
166                         @Override
167                         public void run() {
168                                 perform();
169 //                              Pair<Integer, Collection<JSONObject>> content = DocumentHistoryCollector.getContent(DocumentListener.this, document + "/???" + input + "/???", revision);
170 //                              revision = content.first;
171 //                              updateDocument(content.second);
172                         }
173                         
174                 };
175                 
176                 @Override
177                 public void execute(Integer result) {
178                         IThreadWorkQueue thread = thread();
179                         if(thread.currentThreadAccess()) thread.syncExec(updater);
180                         else thread.asyncExec(updater);
181                 }
182                 
183                 @Override
184                 public boolean isDisposed() {
185                         return support.isDisposed();
186                 }
187
188         };
189         
190         public void track(ListenerSupport support, String document, String input) {
191                 
192                 new DocumentListener(support, document, input).perform();
193                 
194 //              DocumentHistoryCollector.register(location, listener);
195 //              listener.execute(-1);
196                 
197         }
198         
199         WidgetData getRoot() {
200                 return widgetData.get("root");
201         }
202         
203         @SuppressWarnings("unchecked")
204         <T> T getRootWidget() {
205                 return (T)getRoot().widget;
206         }
207         
208         @Override
209         public CommandManager<?, ?> getCommandManager(JSONObject object) {
210             return commandMapping.getCommandManager(object.getType());
211         }
212         
213 }