]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.simulation/src/org/simantics/simulation/project/ExperimentManager.java
Merge "Testing SonarQube with Simantics Platform SDK"
[simantics/platform.git] / bundles / org.simantics.simulation / src / org / simantics / simulation / project / ExperimentManager.java
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
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.simulation.project;\r
13 \r
14 import java.lang.reflect.InvocationTargetException;\r
15 import java.util.concurrent.CopyOnWriteArrayList;\r
16 import java.util.concurrent.atomic.AtomicBoolean;\r
17 \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
40 \r
41 /**\r
42  * Simple local ExperimentManager implementation\r
43  */\r
44 public class ExperimentManager implements IExperimentManager {\r
45 \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
50 \r
51     public ExperimentManager() {\r
52         BundleContext context = Activator.getDefault().getBundle().getBundleContext();\r
53         ServiceReference<?> ref = context.getServiceReference(WorkbenchShutdownService.class.getName());\r
54         if (ref != null) {\r
55             WorkbenchShutdownService shutdown = (WorkbenchShutdownService) context.getService(ref);\r
56             shutdown.registerShutdownHook(new Runnable() {\r
57                 @Override\r
58                 public void run() {\r
59                     IRunnableWithProgress runnable = new IRunnableWithProgress() {\r
60                         @Override\r
61                         public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {\r
62                             try {\r
63                                 ExperimentManager.this.dispose(monitor);\r
64                             } finally {\r
65                                 monitor.done();\r
66                             }\r
67                         }\r
68                     };\r
69                     try {\r
70                         if (PlatformUI.isWorkbenchRunning()) {\r
71                             IProgressService progress = (IProgressService) PlatformUI.getWorkbench().getService(IProgressService.class);\r
72                             progress.run(true, false, runnable);\r
73                         } else {\r
74                             runnable.run(null);\r
75                         }\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
80                     }\r
81                 }\r
82             });\r
83             context.ungetService(ref);\r
84         }\r
85     }\r
86 \r
87     class ManagingExperimentListener implements IExperimentListener {\r
88 \r
89         IExperiment experiment;\r
90         boolean setActive;\r
91 \r
92         public ManagingExperimentListener(IExperiment experiment, boolean setActive) {\r
93             this.experiment = experiment;\r
94             this.setActive = setActive;\r
95         }\r
96 \r
97         @Override\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
102             }\r
103             else if(state==ExperimentState.DISPOSED) {\r
104                 removeActiveExperiment(experiment);\r
105                 experiments.remove(experiment);\r
106                 experiment.removeListener(this);\r
107                 experiment = null;\r
108             }\r
109         }\r
110     }\r
111 \r
112     protected void manageExperiment(IExperiment experiment, boolean setActive) {\r
113         experiments.add(experiment);\r
114         experiment.addListener(new ManagingExperimentListener(experiment, setActive));\r
115     }\r
116 \r
117     @Override\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
131                 }\r
132             }\r
133         }\r
134 \r
135         Simantics.getSession().asyncRequest(new ReadRequest() {\r
136             @Override\r
137             public void run(ReadGraph g) throws DatabaseException {\r
138                 \r
139                 LifecycleSupport ls = g.getService(LifecycleSupport.class);\r
140                 if(ls.isClosing() || ls.isClosed()) {\r
141                     return;\r
142                 }\r
143                 \r
144                 Layer0 L0 = Layer0.getInstance(g);\r
145                 final IModel model =\r
146                     g.adaptUnique(\r
147                             g.getSingleObject(experimentResource, L0.PartOf),\r
148                             IModel.class);\r
149 \r
150                 final IExperimentActivationListener proxy = new ProxyExperimentActivationListener(listener) {\r
151                     @Override\r
152                     public void onExperimentActivated(IExperiment experiment) {\r
153                         if (experiment != null)\r
154                             manageExperiment(experiment, setActive);\r
155                         super.onExperimentActivated(experiment);\r
156                     }\r
157                     @Override\r
158                     public void onFailure(Throwable e) {\r
159                         super.onFailure(e);\r
160                     }\r
161                 };\r
162 \r
163                 // Ignore return value, the experiment is\r
164                 // provided to proxy.onExperimentActivated.\r
165                 model.loadExperiment(g, experimentResource, proxy);\r
166             }\r
167         }, new ProcedureAdapter<Object>() {\r
168             @Override\r
169             public void exception(Throwable t) {\r
170                 listener.onFailure(t);\r
171             }\r
172         });\r
173     }\r
174 \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
183             }\r
184         }\r
185         activeExperiment = experiment;\r
186         for(IExperimentManagerListener listener : listeners)\r
187             listener.activeExperimentLoaded(experiment);\r
188     }\r
189 \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
195         }\r
196     }\r
197 \r
198     @Override\r
199     synchronized public void addListener(IExperimentManagerListener listener) {\r
200         listeners.add(listener);\r
201         if(activeExperiment != null)\r
202             listener.activeExperimentLoaded(activeExperiment);\r
203     }\r
204 \r
205     @Override\r
206     synchronized public void removeListener(IExperimentManagerListener listener) {\r
207         listeners.remove(listener);\r
208     }\r
209 \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
215 \r
216             for(IExperimentManagerListener listener : listeners)\r
217                 listener.managerDisposed();\r
218 \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
224             }\r
225         }\r
226     }\r
227 \r
228     @Override\r
229     public IExperiment getActiveExperiment() {\r
230         return activeExperiment;\r
231     }\r
232 \r
233     @Override\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
238                 return experiment;\r
239             }\r
240         }\r
241         return null;\r
242     }\r
243 \r
244     @Override\r
245     public IExperiment[] getExperiments() {\r
246         return experiments.getListeners();\r
247     }\r
248 \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
253             return mode;\r
254         mode = project.getHint(ExperimentManagerKeys.EXPERIMENT_MANAGER_MODE);\r
255         return mode != null ? mode : ExperimentManagerMode.MULTI_EXPERIMENT;\r
256     }\r
257 \r
258 }\r