X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.simulation%2Fsrc%2Forg%2Fsimantics%2Fsimulation%2Fproject%2FExperimentManager.java;h=ec56854751f55bc5d5666cb29422b6a7ff10e184;hb=refs%2Fchanges%2F38%2F238%2F2;hp=b9e2e0864fd0f08312df47f3798c8bb16b15789b;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.simulation/src/org/simantics/simulation/project/ExperimentManager.java b/bundles/org.simantics.simulation/src/org/simantics/simulation/project/ExperimentManager.java index b9e2e0864..ec5685475 100644 --- a/bundles/org.simantics.simulation/src/org/simantics/simulation/project/ExperimentManager.java +++ b/bundles/org.simantics.simulation/src/org/simantics/simulation/project/ExperimentManager.java @@ -1,258 +1,258 @@ -/******************************************************************************* - * 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; - -/** - * Simple local ExperimentManager implementation - */ -public class ExperimentManager implements IExperimentManager { - - CopyOnWriteArrayList listeners = new CopyOnWriteArrayList(); - ListenerList experiments = new ListenerList(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); - } 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() { - @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. - System.err.println("ExperimentManager still contains the following listeners after disposal:"); - for (IExperimentManagerListener listener : listeners) - System.err.println("\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; - } - -} +/******************************************************************************* + * 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; + +/** + * Simple local ExperimentManager implementation + */ +public class ExperimentManager implements IExperimentManager { + + CopyOnWriteArrayList listeners = new CopyOnWriteArrayList(); + ListenerList experiments = new ListenerList(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() { + @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. + System.err.println("ExperimentManager still contains the following listeners after disposal:"); + for (IExperimentManagerListener listener : listeners) + System.err.println("\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; + } + +}