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