1 /*******************************************************************************
2 * Copyright (c) 2010, 2013 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 * Semantum Oy - issue #4384
12 *******************************************************************************/
13 package org.simantics.diagram.runtime;
15 import java.util.concurrent.atomic.AtomicReference;
17 import org.eclipse.ui.IEditorInput;
18 import org.simantics.databoard.Bindings;
19 import org.simantics.db.AsyncReadGraph;
20 import org.simantics.db.RequestProcessor;
21 import org.simantics.db.Resource;
22 import org.simantics.db.Session;
23 import org.simantics.db.VirtualGraph;
24 import org.simantics.db.WriteGraph;
25 import org.simantics.db.common.procedure.adapter.ListenerSupport;
26 import org.simantics.db.common.request.WriteRequest;
27 import org.simantics.db.common.request.WriteResultRequest;
28 import org.simantics.db.exception.DatabaseException;
29 import org.simantics.db.layer0.util.RemoverUtil;
30 import org.simantics.db.layer0.variable.RVI;
31 import org.simantics.db.procedure.AsyncListener;
32 import org.simantics.diagram.stubs.DiagramResource;
33 import org.simantics.layer0.Layer0;
34 import org.simantics.operation.Layer0X;
35 import org.simantics.ui.workbench.IResourceEditorInput2;
36 import org.simantics.utils.ui.ErrorLogger;
39 * A helper class for managing the life-cycle of a diagram runtime realization.
42 * The diagram runtime resource is a virtual (transient) graph database resource
43 * that specifies the active runtime properties of the diagram as follows:
47 * |---[DIAGRAM.RuntimeDiagram.HasConfiguration]---> :DIAGRAM.Diagram (directed link, no inverse relation)
48 * |---[DIAGRAM.RuntimeDiagram.HasRuntimeProfile]---> :DIAGRAM.Profile (directed link, no inverse relation)
49 * |---[DIAGRAM.HasModelURI]------------ "Model URI" : L0.String
50 * |---[DIAGRAM.HasVariable]------------ "Variable URI" : L0.String
51 * `---[DIAGRAM.HasRVI]----------------- "RVI" : L0.String
54 * The runtime resource itself is not attached anywhere in the graph, it only
55 * contains a directed link back to its diagram.
58 * For example diagram profiles require the runtime diagram to have the
59 * DIAGRAM.HasVariable property. This in turn requires that the model has a
60 * proper {@link Layer0X#HasBaseRealization} relation in order to be resolved
61 * (see {@link RuntimeVariable}).
64 * To get started using this class, see
65 * {@link #track(Session, Resource, IEditorInput, ListenerSupport)} and
66 * {@link #create(Session, Resource, String, String)}.
69 * Instances of this class are not thread-safe.
71 * @author Tuukka Lehtonen
73 public class RuntimeDiagramManager {
75 private boolean disposed;
77 private Session session;
78 private IEditorInput editorInput;
79 private ListenerSupport support;
81 private AtomicReference<Resource> runtimeDiagram = new AtomicReference<Resource>();
84 * Constructs a new RuntimeDiagramManager, creates a new runtime diagram
85 * based on the specified editor input if it is an
86 * {@link IResourceEditorInput2} and starts tracking (listening) to changes
87 * in editor input which specifies the ModelURI and RVI needed for the
88 * runtime diagram. The tracking aspect comes to play in that editor inputs
89 * are basically allowed to change and therefore this manager tries to
90 * listen to changes in both the Model URI and RVI. If the input changes,
91 * the manager will automatically update the properties of the runtime
92 * diagram to match the input.
95 * Invoking this method is equal to calling:
98 * RuntimeDiagramManager manager = new RuntimeDiagramManager(session);
99 * manager.track(diagram, editorInput, listenerSupport);
105 * @param listenerSupport
107 * @throws DatabaseException
109 public static RuntimeDiagramManager track(
111 final Resource diagram,
112 IEditorInput editorInput,
113 ListenerSupport listenerSupport)
114 throws DatabaseException
116 RuntimeDiagramManager manager = new RuntimeDiagramManager(session);
117 manager.track(diagram, editorInput, listenerSupport);
122 * Just as {@link #track(Session, Resource, IEditorInput, ListenerSupport)}
123 * this method will construct a RuntimeDiagramManager and create a runtime
124 * diagram resource, but contrary to
125 * {@link #track(Session, Resource, IEditorInput, ListenerSupport)} it will
126 * not listen to changes nor update the runtime diagram properties.
129 * Invoking this method is equal to calling:
131 * RuntimeDiagramManager manager = new RuntimeDiagramManager(session);
132 * manager.createRuntimeDiagram(diagram, modelURI, RVI);
140 * @throws DatabaseException
142 * @see {@link #track(Session, Resource, IEditorInput, ListenerSupport)}
144 public static RuntimeDiagramManager create(
149 throws DatabaseException
151 RuntimeDiagramManager manager = new RuntimeDiagramManager(session);
152 manager.createRuntimeDiagram(diagram, modelURI, RVI);
156 public RuntimeDiagramManager(Session session) {
157 this.session = session;
160 public Resource getRuntimeDiagram() {
161 return runtimeDiagram.get();
164 public void dispose() {
165 synchronized (this) {
173 this.editorInput = null;
177 private void assertNotDisposed() {
179 throw new IllegalStateException(this + " is disposed");
182 private static IResourceEditorInput2 getResourceInput(Object input) {
183 if (input instanceof IResourceEditorInput2)
184 return (IResourceEditorInput2) input;
188 private IResourceEditorInput2 getResourceInput() {
189 return getResourceInput(editorInput);
193 * Does nothing if already tracking a diagram runtime resource.
197 * @param listenerSupport
198 * @return the current tracked diagram runtime resource
199 * @throws DatabaseException
201 * @see {@link #track(Session, Resource, IEditorInput, ListenerSupport)}
203 public Resource track(final Resource diagram, IEditorInput editorInput, ListenerSupport listenerSupport) throws DatabaseException {
204 Resource runtime = runtimeDiagram.get();
208 if (editorInput == null)
209 throw new NullPointerException("null editorInput");
210 if (listenerSupport == null)
211 throw new NullPointerException("null listenerSupport");
213 final IResourceEditorInput2 input = getResourceInput(editorInput);
217 this.editorInput = editorInput;
218 this.support = listenerSupport;
220 runtime = session.syncRequest(new WriteResultRequest<Resource>(session.getService(VirtualGraph.class)) {
222 public Resource perform(WriteGraph graph) throws DatabaseException {
223 RuntimeDiagramDesc variable = graph.syncRequest(new RuntimeVariableForInput(input));
224 if (variable == null)
227 final Resource runtime = createRuntimeDiagram(graph, diagram, variable);
228 listenRequest(graph, diagram);
233 runtimeDiagram.set(runtime);
242 * @throws DatabaseException
244 * @see {@link #create(Session, Resource, String, String)
246 public Resource createRuntimeDiagram(final Resource diagram, final String modelURI, final String RVI) throws DatabaseException {
247 Resource runtime = runtimeDiagram.get();
251 runtime = session.syncRequest(new WriteResultRequest<Resource>(session.getService(VirtualGraph.class)) {
253 public Resource perform(WriteGraph graph) throws DatabaseException {
254 Resource model = graph.getPossibleResource(modelURI);
255 return createRuntimeDiagram(graph, diagram, model, RVI);
259 runtimeDiagram.set(runtime);
269 * @throws DatabaseException
271 public Resource createRuntimeDiagram(WriteGraph graph, final Resource diagram, final Resource model, final String rvis) throws DatabaseException {
272 RVI rvi = rvis != null ? RVI.fromResourceFormat(graph, rvis) : null;
273 RuntimeDiagramDesc desc = graph.syncRequest(new RuntimeVariable(model, rvi, diagram));
276 return createRuntimeDiagram(graph, diagram, desc);
279 private void listenRequest(RequestProcessor processor, final Resource diagram) throws DatabaseException {
280 processor.syncRequest(new RuntimeVariableForInput(getResourceInput()), new AsyncListener<RuntimeDiagramDesc>() {
283 public void exception(AsyncReadGraph graph, Throwable throwable) {
284 ListenerSupport s = support;
286 s.exception(throwable);
290 public void execute(AsyncReadGraph graph, final RuntimeDiagramDesc desc) {
294 Session session = graph.getSession();
295 session.asyncRequest(new WriteRequest(session.getService(VirtualGraph.class)) {
297 public void perform(WriteGraph graph) throws DatabaseException {
298 Resource runtime = getRuntimeDiagram();
300 writeConfig(graph, runtime, diagram, desc);
303 ListenerSupport s = support;
304 if (e != null && s != null)
310 public boolean isDisposed() {
311 if(disposed) return true;
312 else return support != null && support.isDisposed();
317 private Resource createRuntimeDiagram(WriteGraph graph, Resource diagram, RuntimeDiagramDesc desc) throws DatabaseException {
319 Layer0 L0 = Layer0.getInstance(graph);
320 final DiagramResource DIA = DiagramResource.getInstance(graph);
322 // Create the new runtime diagram instance!
323 final Resource runtime = graph.newResource();
324 graph.claim(runtime, L0.InstanceOf, null, DIA.RuntimeDiagram);
325 graph.claim(runtime, DIA.RuntimeDiagram_HasConfiguration, null, diagram);
327 writeConfig(graph, runtime, diagram, desc);
332 private void writeConfig(WriteGraph graph, final Resource runtime, final Resource diagram, RuntimeDiagramDesc desc) throws DatabaseException {
333 final DiagramResource DIA = DiagramResource.getInstance(graph);
334 if (desc.getVariableURI() != null)
335 graph.claimLiteral(runtime, DIA.RuntimeDiagram_HasVariable, desc.getVariableURI(), Bindings.STRING);
336 if (desc.getRVI() != null)
337 graph.claimLiteral(runtime, DIA.RuntimeDiagram_HasRVI, desc.getRVI(), Bindings.STRING);
338 if (desc.getModelURI() != null)
339 graph.claimLiteral(runtime, DIA.RuntimeDiagram_HasModelURI, desc.getModelURI(), Bindings.STRING);
340 if (desc.getActiveProfileURI() != null) {
341 Resource activeProfile = graph.getPossibleResource(desc.getActiveProfileURI());
342 if (activeProfile != null) {
343 graph.deny(runtime, DIA.RuntimeDiagram_HasRuntimeProfile);
344 graph.claim(runtime, DIA.RuntimeDiagram_HasRuntimeProfile, null, activeProfile);
349 private void destroy() {
350 final Resource rd = runtimeDiagram.getAndSet(null);
353 session.syncRequest(new WriteRequest(session.getService(VirtualGraph.class)) {
355 public void perform(WriteGraph graph) throws DatabaseException {
356 RemoverUtil.remove(graph, rd);
359 } catch (DatabaseException e) {
360 ListenerSupport s = support;
364 ErrorLogger.defaultLogError(e);