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;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * Simple local ExperimentManager implementation
46 public class ExperimentManager implements IExperimentManager {
48 private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentManager.class);
50 CopyOnWriteArrayList<IExperimentManagerListener> listeners = new CopyOnWriteArrayList<IExperimentManagerListener>();
51 ListenerList<IExperiment> experiments = new ListenerList<IExperiment>(IExperiment.class);
52 IExperiment activeExperiment;
53 AtomicBoolean isDisposed = new AtomicBoolean(false);
55 public ExperimentManager() {
56 BundleContext context = Activator.getDefault().getBundle().getBundleContext();
57 ServiceReference<?> ref = context.getServiceReference(WorkbenchShutdownService.class.getName());
59 WorkbenchShutdownService shutdown = (WorkbenchShutdownService) context.getService(ref);
60 shutdown.registerShutdownHook(new Runnable() {
63 IRunnableWithProgress runnable = new IRunnableWithProgress() {
65 public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
67 ExperimentManager.this.dispose(monitor);
74 if (PlatformUI.isWorkbenchRunning()) {
75 IProgressService progress = (IProgressService) PlatformUI.getWorkbench().getService(IProgressService.class);
76 progress.run(true, false, runnable);
80 } catch (InvocationTargetException e) {
81 Activator.logError("Experiment manager shutdown failed, see exception for details.", e.getCause());
82 } catch (InterruptedException e) {
83 Activator.logError("Experiment manager shutdown was interrupted, see exception for details.", e);
87 context.ungetService(ref);
91 class ManagingExperimentListener implements IExperimentListener {
93 IExperiment experiment;
96 public ManagingExperimentListener(IExperiment experiment, boolean setActive) {
97 this.experiment = experiment;
98 this.setActive = setActive;
102 public void stateChanged(ExperimentState state) {
103 if(state==ExperimentState.RUNNING || state==ExperimentState.STOPPED) {
104 if(setActive && activeExperiment != experiment)
105 setActiveExperiment(experiment);
107 else if(state==ExperimentState.DISPOSED) {
108 removeActiveExperiment(experiment);
109 experiments.remove(experiment);
110 experiment.removeListener(this);
116 protected void manageExperiment(IExperiment experiment, boolean setActive) {
117 experiments.add(experiment);
118 experiment.addListener(new ManagingExperimentListener(experiment, setActive));
122 public void startExperiment(final Resource experimentResource,
123 final IExperimentActivationListener listener, final boolean setActive) {
124 // ENFORCE SINGLE_EXPERIMENT MODE POLICY:
125 // Shutdown active experiment before loading new experiment.
126 // IMPORTANT: Perform shutdown outside of a graph transaction to allow
127 // shutdown to perform graph requests at will.
128 synchronized (ExperimentManager.this) {
129 ExperimentManagerMode mode = getMode();
130 // Close previous active experiment before loading new
131 if (mode == ExperimentManagerMode.SINGLE_EXPERIMENT) {
132 if (activeExperiment != null && setActive) {
133 // TODO: provide a proper progress monitor for shutdown!
134 activeExperiment.shutdown(null);
139 Simantics.getSession().asyncRequest(new ReadRequest() {
141 public void run(ReadGraph g) throws DatabaseException {
143 LifecycleSupport ls = g.getService(LifecycleSupport.class);
144 if(ls.isClosing() || ls.isClosed()) {
148 Layer0 L0 = Layer0.getInstance(g);
151 g.getSingleObject(experimentResource, L0.PartOf),
154 final IExperimentActivationListener proxy = new ProxyExperimentActivationListener(listener) {
156 public void onExperimentActivated(IExperiment experiment) {
157 if (experiment != null)
158 manageExperiment(experiment, setActive);
159 super.onExperimentActivated(experiment);
162 public void onFailure(Throwable e) {
167 // Ignore return value, the experiment is
168 // provided to proxy.onExperimentActivated.
169 model.loadExperiment(g, experimentResource, proxy);
171 }, new ProcedureAdapter<Object>() {
173 public void exception(Throwable t) {
174 listener.onFailure(t);
179 synchronized void setActiveExperiment(IExperiment experiment) {
180 // Multiple experiments may need to run concurrently - so don't shutdown
181 // if not explicitly requested to do so.
182 if (getMode() == ExperimentManagerMode.SINGLE_EXPERIMENT) {
183 if (activeExperiment != null) {
184 activeExperiment.shutdown(null);
185 for (IExperimentManagerListener listener : listeners)
186 listener.activeExperimentUnloaded();
189 activeExperiment = experiment;
190 for(IExperimentManagerListener listener : listeners)
191 listener.activeExperimentLoaded(experiment);
194 synchronized private void removeActiveExperiment(IExperiment experiment) {
195 if(activeExperiment == experiment) {
196 activeExperiment = null;
197 for(IExperimentManagerListener listener : listeners)
198 listener.activeExperimentUnloaded();
203 synchronized public void addListener(IExperimentManagerListener listener) {
204 listeners.add(listener);
205 if(activeExperiment != null)
206 listener.activeExperimentLoaded(activeExperiment);
210 synchronized public void removeListener(IExperimentManagerListener listener) {
211 listeners.remove(listener);
214 public void dispose(IProgressMonitor monitor) {
215 if(isDisposed.compareAndSet(false, true)) {
216 if(activeExperiment != null)
217 activeExperiment.shutdown(monitor);
218 activeExperiment = null;
220 for(IExperimentManagerListener listener : listeners)
221 listener.managerDisposed();
223 if (!listeners.isEmpty()) {
224 // Some clients are leaking listeners. Shame on them.
225 LOGGER.warn("ExperimentManager still contains the following listeners after disposal:");
226 for (IExperimentManagerListener listener : listeners)
227 LOGGER.warn("\t" + listener);
233 public IExperiment getActiveExperiment() {
234 return activeExperiment;
238 public IExperiment getExperiment(final String identifier) {
239 if(identifier == null) return null;
240 for(IExperiment experiment : experiments.getListeners()) {
241 if(experiment != null && identifier.equals(experiment.getIdentifier())) {
249 public IExperiment[] getExperiments() {
250 return experiments.getListeners();
253 private ExperimentManagerMode getMode() {
254 ExperimentManagerMode mode = ExperimentManagerMode.MULTI_EXPERIMENT;
255 IProject project = org.simantics.Simantics.peekProject();
258 mode = project.getHint(ExperimentManagerKeys.EXPERIMENT_MANAGER_MODE);
259 return mode != null ? mode : ExperimentManagerMode.MULTI_EXPERIMENT;