1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
|
package testing;
import simulator.*;
import simulator.engine.*;
import core.*;
import prefs.*;
import events.*;
import serialize.*;
import java.lang.reflect.*;
import java.util.concurrent.*;
import java.util.ArrayList;
/**
* A headless runner that uses the new decoupled simulation engine.
* This demonstrates how the new architecture eliminates GUI errors.
*/
public class EngineBasedHeadlessRunner {
private final VSDefaultPrefs prefs;
private SimulationEngine engine;
private VSSimulator simulator;
private LogCapture logCapture;
private final ExecutorService executor;
private boolean printLogs = false;
public EngineBasedHeadlessRunner() {
this.prefs = new VSDefaultPrefs();
this.prefs.fillWithDefaults();
VSRegisteredEvents.init(prefs);
this.executor = Executors.newSingleThreadExecutor();
}
public SimulationResult runSimulation(String simulationFile, long maxTime) throws Exception {
return runSimulation(simulationFile, maxTime, null);
}
public SimulationResult runSimulation(String simulationFile, long maxTime, LogListener listener)
throws Exception {
System.out.println("Loading simulation: " + simulationFile);
try {
// Create log capture first
logCapture = new LogCapture();
logCapture.setPrintLogs(printLogs);
if (listener != null) {
logCapture.addListener(listener);
}
// Create headless engine
engine = new HeadlessSimulationEngine(prefs, logCapture);
// Load simulation data
loadSimulation(simulationFile);
System.out.println("Running simulation for " + maxTime + "ms...");
// Run simulation in executor
Future<Void> runFuture = executor.submit(() -> {
try {
runSimulation(maxTime);
} catch (Exception e) {
System.err.println("Error during simulation: " + e.getMessage());
e.printStackTrace();
}
return null;
});
// Wait for completion
try {
runFuture.get(maxTime * 2, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
System.out.println("Simulation timeout - stopping...");
runFuture.cancel(true);
}
System.out.println("Simulation complete. Captured " +
logCapture.getTotalLogCount() + " log entries.");
return new SimulationResult(
logCapture.getCapturedLogs(),
logCapture.getProcessLogs(),
getSimulationMetrics()
);
} catch (Exception e) {
System.err.println("Failed to run simulation: " + e.getMessage());
throw e;
}
}
private void loadSimulation(String simulationFile) throws Exception {
// We need a custom loader that works with the engine
// For now, we'll use the existing loader and extract data
DummySimulatorFrame dummyFrame = null;
try {
// Create minimal frame for loading
dummyFrame = new DummySimulatorFrame(prefs);
// Load simulation
VSSerialize serialize = new VSSerialize();
simulator = serialize.openSimulator(simulationFile, dummyFrame);
if (simulator == null) {
throw new IllegalStateException("Failed to load simulation");
}
// Extract visualization
Field vizField = VSSimulator.class.getDeclaredField("simulatorVisualization");
vizField.setAccessible(true);
VSSimulatorVisualization viz = (VSSimulatorVisualization) vizField.get(simulator);
// Extract processes and add to engine
for (int i = 0; i < viz.getNumProcesses(); i++) {
VSInternalProcess process = viz.getProcess(i);
if (process != null) {
engine.addProcess(process);
// Update process to use engine for message sending
injectEngineIntoProcess(process);
}
}
// Extract tasks from task manager
VSTaskManager vizTaskManager = viz.getTaskManager();
copyTasksToEngine(vizTaskManager, engine.getTaskManager());
} finally {
if (dummyFrame != null) {
dummyFrame.dispose();
}
}
}
private void injectEngineIntoProcess(VSInternalProcess process) throws Exception {
// This is where we'd modify the process to use the engine for sending messages
// For now, we'll set up the logging
Field logingField = VSAbstractProcess.class.getDeclaredField("loging");
logingField.setAccessible(true);
logingField.set(process, logCapture);
}
private void copyTasksToEngine(VSTaskManager source, VSTaskManager dest) throws Exception {
// Copy tasks from source to destination
// This requires accessing internal task manager state
Field globalTasksField = VSTaskManager.class.getDeclaredField("globalTasks");
globalTasksField.setAccessible(true);
Field localTasksField = VSTaskManager.class.getDeclaredField("localTasks");
localTasksField.setAccessible(true);
// Copy global tasks
Object globalTasks = globalTasksField.get(source);
globalTasksField.set(dest, globalTasks);
// Copy local tasks
Object localTasks = localTasksField.get(source);
localTasksField.set(dest, localTasks);
}
private void runSimulation(long maxTime) {
if (engine instanceof HeadlessSimulationEngine) {
HeadlessSimulationEngine headlessEngine = (HeadlessSimulationEngine) engine;
// Reset and start
engine.reset();
engine.play();
// Run for specified duration
headlessEngine.runFor(maxTime);
}
}
private SimulationMetrics getSimulationMetrics() {
return new SimulationMetrics(
engine.getNumProcesses(),
logCapture.getTotalLogCount(),
logCapture.getProcessMessageCounts()
);
}
public void setPrintLogs(boolean printLogs) {
this.printLogs = printLogs;
if (logCapture != null) {
logCapture.setPrintLogs(printLogs);
}
}
public void shutdown() {
executor.shutdown();
try {
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}
|