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(Pair.make(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() {
171 temporaryProperties.clear();
173 long t0 = DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM ? System.nanoTime() : 0L;
176 for(ProfileEntry e : entries) {
177 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
178 System.out.println("Apply profile entry: " + e);
179 e.apply(ProfileObserver.this);
184 List<Pair<Style, Object>> updatesCopy = new ArrayList<>(updates);
186 for (Pair<Style, Object> update : updatesCopy) {
187 Style style = update.first;
188 Object item = update.second;
190 style.apply2(item, ProfileObserver.this);
194 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM) {
195 long t1 = System.nanoTime();
196 System.out.println((t1-t0) / 1e6);
200 sceneGraph.setPending(ProfileObserver.this);
201 // System.err.println("setPending, dirty=true");
204 sceneGraph.clearPending(ProfileObserver.this);
205 // System.err.println("clearPending, dirty=false");
209 // canvas.getContentContext().setDirty();
211 // Something is underway, schedule update
213 Simantics.async(() -> {
214 if (isDisposed()) return;
215 if (dirty) perform();
216 }, 100, TimeUnit.MILLISECONDS);
223 public void exception(Throwable t) {
224 Logger.defaultLogError(t);
230 public boolean isDisposed() {
231 return disposed || canvas.isDisposed();
235 public void exception(Throwable throwable) {
236 Logger.defaultLogError(throwable);
239 @SuppressWarnings("unchecked")
241 public <T> T getTemporaryProperty(INode element, String key) {
242 Map<String, Object> map = temporaryProperties.get(element);
243 T t = map == null ? null : (T) map.get(key);
244 //System.out.println(this + ".getTemporaryProperty(" + element + ", " + key + "): " + t);
249 public <T> void setTemporaryProperty(INode element, String key, T value) {
250 //System.out.println(this + ".setTemporaryProperty(" + element + ", " + key + ", " + value + ")");
251 Map<String, Object> map = temporaryProperties.get(element);
255 map = new HashMap<String, Object>(8);
256 temporaryProperties.put(element, map);
261 temporaryProperties.remove(element);
266 @SuppressWarnings("unchecked")
268 public <T> T getProperty(INode element, String key) {
269 Map<String, Object> map = properties.get(element);
270 T t = map == null ? null : (T) map.get(key);
271 //System.out.println(this + ".getProperty(" + element + ", " + key + "): " + t);
275 @SuppressWarnings("unchecked")
277 public <T> T setProperty(INode element, String key, T value) {
279 //System.out.println(this + ".setProperty(" + element + ", " + key + ", " + value + ")");
280 Map<String, Object> map = properties.get(element);
284 map = new HashMap<String, Object>(8);
285 properties.put(element, map);
288 result = (T) map.remove(key);
290 properties.remove(element);
292 result = (T) map.put(key, value);
296 @SuppressWarnings("unchecked")
298 public <T> T getConstant(String key) {
299 return (T) constants.get(key);
303 public String toString() {
304 return "ProfileObserver[" + resource.getResourceId() + "]";
308 // public ICanvasContext getContext() {
313 // public IDiagram getDiagram() {
317 public void listen(AsyncRequestProcessor processor, IDisposable disposable) {
318 activationListener = new ProfileActivationListener(resource, this, disposable);
319 processor.asyncRequest(new RuntimeProfileActiveEntries(resource), activationListener);
323 public Resource getResource() {
328 public G2DSceneGraph getSceneGraph() {