-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.simulation.project;\r
-\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.util.concurrent.CopyOnWriteArrayList;\r
-import java.util.concurrent.atomic.AtomicBoolean;\r
-\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.jface.operation.IRunnableWithProgress;\r
-import org.eclipse.ui.PlatformUI;\r
-import org.eclipse.ui.progress.IProgressService;\r
-import org.osgi.framework.BundleContext;\r
-import org.osgi.framework.ServiceReference;\r
-import org.simantics.Simantics;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.common.procedure.adapter.ProcedureAdapter;\r
-import org.simantics.db.common.request.ReadRequest;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.service.LifecycleSupport;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.project.IProject;\r
-import org.simantics.simulation.Activator;\r
-import org.simantics.simulation.experiment.ExperimentState;\r
-import org.simantics.simulation.experiment.IExperiment;\r
-import org.simantics.simulation.experiment.IExperimentListener;\r
-import org.simantics.simulation.model.IModel;\r
-import org.simantics.ui.workbench.WorkbenchShutdownService;\r
-import org.simantics.utils.datastructures.ListenerList;\r
-\r
-/**\r
- * Simple local ExperimentManager implementation\r
- */\r
-public class ExperimentManager implements IExperimentManager {\r
-\r
- CopyOnWriteArrayList<IExperimentManagerListener> listeners = new CopyOnWriteArrayList<IExperimentManagerListener>();\r
- ListenerList<IExperiment> experiments = new ListenerList<IExperiment>(IExperiment.class);\r
- IExperiment activeExperiment;\r
- AtomicBoolean isDisposed = new AtomicBoolean(false);\r
-\r
- public ExperimentManager() {\r
- BundleContext context = Activator.getDefault().getBundle().getBundleContext();\r
- ServiceReference<?> ref = context.getServiceReference(WorkbenchShutdownService.class.getName());\r
- if (ref != null) {\r
- WorkbenchShutdownService shutdown = (WorkbenchShutdownService) context.getService(ref);\r
- shutdown.registerShutdownHook(new Runnable() {\r
- @Override\r
- public void run() {\r
- IRunnableWithProgress runnable = new IRunnableWithProgress() {\r
- @Override\r
- public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {\r
- try {\r
- ExperimentManager.this.dispose(monitor);\r
- } finally {\r
- monitor.done();\r
- }\r
- }\r
- };\r
- try {\r
- if (PlatformUI.isWorkbenchRunning()) {\r
- IProgressService progress = (IProgressService) PlatformUI.getWorkbench().getService(IProgressService.class);\r
- progress.run(true, false, runnable);\r
- } else {\r
- runnable.run(null);\r
- }\r
- } catch (InvocationTargetException e) {\r
- Activator.logError("Experiment manager shutdown failed, see exception for details.", e);\r
- } catch (InterruptedException e) {\r
- Activator.logError("Experiment manager shutdown was interrupted, see exception for details.", e);\r
- }\r
- }\r
- });\r
- context.ungetService(ref);\r
- }\r
- }\r
-\r
- class ManagingExperimentListener implements IExperimentListener {\r
-\r
- IExperiment experiment;\r
- boolean setActive;\r
-\r
- public ManagingExperimentListener(IExperiment experiment, boolean setActive) {\r
- this.experiment = experiment;\r
- this.setActive = setActive;\r
- }\r
-\r
- @Override\r
- public void stateChanged(ExperimentState state) {\r
- if(state==ExperimentState.RUNNING || state==ExperimentState.STOPPED) {\r
- if(setActive && activeExperiment != experiment)\r
- setActiveExperiment(experiment);\r
- }\r
- else if(state==ExperimentState.DISPOSED) {\r
- removeActiveExperiment(experiment);\r
- experiments.remove(experiment);\r
- experiment.removeListener(this);\r
- experiment = null;\r
- }\r
- }\r
- }\r
-\r
- protected void manageExperiment(IExperiment experiment, boolean setActive) {\r
- experiments.add(experiment);\r
- experiment.addListener(new ManagingExperimentListener(experiment, setActive));\r
- }\r
-\r
- @Override\r
- public void startExperiment(final Resource experimentResource,\r
- final IExperimentActivationListener listener, final boolean setActive) {\r
- // ENFORCE SINGLE_EXPERIMENT MODE POLICY:\r
- // Shutdown active experiment before loading new experiment.\r
- // IMPORTANT: Perform shutdown outside of a graph transaction to allow\r
- // shutdown to perform graph requests at will.\r
- synchronized (ExperimentManager.this) {\r
- ExperimentManagerMode mode = getMode();\r
- // Close previous active experiment before loading new\r
- if (mode == ExperimentManagerMode.SINGLE_EXPERIMENT) {\r
- if (activeExperiment != null && setActive) {\r
- // TODO: provide a proper progress monitor for shutdown! \r
- activeExperiment.shutdown(null);\r
- }\r
- }\r
- }\r
-\r
- Simantics.getSession().asyncRequest(new ReadRequest() {\r
- @Override\r
- public void run(ReadGraph g) throws DatabaseException {\r
- \r
- LifecycleSupport ls = g.getService(LifecycleSupport.class);\r
- if(ls.isClosing() || ls.isClosed()) {\r
- return;\r
- }\r
- \r
- Layer0 L0 = Layer0.getInstance(g);\r
- final IModel model =\r
- g.adaptUnique(\r
- g.getSingleObject(experimentResource, L0.PartOf),\r
- IModel.class);\r
-\r
- final IExperimentActivationListener proxy = new ProxyExperimentActivationListener(listener) {\r
- @Override\r
- public void onExperimentActivated(IExperiment experiment) {\r
- if (experiment != null)\r
- manageExperiment(experiment, setActive);\r
- super.onExperimentActivated(experiment);\r
- }\r
- @Override\r
- public void onFailure(Throwable e) {\r
- super.onFailure(e);\r
- }\r
- };\r
-\r
- // Ignore return value, the experiment is\r
- // provided to proxy.onExperimentActivated.\r
- model.loadExperiment(g, experimentResource, proxy);\r
- }\r
- }, new ProcedureAdapter<Object>() {\r
- @Override\r
- public void exception(Throwable t) {\r
- listener.onFailure(t);\r
- }\r
- });\r
- }\r
-\r
- synchronized void setActiveExperiment(IExperiment experiment) {\r
- // Multiple experiments may need to run concurrently - so don't shutdown\r
- // if not explicitly requested to do so.\r
- if (getMode() == ExperimentManagerMode.SINGLE_EXPERIMENT) {\r
- if (activeExperiment != null) {\r
- activeExperiment.shutdown(null);\r
- for (IExperimentManagerListener listener : listeners)\r
- listener.activeExperimentUnloaded();\r
- }\r
- }\r
- activeExperiment = experiment;\r
- for(IExperimentManagerListener listener : listeners)\r
- listener.activeExperimentLoaded(experiment);\r
- }\r
-\r
- synchronized private void removeActiveExperiment(IExperiment experiment) {\r
- if(activeExperiment == experiment) {\r
- activeExperiment = null;\r
- for(IExperimentManagerListener listener : listeners)\r
- listener.activeExperimentUnloaded();\r
- }\r
- }\r
-\r
- @Override\r
- synchronized public void addListener(IExperimentManagerListener listener) {\r
- listeners.add(listener);\r
- if(activeExperiment != null)\r
- listener.activeExperimentLoaded(activeExperiment);\r
- }\r
-\r
- @Override\r
- synchronized public void removeListener(IExperimentManagerListener listener) {\r
- listeners.remove(listener);\r
- }\r
-\r
- public void dispose(IProgressMonitor monitor) {\r
- if(isDisposed.compareAndSet(false, true)) {\r
- if(activeExperiment != null)\r
- activeExperiment.shutdown(monitor);\r
- activeExperiment = null;\r
-\r
- for(IExperimentManagerListener listener : listeners)\r
- listener.managerDisposed();\r
-\r
- if (!listeners.isEmpty()) {\r
- // Some clients are leaking listeners. Shame on them.\r
- System.err.println("ExperimentManager still contains the following listeners after disposal:");\r
- for (IExperimentManagerListener listener : listeners)\r
- System.err.println("\t" + listener);\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public IExperiment getActiveExperiment() {\r
- return activeExperiment;\r
- }\r
-\r
- @Override\r
- public IExperiment getExperiment(final String identifier) {\r
- if(identifier == null) return null;\r
- for(IExperiment experiment : experiments.getListeners()) {\r
- if(experiment != null && identifier.equals(experiment.getIdentifier())) {\r
- return experiment;\r
- }\r
- }\r
- return null;\r
- }\r
-\r
- @Override\r
- public IExperiment[] getExperiments() {\r
- return experiments.getListeners();\r
- }\r
-\r
- private ExperimentManagerMode getMode() {\r
- ExperimentManagerMode mode = ExperimentManagerMode.MULTI_EXPERIMENT;\r
- IProject project = org.simantics.Simantics.peekProject();\r
- if (project == null)\r
- return mode;\r
- mode = project.getHint(ExperimentManagerKeys.EXPERIMENT_MANAGER_MODE);\r
- return mode != null ? mode : ExperimentManagerMode.MULTI_EXPERIMENT;\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.simulation.project;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.progress.IProgressService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.procedure.adapter.ProcedureAdapter;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.service.LifecycleSupport;
+import org.simantics.layer0.Layer0;
+import org.simantics.project.IProject;
+import org.simantics.simulation.Activator;
+import org.simantics.simulation.experiment.ExperimentState;
+import org.simantics.simulation.experiment.IExperiment;
+import org.simantics.simulation.experiment.IExperimentListener;
+import org.simantics.simulation.model.IModel;
+import org.simantics.ui.workbench.WorkbenchShutdownService;
+import org.simantics.utils.datastructures.ListenerList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Simple local ExperimentManager implementation
+ */
+public class ExperimentManager implements IExperimentManager {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ExperimentManager.class);
+
+ CopyOnWriteArrayList<IExperimentManagerListener> listeners = new CopyOnWriteArrayList<IExperimentManagerListener>();
+ ListenerList<IExperiment> experiments = new ListenerList<IExperiment>(IExperiment.class);
+ IExperiment activeExperiment;
+ AtomicBoolean isDisposed = new AtomicBoolean(false);
+
+ public ExperimentManager() {
+ BundleContext context = Activator.getDefault().getBundle().getBundleContext();
+ ServiceReference<?> ref = context.getServiceReference(WorkbenchShutdownService.class.getName());
+ if (ref != null) {
+ WorkbenchShutdownService shutdown = (WorkbenchShutdownService) context.getService(ref);
+ shutdown.registerShutdownHook(new Runnable() {
+ @Override
+ public void run() {
+ IRunnableWithProgress runnable = new IRunnableWithProgress() {
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ try {
+ ExperimentManager.this.dispose(monitor);
+ } finally {
+ monitor.done();
+ }
+ }
+ };
+ try {
+ if (PlatformUI.isWorkbenchRunning()) {
+ IProgressService progress = (IProgressService) PlatformUI.getWorkbench().getService(IProgressService.class);
+ progress.run(true, false, runnable);
+ } else {
+ runnable.run(null);
+ }
+ } catch (InvocationTargetException e) {
+ Activator.logError("Experiment manager shutdown failed, see exception for details.", e.getCause());
+ } catch (InterruptedException e) {
+ Activator.logError("Experiment manager shutdown was interrupted, see exception for details.", e);
+ }
+ }
+ });
+ context.ungetService(ref);
+ }
+ }
+
+ class ManagingExperimentListener implements IExperimentListener {
+
+ IExperiment experiment;
+ boolean setActive;
+
+ public ManagingExperimentListener(IExperiment experiment, boolean setActive) {
+ this.experiment = experiment;
+ this.setActive = setActive;
+ }
+
+ @Override
+ public void stateChanged(ExperimentState state) {
+ if(state==ExperimentState.RUNNING || state==ExperimentState.STOPPED) {
+ if(setActive && activeExperiment != experiment)
+ setActiveExperiment(experiment);
+ }
+ else if(state==ExperimentState.DISPOSED) {
+ removeActiveExperiment(experiment);
+ experiments.remove(experiment);
+ experiment.removeListener(this);
+ experiment = null;
+ }
+ }
+ }
+
+ protected void manageExperiment(IExperiment experiment, boolean setActive) {
+ experiments.add(experiment);
+ experiment.addListener(new ManagingExperimentListener(experiment, setActive));
+ }
+
+ @Override
+ public void startExperiment(final Resource experimentResource,
+ final IExperimentActivationListener listener, final boolean setActive) {
+ // ENFORCE SINGLE_EXPERIMENT MODE POLICY:
+ // Shutdown active experiment before loading new experiment.
+ // IMPORTANT: Perform shutdown outside of a graph transaction to allow
+ // shutdown to perform graph requests at will.
+ synchronized (ExperimentManager.this) {
+ ExperimentManagerMode mode = getMode();
+ // Close previous active experiment before loading new
+ if (mode == ExperimentManagerMode.SINGLE_EXPERIMENT) {
+ if (activeExperiment != null && setActive) {
+ // TODO: provide a proper progress monitor for shutdown!
+ activeExperiment.shutdown(null);
+ }
+ }
+ }
+
+ Simantics.getSession().asyncRequest(new ReadRequest() {
+ @Override
+ public void run(ReadGraph g) throws DatabaseException {
+
+ LifecycleSupport ls = g.getService(LifecycleSupport.class);
+ if(ls.isClosing() || ls.isClosed()) {
+ return;
+ }
+
+ Layer0 L0 = Layer0.getInstance(g);
+ final IModel model =
+ g.adaptUnique(
+ g.getSingleObject(experimentResource, L0.PartOf),
+ IModel.class);
+
+ final IExperimentActivationListener proxy = new ProxyExperimentActivationListener(listener) {
+ @Override
+ public void onExperimentActivated(IExperiment experiment) {
+ if (experiment != null)
+ manageExperiment(experiment, setActive);
+ super.onExperimentActivated(experiment);
+ }
+ @Override
+ public void onFailure(Throwable e) {
+ super.onFailure(e);
+ }
+ };
+
+ // Ignore return value, the experiment is
+ // provided to proxy.onExperimentActivated.
+ model.loadExperiment(g, experimentResource, proxy);
+ }
+ }, new ProcedureAdapter<Object>() {
+ @Override
+ public void exception(Throwable t) {
+ listener.onFailure(t);
+ }
+ });
+ }
+
+ synchronized void setActiveExperiment(IExperiment experiment) {
+ // Multiple experiments may need to run concurrently - so don't shutdown
+ // if not explicitly requested to do so.
+ if (getMode() == ExperimentManagerMode.SINGLE_EXPERIMENT) {
+ if (activeExperiment != null) {
+ activeExperiment.shutdown(null);
+ for (IExperimentManagerListener listener : listeners)
+ listener.activeExperimentUnloaded();
+ }
+ }
+ activeExperiment = experiment;
+ for(IExperimentManagerListener listener : listeners)
+ listener.activeExperimentLoaded(experiment);
+ }
+
+ synchronized private void removeActiveExperiment(IExperiment experiment) {
+ if(activeExperiment == experiment) {
+ activeExperiment = null;
+ for(IExperimentManagerListener listener : listeners)
+ listener.activeExperimentUnloaded();
+ }
+ }
+
+ @Override
+ synchronized public void addListener(IExperimentManagerListener listener) {
+ listeners.add(listener);
+ if(activeExperiment != null)
+ listener.activeExperimentLoaded(activeExperiment);
+ }
+
+ @Override
+ synchronized public void removeListener(IExperimentManagerListener listener) {
+ listeners.remove(listener);
+ }
+
+ public void dispose(IProgressMonitor monitor) {
+ if(isDisposed.compareAndSet(false, true)) {
+ if(activeExperiment != null)
+ activeExperiment.shutdown(monitor);
+ activeExperiment = null;
+
+ for(IExperimentManagerListener listener : listeners)
+ listener.managerDisposed();
+
+ if (!listeners.isEmpty()) {
+ // Some clients are leaking listeners. Shame on them.
+ LOGGER.warn("ExperimentManager still contains the following listeners after disposal:");
+ for (IExperimentManagerListener listener : listeners)
+ LOGGER.warn("\t" + listener);
+ }
+ }
+ }
+
+ @Override
+ public IExperiment getActiveExperiment() {
+ return activeExperiment;
+ }
+
+ @Override
+ public IExperiment getExperiment(final String identifier) {
+ if(identifier == null) return null;
+ for(IExperiment experiment : experiments.getListeners()) {
+ if(experiment != null && identifier.equals(experiment.getIdentifier())) {
+ return experiment;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IExperiment[] getExperiments() {
+ return experiments.getListeners();
+ }
+
+ private ExperimentManagerMode getMode() {
+ ExperimentManagerMode mode = ExperimentManagerMode.MULTI_EXPERIMENT;
+ IProject project = org.simantics.Simantics.peekProject();
+ if (project == null)
+ return mode;
+ mode = project.getHint(ExperimentManagerKeys.EXPERIMENT_MANAGER_MODE);
+ return mode != null ? mode : ExperimentManagerMode.MULTI_EXPERIMENT;
+ }
+
+}