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