1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.simulation.project;
\r
14 import java.lang.reflect.InvocationTargetException;
\r
15 import java.util.concurrent.CopyOnWriteArrayList;
\r
16 import java.util.concurrent.atomic.AtomicBoolean;
\r
18 import org.eclipse.core.runtime.IProgressMonitor;
\r
19 import org.eclipse.jface.operation.IRunnableWithProgress;
\r
20 import org.eclipse.ui.PlatformUI;
\r
21 import org.eclipse.ui.progress.IProgressService;
\r
22 import org.osgi.framework.BundleContext;
\r
23 import org.osgi.framework.ServiceReference;
\r
24 import org.simantics.Simantics;
\r
25 import org.simantics.db.ReadGraph;
\r
26 import org.simantics.db.Resource;
\r
27 import org.simantics.db.common.procedure.adapter.ProcedureAdapter;
\r
28 import org.simantics.db.common.request.ReadRequest;
\r
29 import org.simantics.db.exception.DatabaseException;
\r
30 import org.simantics.db.service.LifecycleSupport;
\r
31 import org.simantics.layer0.Layer0;
\r
32 import org.simantics.project.IProject;
\r
33 import org.simantics.simulation.Activator;
\r
34 import org.simantics.simulation.experiment.ExperimentState;
\r
35 import org.simantics.simulation.experiment.IExperiment;
\r
36 import org.simantics.simulation.experiment.IExperimentListener;
\r
37 import org.simantics.simulation.model.IModel;
\r
38 import org.simantics.ui.workbench.WorkbenchShutdownService;
\r
39 import org.simantics.utils.datastructures.ListenerList;
\r
42 * Simple local ExperimentManager implementation
\r
44 public class ExperimentManager implements IExperimentManager {
\r
46 CopyOnWriteArrayList<IExperimentManagerListener> listeners = new CopyOnWriteArrayList<IExperimentManagerListener>();
\r
47 ListenerList<IExperiment> experiments = new ListenerList<IExperiment>(IExperiment.class);
\r
48 IExperiment activeExperiment;
\r
49 AtomicBoolean isDisposed = new AtomicBoolean(false);
\r
51 public ExperimentManager() {
\r
52 BundleContext context = Activator.getDefault().getBundle().getBundleContext();
\r
53 ServiceReference<?> ref = context.getServiceReference(WorkbenchShutdownService.class.getName());
\r
55 WorkbenchShutdownService shutdown = (WorkbenchShutdownService) context.getService(ref);
\r
56 shutdown.registerShutdownHook(new Runnable() {
\r
59 IRunnableWithProgress runnable = new IRunnableWithProgress() {
\r
61 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
\r
63 ExperimentManager.this.dispose(monitor);
\r
70 if (PlatformUI.isWorkbenchRunning()) {
\r
71 IProgressService progress = (IProgressService) PlatformUI.getWorkbench().getService(IProgressService.class);
\r
72 progress.run(true, false, runnable);
\r
76 } catch (InvocationTargetException e) {
\r
77 Activator.logError("Experiment manager shutdown failed, see exception for details.", e.getCause());
\r
78 } catch (InterruptedException e) {
\r
79 Activator.logError("Experiment manager shutdown was interrupted, see exception for details.", e);
\r
83 context.ungetService(ref);
\r
87 class ManagingExperimentListener implements IExperimentListener {
\r
89 IExperiment experiment;
\r
92 public ManagingExperimentListener(IExperiment experiment, boolean setActive) {
\r
93 this.experiment = experiment;
\r
94 this.setActive = setActive;
\r
98 public void stateChanged(ExperimentState state) {
\r
99 if(state==ExperimentState.RUNNING || state==ExperimentState.STOPPED) {
\r
100 if(setActive && activeExperiment != experiment)
\r
101 setActiveExperiment(experiment);
\r
103 else if(state==ExperimentState.DISPOSED) {
\r
104 removeActiveExperiment(experiment);
\r
105 experiments.remove(experiment);
\r
106 experiment.removeListener(this);
\r
112 protected void manageExperiment(IExperiment experiment, boolean setActive) {
\r
113 experiments.add(experiment);
\r
114 experiment.addListener(new ManagingExperimentListener(experiment, setActive));
\r
118 public void startExperiment(final Resource experimentResource,
\r
119 final IExperimentActivationListener listener, final boolean setActive) {
\r
120 // ENFORCE SINGLE_EXPERIMENT MODE POLICY:
\r
121 // Shutdown active experiment before loading new experiment.
\r
122 // IMPORTANT: Perform shutdown outside of a graph transaction to allow
\r
123 // shutdown to perform graph requests at will.
\r
124 synchronized (ExperimentManager.this) {
\r
125 ExperimentManagerMode mode = getMode();
\r
126 // Close previous active experiment before loading new
\r
127 if (mode == ExperimentManagerMode.SINGLE_EXPERIMENT) {
\r
128 if (activeExperiment != null && setActive) {
\r
129 // TODO: provide a proper progress monitor for shutdown!
\r
130 activeExperiment.shutdown(null);
\r
135 Simantics.getSession().asyncRequest(new ReadRequest() {
\r
137 public void run(ReadGraph g) throws DatabaseException {
\r
139 LifecycleSupport ls = g.getService(LifecycleSupport.class);
\r
140 if(ls.isClosing() || ls.isClosed()) {
\r
144 Layer0 L0 = Layer0.getInstance(g);
\r
145 final IModel model =
\r
147 g.getSingleObject(experimentResource, L0.PartOf),
\r
150 final IExperimentActivationListener proxy = new ProxyExperimentActivationListener(listener) {
\r
152 public void onExperimentActivated(IExperiment experiment) {
\r
153 if (experiment != null)
\r
154 manageExperiment(experiment, setActive);
\r
155 super.onExperimentActivated(experiment);
\r
158 public void onFailure(Throwable e) {
\r
159 super.onFailure(e);
\r
163 // Ignore return value, the experiment is
\r
164 // provided to proxy.onExperimentActivated.
\r
165 model.loadExperiment(g, experimentResource, proxy);
\r
167 }, new ProcedureAdapter<Object>() {
\r
169 public void exception(Throwable t) {
\r
170 listener.onFailure(t);
\r
175 synchronized void setActiveExperiment(IExperiment experiment) {
\r
176 // Multiple experiments may need to run concurrently - so don't shutdown
\r
177 // if not explicitly requested to do so.
\r
178 if (getMode() == ExperimentManagerMode.SINGLE_EXPERIMENT) {
\r
179 if (activeExperiment != null) {
\r
180 activeExperiment.shutdown(null);
\r
181 for (IExperimentManagerListener listener : listeners)
\r
182 listener.activeExperimentUnloaded();
\r
185 activeExperiment = experiment;
\r
186 for(IExperimentManagerListener listener : listeners)
\r
187 listener.activeExperimentLoaded(experiment);
\r
190 synchronized private void removeActiveExperiment(IExperiment experiment) {
\r
191 if(activeExperiment == experiment) {
\r
192 activeExperiment = null;
\r
193 for(IExperimentManagerListener listener : listeners)
\r
194 listener.activeExperimentUnloaded();
\r
199 synchronized public void addListener(IExperimentManagerListener listener) {
\r
200 listeners.add(listener);
\r
201 if(activeExperiment != null)
\r
202 listener.activeExperimentLoaded(activeExperiment);
\r
206 synchronized public void removeListener(IExperimentManagerListener listener) {
\r
207 listeners.remove(listener);
\r
210 public void dispose(IProgressMonitor monitor) {
\r
211 if(isDisposed.compareAndSet(false, true)) {
\r
212 if(activeExperiment != null)
\r
213 activeExperiment.shutdown(monitor);
\r
214 activeExperiment = null;
\r
216 for(IExperimentManagerListener listener : listeners)
\r
217 listener.managerDisposed();
\r
219 if (!listeners.isEmpty()) {
\r
220 // Some clients are leaking listeners. Shame on them.
\r
221 System.err.println("ExperimentManager still contains the following listeners after disposal:");
\r
222 for (IExperimentManagerListener listener : listeners)
\r
223 System.err.println("\t" + listener);
\r
229 public IExperiment getActiveExperiment() {
\r
230 return activeExperiment;
\r
234 public IExperiment getExperiment(final String identifier) {
\r
235 if(identifier == null) return null;
\r
236 for(IExperiment experiment : experiments.getListeners()) {
\r
237 if(experiment != null && identifier.equals(experiment.getIdentifier())) {
\r
245 public IExperiment[] getExperiments() {
\r
246 return experiments.getListeners();
\r
249 private ExperimentManagerMode getMode() {
\r
250 ExperimentManagerMode mode = ExperimentManagerMode.MULTI_EXPERIMENT;
\r
251 IProject project = org.simantics.Simantics.peekProject();
\r
252 if (project == null)
\r
254 mode = project.getHint(ExperimentManagerKeys.EXPERIMENT_MANAGER_MODE);
\r
255 return mode != null ? mode : ExperimentManagerMode.MULTI_EXPERIMENT;
\r