1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.scenegraph.profile.common;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.List;
19 import java.util.concurrent.TimeUnit;
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;
42 public class ProfileObserver implements EvaluationContext {
44 private final Session session;
47 * Runtime diagram resource.
49 private final Resource resource;
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;
58 private volatile boolean dirty = true;
59 private volatile boolean disposed = false;
61 private List<Pair<Style, Object>> updates = new ArrayList<>();
62 private boolean updateAll;
64 private ProfileActivationListener activationListener;
66 private Map<String, Object> constants = new HashMap<String, Object>();
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>>();
71 private final SessionEventListenerAdapter transactionListener = new SessionEventListenerAdapter() {
73 public void writeTransactionFinished() {
80 public void readTransactionFinished() {
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;
94 this.diagram = diagram;
95 this.sceneGraph = sceneGraph;
96 this.constants.putAll(constants);
97 this.notification = notification;
99 attachSessionListener();
101 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
102 System.out.println("ProfileObserver(" + this + ")");
104 // Tell SceneGraph that this observer is not yet done applying its operations
105 if(sceneGraph != null)
106 sceneGraph.setPending(ProfileObserver.this);
110 private void attachSessionListener() {
111 SessionEventSupport eventSupport = session.getService(SessionEventSupport.class);
112 eventSupport.addListener(transactionListener);
115 private void detachSessionListener() {
116 SessionEventSupport eventSupport = session.getService(SessionEventSupport.class);
117 eventSupport.removeListener(transactionListener);
120 public void dispose() {
121 synchronized (this) {
127 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
128 System.out.println("ProfileObserver.dispose(" + this + ")");
130 if(activationListener != null) {
131 activationListener.cleanup();
132 activationListener = null;
135 detachSessionListener();
139 public void update(Style style, Object item) {
140 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_UPDATE)
141 System.out.println("Profile observer marked dirty.");
143 updates.add(new Pair<>(style, item));
148 public void update() {
153 private void perform() {
155 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_UPDATE)
156 System.out.println("Profile observer detected a change.");
158 session.asyncRequest(new RuntimeProfileActiveEntries(resource), new Procedure<Collection<ProfileEntry>>() {
160 public void execute(final Collection<ProfileEntry> entries) {
165 ThreadUtils.asyncExec(thread, new Runnable() {
167 // private void init(INode node) {
168 // //ProfileVariables.init(node, ProfileObserver.this);
169 //// NodeUtil.forChildren(node, new NodeProcedure<Object>() {
171 //// public Object execute(INode node, String id) {
184 temporaryProperties.clear();
188 // for(IElement e : diagram.getElements()) {
189 // Node node = NodeUtils.
190 // Variables.init(e, ProfileObserver.this);
194 long t0 = System.nanoTime();
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);
205 List<Pair<Style, Object>> updatesCopy = new ArrayList<>(updates);
207 for (Pair<Style, Object> update : updatesCopy) {
208 Style style = update.first;
209 Object item = update.second;
211 style.apply2(item, ProfileObserver.this);
216 long t1 = System.nanoTime();
217 System.out.println((t1-t0) / 1e6);
220 sceneGraph.setPending(ProfileObserver.this);
221 // System.err.println("setPending, dirty=true");
224 sceneGraph.clearPending(ProfileObserver.this);
225 // System.err.println("clearPending, dirty=false");
229 // canvas.getContentContext().setDirty();
231 // Something is underway, schedule update
233 Simantics.async(new Runnable() {
238 if (isDisposed()) return;
244 }, 100, TimeUnit.MILLISECONDS);
252 public void exception(Throwable t) {
253 Logger.defaultLogError(t);
259 public boolean isDisposed() {
260 return disposed || canvas.isDisposed();
264 public void exception(Throwable throwable) {
265 Logger.defaultLogError(throwable);
268 @SuppressWarnings("unchecked")
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);
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);
284 map = new HashMap<String, Object>(8);
285 temporaryProperties.put(element, map);
290 temporaryProperties.remove(element);
295 @SuppressWarnings("unchecked")
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);
304 @SuppressWarnings("unchecked")
306 public <T> T setProperty(INode element, String key, T value) {
308 //System.out.println(this + ".setProperty(" + element + ", " + key + ", " + value + ")");
309 Map<String, Object> map = properties.get(element);
313 map = new HashMap<String, Object>(8);
314 properties.put(element, map);
317 result = (T) map.remove(key);
319 properties.remove(element);
321 result = (T) map.put(key, value);
325 @SuppressWarnings("unchecked")
327 public <T> T getConstant(String key) {
328 return (T) constants.get(key);
332 public String toString() {
333 return "ProfileObserver[" + resource.getResourceId() + "]";
337 // public ICanvasContext getContext() {
342 // public IDiagram getDiagram() {
346 public void listen(AsyncRequestProcessor processor, IDisposable disposable) {
347 activationListener = new ProfileActivationListener(resource, this, disposable);
348 processor.asyncRequest(new RuntimeProfileActiveEntries(resource), activationListener);
352 public Resource getResource() {
357 public G2DSceneGraph getSceneGraph() {