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.procedure.Procedure;
27 import org.simantics.db.service.QueryControl;
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 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
44 public class ProfileObserver implements EvaluationContext {
46 private static final Logger LOGGER = LoggerFactory.getLogger(ProfileObserver.class);
48 private final Session session;
51 * Runtime diagram resource.
53 private final Resource resource;
55 private final IDisposable canvas;
56 private final IThreadWorkQueue thread;
57 @SuppressWarnings("unused")
58 private final Object diagram;
59 private final Runnable notification;
60 private final G2DSceneGraph sceneGraph;
62 private volatile boolean dirty = true;
63 private volatile boolean disposed = false;
65 private boolean needSynchronizedUpdates = false;
66 private List<Pair<Style, Object>> updates = new ArrayList<>();
67 private boolean updateAll;
69 private ProfileActivationListener activationListener;
71 private Map<String, Object> constants = new HashMap<String, Object>();
73 private Map<INode, Map<String, Object>> temporaryProperties = new HashMap<INode, Map<String, Object>>();
74 private Map<INode, Map<String, Object>> properties = new HashMap<INode, Map<String, Object>>();
76 private final SessionEventListenerAdapter transactionListener = new SessionEventListenerAdapter() {
78 public void writeTransactionFinished() {
85 public void readTransactionFinished() {
93 public ProfileObserver(Session session, Resource resource, IThreadWorkQueue thread, IDisposable canvas, G2DSceneGraph sceneGraph, Object diagram, Map<String, Object> constants, Runnable notification) {
94 //System.out.println(this + " NEW PROFILE OBSERVER: ");
95 this.session = session;
96 this.resource = resource;
99 this.diagram = diagram;
100 this.sceneGraph = sceneGraph;
101 this.constants.putAll(constants);
102 this.notification = notification;
103 this.needSynchronizedUpdates = session.getService(QueryControl.class).getAmountOfQueryThreads() > 1;
105 attachSessionListener();
107 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
108 System.out.println("ProfileObserver(" + this + ")");
110 // Tell SceneGraph that this observer is not yet done applying its operations
111 if(sceneGraph != null)
112 sceneGraph.setPending(ProfileObserver.this);
116 private void attachSessionListener() {
117 SessionEventSupport eventSupport = session.getService(SessionEventSupport.class);
118 eventSupport.addListener(transactionListener);
121 private void detachSessionListener() {
122 SessionEventSupport eventSupport = session.getService(SessionEventSupport.class);
123 eventSupport.removeListener(transactionListener);
126 public void dispose() {
127 synchronized (this) {
133 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
134 System.out.println("ProfileObserver.dispose(" + this + ")");
136 if(activationListener != null) {
137 activationListener.cleanup();
138 activationListener = null;
141 detachSessionListener();
145 public void update(Style style, Object item) {
146 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_UPDATE)
147 System.out.println("Profile observer marked dirty.");
149 if (needSynchronizedUpdates) {
150 synchronized (updates) {
151 updates.add(Pair.make(style, item));
154 updates.add(Pair.make(style, item));
160 public void update() {
165 private void perform() {
167 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_UPDATE)
168 System.out.println("Profile observer detected a change.");
170 session.asyncRequest(new RuntimeProfileActiveEntries(resource), new Procedure<Collection<ProfileEntry>>() {
172 public void execute(final Collection<ProfileEntry> entries) {
177 ThreadUtils.asyncExec(thread, new Runnable() {
183 temporaryProperties.clear();
185 long t0 = DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM ? System.nanoTime() : 0L;
188 for(ProfileEntry e : entries) {
189 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM)
190 System.out.println("Apply profile entry: " + e);
191 e.apply(ProfileObserver.this);
194 if (needSynchronizedUpdates) {
195 synchronized (updates) {
202 List<Pair<Style, Object>> updatesCopy;
203 if (needSynchronizedUpdates) {
204 synchronized (updates) {
205 updatesCopy = new ArrayList<>(updates);
209 updatesCopy = new ArrayList<>(updates);
213 for (Pair<Style, Object> update : updatesCopy) {
214 Style style = update.first;
215 Object item = update.second;
217 style.apply2(item, ProfileObserver.this);
221 if (DebugPolicy.DEBUG_PROFILE_OBSERVER_PERFORM) {
222 long t1 = System.nanoTime();
223 System.out.println((t1-t0) / 1e6);
227 sceneGraph.setPending(ProfileObserver.this);
228 // System.err.println("setPending, dirty=true");
231 sceneGraph.clearPending(ProfileObserver.this);
232 // System.err.println("clearPending, dirty=false");
236 // canvas.getContentContext().setDirty();
238 // Something is underway, schedule update
240 Simantics.async(() -> {
241 if (isDisposed()) return;
242 if (dirty) perform();
243 }, 100, TimeUnit.MILLISECONDS);
250 public void exception(Throwable t) {
251 LOGGER.error("RuntimeProfileActiveEntries request failed", t);
257 public boolean isDisposed() {
258 return disposed || canvas.isDisposed();
262 public void exception(Throwable throwable) {
263 LOGGER.error("Exception occurred during diagram profile observation", throwable);
266 @SuppressWarnings("unchecked")
268 public <T> T getTemporaryProperty(INode element, String key) {
269 Map<String, Object> map = temporaryProperties.get(element);
270 T t = map == null ? null : (T) map.get(key);
271 //System.out.println(this + ".getTemporaryProperty(" + element + ", " + key + "): " + t);
276 public <T> void setTemporaryProperty(INode element, String key, T value) {
277 //System.out.println(this + ".setTemporaryProperty(" + element + ", " + key + ", " + value + ")");
278 Map<String, Object> map = temporaryProperties.get(element);
282 map = new HashMap<String, Object>(8);
283 temporaryProperties.put(element, map);
288 temporaryProperties.remove(element);
293 @SuppressWarnings("unchecked")
295 public <T> T getProperty(INode element, String key) {
296 Map<String, Object> map = properties.get(element);
297 T t = map == null ? null : (T) map.get(key);
298 //System.out.println(this + ".getProperty(" + element + ", " + key + "): " + t);
302 @SuppressWarnings("unchecked")
304 public <T> T setProperty(INode element, String key, T value) {
306 //System.out.println(this + ".setProperty(" + element + ", " + key + ", " + value + ")");
307 Map<String, Object> map = properties.get(element);
311 map = new HashMap<String, Object>(8);
312 properties.put(element, map);
315 result = (T) map.remove(key);
317 properties.remove(element);
319 result = (T) map.put(key, value);
323 @SuppressWarnings("unchecked")
325 public <T> T getConstant(String key) {
326 return (T) constants.get(key);
330 public String toString() {
331 return "ProfileObserver[" + resource.getResourceId() + "]";
335 // public ICanvasContext getContext() {
340 // public IDiagram getDiagram() {
344 public void listen(AsyncRequestProcessor processor, IDisposable disposable) {
345 activationListener = new ProfileActivationListener(resource, this, disposable);
346 processor.asyncRequest(new RuntimeProfileActiveEntries(resource), activationListener);
350 public Resource getResource() {
355 public G2DSceneGraph getSceneGraph() {