]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scenegraph.profile/src/org/simantics/scenegraph/profile/common/ProfileObserver.java
Preliminary implementation to update only changed profile entries
[simantics/platform.git] / bundles / org.simantics.scenegraph.profile / src / org / simantics / scenegraph / profile / common / ProfileObserver.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.scenegraph.profile.common;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.concurrent.TimeUnit;
20
21 import org.simantics.Simantics;
22 import org.simantics.db.AsyncRequestProcessor;
23 import org.simantics.db.Resource;
24 import org.simantics.db.Session;
25 import org.simantics.db.common.session.SessionEventListenerAdapter;
26 import org.simantics.db.common.utils.Logger;
27 import org.simantics.db.procedure.Procedure;
28 import org.simantics.db.service.SessionEventSupport;
29 import org.simantics.scenegraph.INode;
30 import org.simantics.scenegraph.g2d.G2DSceneGraph;
31 import org.simantics.scenegraph.profile.EvaluationContext;
32 import org.simantics.scenegraph.profile.ProfileEntry;
33 import org.simantics.scenegraph.profile.Style;
34 import org.simantics.scenegraph.profile.impl.DebugPolicy;
35 import org.simantics.scenegraph.profile.impl.ProfileActivationListener;
36 import org.simantics.scenegraph.profile.request.RuntimeProfileActiveEntries;
37 import org.simantics.utils.datastructures.Pair;
38 import org.simantics.utils.datastructures.disposable.IDisposable;
39 import org.simantics.utils.threads.IThreadWorkQueue;
40 import org.simantics.utils.threads.ThreadUtils;
41
42 public class ProfileObserver implements EvaluationContext {
43
44     private final Session                     session;
45
46     /**
47      * Runtime diagram resource.
48      */
49     private final Resource                    resource;
50
51     private final IDisposable                 canvas;
52     private final IThreadWorkQueue            thread;
53     @SuppressWarnings("unused")
54     private final Object                      diagram;
55     private final Runnable                    notification;
56     private final G2DSceneGraph               sceneGraph;
57
58     private volatile boolean                           dirty               = true;
59     private volatile boolean                           disposed            = false;
60
61     private List<Pair<Style, Object>> updates = new ArrayList<>();
62     private boolean updateAll;
63     
64     private ProfileActivationListener         activationListener;
65
66     private Map<String, Object>               constants           = new HashMap<String, Object>();
67
68     private Map<INode, Map<String, Object>>   temporaryProperties = new HashMap<INode, Map<String, Object>>();
69     private Map<INode, Map<String, Object>>   properties          = new HashMap<INode, Map<String, Object>>();
70
71     private final SessionEventListenerAdapter transactionListener = new SessionEventListenerAdapter() {
72         @Override
73         public void writeTransactionFinished() {
74             if (isDisposed())
75                 dispose();
76             if (dirty)
77                 perform();
78         }
79         @Override
80         public void readTransactionFinished() {
81             if (isDisposed())
82                 dispose();
83             if (dirty)
84                 perform();
85         }
86     };
87
88     public ProfileObserver(Session session, Resource resource, IThreadWorkQueue thread, IDisposable canvas, G2DSceneGraph sceneGraph, Object diagram, Map<String, Object> constants, Runnable notification) {
89         //System.out.println(this + " NEW PROFILE OBSERVER: ");
90         this.session = session;
91         this.resource = resource;
92         this.thread = thread;
93         this.canvas = canvas;
94         this.diagram = diagram;
95         this.sceneGraph = sceneGraph;
96         this.constants.putAll(constants);
97         this.notification = notification;
98
99         attachSessionListener();
100
101         if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
102             System.out.println("ProfileObserver(" + this + ")");
103         
104         // Tell SceneGraph that this observer is not yet done applying its operations
105         if(sceneGraph != null)
106             sceneGraph.setPending(ProfileObserver.this);
107         
108     }
109
110     private void attachSessionListener() {
111         SessionEventSupport eventSupport = session.getService(SessionEventSupport.class);
112         eventSupport.addListener(transactionListener);
113     }
114
115     private void detachSessionListener() {
116         SessionEventSupport eventSupport = session.getService(SessionEventSupport.class);
117         eventSupport.removeListener(transactionListener);
118     }
119
120     public void dispose() {
121         synchronized (this) {
122             if (disposed)
123                 return;
124             disposed = true;
125         }
126
127         if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
128             System.out.println("ProfileObserver.dispose(" + this + ")");
129
130         if(activationListener != null) { 
131             activationListener.cleanup();
132             activationListener = null;
133         }
134
135         detachSessionListener();
136     }
137
138     @Override
139     public void update(Style style, Object item) {
140         if (DebugPolicy.DEBUG_PROFILE_OBSERVER_UPDATE)
141             System.out.println("Profile observer marked dirty.");
142         
143         updates.add(new Pair<>(style, item));
144         //updateAll = true;
145         dirty = true;
146     }
147
148     public void update() {
149         updateAll = true;
150         dirty = true;
151     }
152     
153     private void perform() {
154         dirty = false;
155         if (DebugPolicy.DEBUG_PROFILE_OBSERVER_UPDATE)
156             System.out.println("Profile observer detected a change.");
157         
158         session.asyncRequest(new RuntimeProfileActiveEntries(resource), new Procedure<Collection<ProfileEntry>>() {
159             @Override
160             public void execute(final Collection<ProfileEntry> entries) {
161
162                 if (isDisposed())
163                     return;
164
165                 ThreadUtils.asyncExec(thread, new Runnable() {
166                     
167 //                    private void init(INode node) {
168 //                        //ProfileVariables.init(node, ProfileObserver.this);
169 ////                        NodeUtil.forChildren(node, new NodeProcedure<Object>() {
170 ////                            @Override
171 ////                            public Object execute(INode node, String id) {
172 ////                                init(node);
173 ////                                return null;
174 ////                            }
175 ////                        }, null);
176 //                    }
177
178                     @Override
179                     public void run() {
180
181                         if (isDisposed())
182                             return;
183
184                         temporaryProperties.clear();
185
186 //                        init(sceneGraph);
187
188 //                        for(IElement e : diagram.getElements()) {
189 //                            Node node = NodeUtils.
190 //                            Variables.init(e, ProfileObserver.this);
191 //                        }
192
193                         
194                         long t0 = System.nanoTime();
195                         
196                         if (updateAll) {
197                             for(ProfileEntry e : entries) {
198                                 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
199                                     System.out.println("Apply profile entry: " + e);
200                                 e.apply(ProfileObserver.this);
201                             }
202                             updateAll = false;
203                             updates.clear();
204                         } else {
205                             List<Pair<Style, Object>> updatesCopy = new ArrayList<>(updates);
206                             updates.clear();
207                             for (Pair<Style, Object> update : updatesCopy) {
208                                 Style style = update.first;
209                                 Object item = update.second;
210                                 
211                                 style.apply2(item, ProfileObserver.this);
212                             }
213                         }
214
215
216                         long t1 = System.nanoTime();
217                         System.out.println((t1-t0) / 1e6);
218                         
219                         if(dirty) {
220                                 sceneGraph.setPending(ProfileObserver.this);
221 //                              System.err.println("setPending, dirty=true");
222                         }
223                         else {
224                                 sceneGraph.clearPending(ProfileObserver.this);
225 //                              System.err.println("clearPending, dirty=false");
226                         }
227                         
228                         notification.run();
229 //                        canvas.getContentContext().setDirty();
230                         
231                         // Something is underway, schedule update
232                         if(dirty) {
233                                 Simantics.async(new Runnable() {
234
235                                                                 @Override
236                                                                 public void run() {
237
238                                                             if (isDisposed()) return;
239                                                             
240                                                                         if(dirty) perform();
241                                                                         
242                                                                 }
243                                         
244                                 }, 100, TimeUnit.MILLISECONDS);
245                         }
246
247                     }
248                 });
249             }
250
251             @Override
252             public void exception(Throwable t) {
253                 Logger.defaultLogError(t);
254             }
255         });
256     }
257
258     @Override
259     public boolean isDisposed() {
260         return disposed || canvas.isDisposed();
261     }
262
263     @Override
264     public void exception(Throwable throwable) {
265         Logger.defaultLogError(throwable);
266     }
267
268     @SuppressWarnings("unchecked")
269     @Override
270     public <T> T getTemporaryProperty(INode element, String key) {
271         Map<String, Object> map = temporaryProperties.get(element);
272         T t = map == null ? null : (T) map.get(key);
273         //System.out.println(this + ".getTemporaryProperty(" + element + ", " + key + "): " + t);
274         return t;
275     }
276
277     @Override
278     public <T> void setTemporaryProperty(INode element, String key, T value) {
279         //System.out.println(this + ".setTemporaryProperty(" + element + ", " + key + ", " + value + ")");
280         Map<String, Object> map = temporaryProperties.get(element);
281         if (map == null) {
282             if (value == null)
283                 return;
284             map = new HashMap<String, Object>(8);
285             temporaryProperties.put(element, map);
286         }
287         if (value == null) {
288             map.remove(key);
289             if (map.isEmpty())
290                 temporaryProperties.remove(element);
291         } else
292             map.put(key, value);
293     }
294
295     @SuppressWarnings("unchecked")
296     @Override
297     public <T> T getProperty(INode element, String key) {
298         Map<String, Object> map = properties.get(element);
299         T t = map == null ? null : (T) map.get(key);
300         //System.out.println(this + ".getProperty(" + element + ", " + key + "): " + t);
301         return t;
302     }
303
304     @SuppressWarnings("unchecked")
305     @Override
306     public <T> T setProperty(INode element, String key, T value) {
307         T result = null;
308         //System.out.println(this + ".setProperty(" + element + ", " + key + ", " + value + ")");
309         Map<String, Object> map = properties.get(element);
310         if (map == null) {
311             if (value == null)
312                 return null;
313             map = new HashMap<String, Object>(8);
314             properties.put(element, map);
315         }
316         if (value == null) {
317             result = (T) map.remove(key);
318             if (map.isEmpty())
319                 properties.remove(element);
320         } else
321             result = (T) map.put(key, value);
322         return result;
323     }
324
325     @SuppressWarnings("unchecked")
326     @Override
327     public <T> T getConstant(String key) {
328         return (T) constants.get(key);
329     }
330
331     @Override
332     public String toString() {
333         return "ProfileObserver[" + resource.getResourceId() + "]";
334     }
335
336 //    @Override
337 //    public ICanvasContext getContext() {
338 //      return canvas;
339 //    }
340 //    
341 //    @Override
342 //    public IDiagram getDiagram() {
343 //      return diagram;
344 //    }
345
346     public void listen(AsyncRequestProcessor processor, IDisposable disposable) {
347         activationListener = new ProfileActivationListener(resource, this, disposable);
348         processor.asyncRequest(new RuntimeProfileActiveEntries(resource), activationListener);
349     }
350
351     @Override
352     public Resource getResource() {
353         return resource;
354     }
355
356     @Override
357     public G2DSceneGraph getSceneGraph() {
358         return sceneGraph;
359     }
360
361 }