1 | package de.uka.ipd.sdq.simucomframework.simulationdock; |
2 | |
3 | import java.io.File; |
4 | import java.io.FileOutputStream; |
5 | import java.io.IOException; |
6 | import java.util.Hashtable; |
7 | import java.util.Map; |
8 | |
9 | import org.apache.log4j.ConsoleAppender; |
10 | import org.apache.log4j.Logger; |
11 | import org.apache.log4j.PatternLayout; |
12 | import org.eclipse.emf.ecore.util.EcoreUtil; |
13 | import org.osgi.framework.Bundle; |
14 | import org.osgi.framework.BundleContext; |
15 | import org.osgi.framework.BundleException; |
16 | import org.osgi.framework.ServiceReference; |
17 | import org.osgi.service.event.Event; |
18 | import org.osgi.service.event.EventAdmin; |
19 | import org.osgi.util.tracker.ServiceTracker; |
20 | |
21 | import de.uka.ipd.sdq.simucomframework.AbstractMain; |
22 | import de.uka.ipd.sdq.simucomframework.model.SimuComModel; |
23 | import de.uka.ipd.sdq.simucomframework.simucomstatus.SimuComStatus; |
24 | import de.uka.ipd.sdq.simulation.AbstractSimulationConfig; |
25 | import de.uka.ipd.sdq.simulation.ISimulationControl; |
26 | import de.uka.ipd.sdq.simulation.SimulationResult; |
27 | |
28 | public class SimulationDockServiceImpl implements SimulationDockService { |
29 | |
30 | public static final String SIMTIME_TOTAL = "SIMTIMETOTAL"; |
31 | |
32 | protected static Logger logger = |
33 | Logger.getLogger(SimulationDockServiceImpl.class.getName()); |
34 | |
35 | private BundleContext context; |
36 | private String myID = EcoreUtil.generateUUID(); |
37 | private ServiceTracker service; |
38 | private ServiceTracker eventService; |
39 | private EventAdmin eventAdmin; |
40 | |
41 | private DebugObserver debugObserver; |
42 | |
43 | public SimulationDockServiceImpl(BundleContext context) { |
44 | this.context = context; |
45 | ServiceReference eventServiceRef = context.getServiceReference(EventAdmin.class.getName()); |
46 | eventService = new ServiceTracker(context,eventServiceRef,null); |
47 | eventService.open(); |
48 | eventAdmin = (EventAdmin)eventService.getService(); |
49 | |
50 | logger.addAppender(new ConsoleAppender(new PatternLayout(),ConsoleAppender.SYSTEM_OUT)); |
51 | logger.debug("Simulation Dock Started"); |
52 | } |
53 | |
54 | @Override |
55 | protected void finalize() throws Throwable { |
56 | eventService.close(); |
57 | super.finalize(); |
58 | } |
59 | |
60 | public void load(AbstractSimulationConfig config, byte[] simulationBundle, boolean isRemoteRun) { |
61 | sendEvent("de/uka/ipd/sdq/simucomframework/simucomdock/DOCK_BUSY"); |
62 | |
63 | if (config.isDebug()) { |
64 | this.debugObserver = new DebugObserver(eventAdmin,this); |
65 | } else { |
66 | this.debugObserver = null; |
67 | } |
68 | |
69 | ensurePluginLoaded(context, "org.eclipse.equinox.event"); |
70 | unloadPluginIfExists(context, "de.uka.ipd.sdq.codegen.simucominstance"); |
71 | |
72 | try { |
73 | loadBundle(config, simulationBundle, eventAdmin, isRemoteRun); |
74 | } catch (Exception e) { |
75 | unloadPluginIfExists(context, "de.uka.ipd.sdq.codegen.simucominstance"); |
76 | sendEvent("de/uka/ipd/sdq/simucomframework/simucomdock/DOCK_IDLE"); |
77 | throw new RuntimeException("Simulation preparation failed",e); |
78 | } finally { |
79 | |
80 | } |
81 | } |
82 | |
83 | |
84 | public void simulate(AbstractSimulationConfig config, byte[] simulationBundle, boolean isRemoteRun) { |
85 | |
86 | try { |
87 | simulateBundle(config, simulationBundle, eventAdmin, isRemoteRun); |
88 | } catch (Exception e) { |
89 | throw new RuntimeException("Simulation failed",e); |
90 | } finally { |
91 | unloadPluginIfExists(context, "de.uka.ipd.sdq.codegen.simucominstance"); |
92 | sendEvent("de/uka/ipd/sdq/simucomframework/simucomdock/DOCK_IDLE"); |
93 | } |
94 | } |
95 | |
96 | Bundle simulationBundleRef = null; |
97 | private DispatchingSimulationObserver simulationObservers = null; |
98 | long simulationStartTime = -1; |
99 | |
100 | private void loadBundle(AbstractSimulationConfig config, |
101 | byte[] simulationBundle, EventAdmin eventAdmin, boolean isRemoteRun) { |
102 | String bundleLocation = persistBundleInTempDir(simulationBundle); |
103 | try { |
104 | simulationBundleRef = context.installBundle(new File(bundleLocation).toURI().toString()); |
105 | simulationBundleRef.start(); |
106 | |
107 | } catch (BundleException e) { |
108 | throw new RuntimeException("OSGi failure",e); |
109 | } |
110 | ServiceReference[] services = simulationBundleRef.getRegisteredServices(); |
111 | assert services.length == 1; |
112 | |
113 | service = new ServiceTracker(context,services[0],null); |
114 | service.open(); |
115 | try { |
116 | simulationObservers = new DispatchingSimulationObserver(); |
117 | simulationObservers.addObserver(new SimulationProgressReportingObserver(config,eventAdmin,this)); |
118 | if (debugObserver != null) { |
119 | simulationObservers.addObserver(debugObserver); |
120 | } |
121 | |
122 | simulationStartTime = System.nanoTime(); |
123 | sendEvent("de/uka/ipd/sdq/simucomframework/simucomdock/SIM_STARTED"); |
124 | ((ISimulationControl) service.getService()).prepareSimulation(config, simulationObservers, isRemoteRun); |
125 | } catch (Exception ex) { |
126 | throw new RuntimeException(ex); |
127 | } |
128 | } |
129 | |
130 | public SimuComModel getSimuComModel() { |
131 | if (service != null) { |
132 | return ((AbstractMain)service.getService()).getModel(); |
133 | } |
134 | return null; |
135 | } |
136 | |
137 | private void simulateBundle(AbstractSimulationConfig config, |
138 | byte[] simulationBundle, EventAdmin eventAdmin, boolean isRemoteRun) { |
139 | try { |
140 | simulate(config, simulationBundleRef, eventAdmin, isRemoteRun); |
141 | } catch (Exception e) { |
142 | throw new RuntimeException("OSGi failure",e); |
143 | } finally { |
144 | if (simulationBundleRef != null) { |
145 | try { |
146 | if (simulationBundleRef.getState() == Bundle.ACTIVE) |
147 | simulationBundleRef.stop(); |
148 | |
149 | simulationBundleRef.uninstall(); |
150 | } catch (BundleException e) { |
151 | throw new RuntimeException("OSGi failure",e); |
152 | } |
153 | } |
154 | } |
155 | |
156 | } |
157 | |
158 | private void simulate(final AbstractSimulationConfig config, Bundle simulationBundleRef, final EventAdmin eventAdmin, boolean isRemoteRun) { |
159 | try { |
160 | SimulationResult result = ((ISimulationControl)service.getService()).startSimulation( |
161 | config, simulationObservers, isRemoteRun); |
162 | |
163 | if (result == SimulationResult.ERROR) { |
164 | throw new RuntimeException("Simulation failed.",((ISimulationControl)service.getService()).getErrorThrowable()); |
165 | } |
166 | } catch (Exception ex) { |
167 | throw new RuntimeException(ex); |
168 | } finally { |
169 | service.close(); |
170 | Hashtable<String, Object> eventData = new Hashtable<String, Object>(); |
171 | eventData.put(SIMTIME_TOTAL, System.nanoTime()-simulationStartTime); |
172 | sendEvent("de/uka/ipd/sdq/simucomframework/simucomdock/SIM_STOPPED",eventData); |
173 | } |
174 | } |
175 | |
176 | public void suspend() { |
177 | if (debugObserver == null) |
178 | throw new IllegalStateException("Suspend only available in debug mode"); |
179 | debugObserver.suspend(); |
180 | } |
181 | |
182 | public void resume() { |
183 | if (debugObserver == null) |
184 | throw new IllegalStateException("Suspend only available in debug mode"); |
185 | debugObserver.resume(); |
186 | } |
187 | |
188 | private void sendEvent(String topic) { |
189 | sendEvent(topic, new Hashtable()); |
190 | } |
191 | |
192 | private void sendEvent(String topic, Hashtable newProperties) { |
193 | Hashtable properties = new Hashtable(); |
194 | properties.put("DOCK_ID", SimulationDockServiceImpl.this.getDockId()); |
195 | properties.putAll(newProperties); |
196 | Event event = new Event(topic, (Map)properties); |
197 | eventAdmin.sendEvent(event); |
198 | } |
199 | |
200 | private String persistBundleInTempDir(byte[] simulationBundle) { |
201 | File tempFile = null; |
202 | try { |
203 | tempFile = File.createTempFile("simucominstance", ".jar"); |
204 | tempFile.deleteOnExit(); |
205 | FileOutputStream fos = new FileOutputStream(tempFile); |
206 | fos.write(simulationBundle); |
207 | fos.close(); |
208 | } catch (IOException e) { |
209 | throw new RuntimeException("OSGi failure",e); |
210 | } |
211 | return tempFile.getAbsolutePath(); |
212 | } |
213 | |
214 | public String getDockId() { |
215 | return myID; |
216 | } |
217 | |
218 | private void unloadPluginIfExists(BundleContext context, String bundleName) { |
219 | for (Bundle b : context.getBundles()) { |
220 | if (b.getSymbolicName() != null && b.getSymbolicName().equals(bundleName)) { |
221 | try { |
222 | if (b.getState() == Bundle.ACTIVE){ |
223 | b.stop(); |
224 | } |
225 | b.uninstall(); |
226 | } catch (BundleException e) { |
227 | throw new RuntimeException("OSGi failure",e); |
228 | } |
229 | } |
230 | } |
231 | } |
232 | |
233 | private void ensurePluginLoaded(BundleContext context, String bundleName) { |
234 | for (Bundle b : context.getBundles()) { |
235 | if (b.getSymbolicName() != null && b.getSymbolicName().equals(bundleName)) { |
236 | if (b.getState() != Bundle.ACTIVE){ |
237 | try { |
238 | b.start(); |
239 | } catch (BundleException e) { |
240 | throw new RuntimeException("OSGi failure",e); |
241 | } |
242 | } |
243 | } |
244 | } |
245 | } |
246 | |
247 | public void stopSimulation() { |
248 | if (service != null && service.getService() != null) { |
249 | ((ISimulationControl)service.getService()).stopSimulation(); |
250 | } |
251 | if (debugObserver != null) { |
252 | debugObserver.resume(); |
253 | } |
254 | } |
255 | |
256 | public void step() { |
257 | if (debugObserver == null) |
258 | throw new IllegalStateException("Stepping only available in debug mode"); |
259 | debugObserver.step(); |
260 | } |
261 | |
262 | public SimuComStatus getSimuComStatus() { |
263 | return ((ISimulationControl)service.getService()).getStatus(); |
264 | } |
265 | } |