Skip to content

Commit e463447

Browse files
Add scenario container and tests (#318)
* Add ScenarioContainer and corresponding tests * Update AT_ScenarioContainer and ScenarioContainer Made final adjustments to AT_ScenarioContainer and removed toString from ScenarioContainer and testToString from AT_ScenarioContainer.
1 parent 1cf5784 commit e463447

2 files changed

Lines changed: 801 additions & 0 deletions

File tree

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
package gov.hhs.aspr.ms.gcm.simulation.nucleus.testsupport;
2+
3+
import java.util.ArrayList;
4+
import java.util.LinkedHashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.Objects;
8+
import java.util.Optional;
9+
10+
import gov.hhs.aspr.ms.gcm.simulation.nucleus.NucleusError;
11+
import gov.hhs.aspr.ms.gcm.simulation.nucleus.Plugin;
12+
import gov.hhs.aspr.ms.gcm.simulation.nucleus.PluginData;
13+
import gov.hhs.aspr.ms.gcm.simulation.nucleus.PluginId;
14+
import gov.hhs.aspr.ms.gcm.simulation.nucleus.SimulationState;
15+
import gov.hhs.aspr.ms.util.errors.ContractException;
16+
17+
public final class ScenarioContainer {
18+
19+
private static class Data {
20+
21+
private Map<PluginId, Plugin> plugins = new LinkedHashMap<>();
22+
private SimulationState simulationState = SimulationState.builder().build();
23+
24+
private boolean locked;
25+
26+
private Data() {
27+
}
28+
29+
private Data(Data data) {
30+
plugins.putAll(data.plugins);
31+
simulationState = data.simulationState;
32+
locked = data.locked;
33+
}
34+
35+
/**
36+
* Standard implementation consistent with the {@link #equals(Object)} method
37+
*/
38+
@Override
39+
public int hashCode() {
40+
return Objects.hash(plugins, simulationState);
41+
}
42+
43+
/**
44+
* Two {@link Data} instances are equal if and only if their inputs are equal.
45+
*/
46+
@Override
47+
public boolean equals(Object obj) {
48+
if (this == obj) {
49+
return true;
50+
}
51+
if (!(obj instanceof Data)) {
52+
return false;
53+
}
54+
Data other = (Data) obj;
55+
return Objects.equals(plugins, other.plugins) && Objects.equals(simulationState, other.simulationState);
56+
}
57+
58+
}
59+
60+
private final Data data;
61+
62+
private ScenarioContainer(Data data) {
63+
this.data = data;
64+
}
65+
66+
/**
67+
* Returns a new builder instance
68+
*/
69+
public static Builder builder() {
70+
return new Builder(new Data());
71+
}
72+
73+
/**
74+
* Builder class for ScenarioContainer
75+
*/
76+
public static class Builder {
77+
private Data data;
78+
79+
private void ensureDataMutability() {
80+
if (data.locked) {
81+
data = new Data(data);
82+
data.locked = false;
83+
}
84+
}
85+
86+
private void ensureImmutability() {
87+
if (!data.locked) {
88+
data.locked = true;
89+
}
90+
}
91+
92+
private Builder(Data data) {
93+
this.data = data;
94+
}
95+
96+
/**
97+
* Returns the ScenarioContainer built from the collected data.
98+
*/
99+
public ScenarioContainer build() {
100+
101+
if (!data.locked) {
102+
validateData();
103+
}
104+
ensureImmutability();
105+
return new ScenarioContainer(data);
106+
}
107+
108+
/**
109+
* Adds a plugin to this container. Replaces any existing plugin with the same
110+
* plugin id.
111+
*
112+
* @throws ContractException
113+
* <ul>
114+
* <li>{@linkplain NucleusError#NULL_PLUGIN} if the
115+
* plugin is null</li>
116+
* </ul>
117+
*/
118+
public Builder addPlugin(final Plugin plugin) {
119+
ensureDataMutability();
120+
validatePluginNotNull(plugin);
121+
data.plugins.put(plugin.getPluginId(), plugin);
122+
return this;
123+
}
124+
125+
/**
126+
* Sets the simulation state. Defaults to the default SimulationState at the
127+
* current execution time.
128+
*
129+
* @throws ContractException
130+
*
131+
* <ul>
132+
* <li>{@linkplain NucleusError#NULL_SIMULATION_STATE}
133+
* if the simulation state is null</li>
134+
* </ul>
135+
*/
136+
public Builder setSimulationState(SimulationState simulationState) {
137+
validateSimulationStateNotNull(simulationState);
138+
ensureDataMutability();
139+
data.simulationState = simulationState;
140+
return this;
141+
}
142+
143+
private void validateData() {
144+
// do nothing
145+
}
146+
147+
private void validateSimulationStateNotNull(SimulationState simulationState) {
148+
if (simulationState == null) {
149+
throw new ContractException(NucleusError.NULL_SIMULATION_STATE);
150+
}
151+
}
152+
153+
private void validatePluginNotNull(Plugin plugin) {
154+
if (plugin == null) {
155+
throw new ContractException(NucleusError.NULL_PLUGIN);
156+
}
157+
}
158+
159+
}
160+
161+
/**
162+
* Returns the plugin data object compatible with the given plugin data class
163+
* reference.
164+
*
165+
* @throws ContractException
166+
* <ul>
167+
* <li>{@linkplain NucleusError#NULL_PLUGIN_DATA_CLASS}
168+
* if the class reference is null</li>
169+
* <li>{@linkplain NucleusError#AMBIGUOUS_PLUGIN_DATA_CLASS}
170+
* if more than one plugin data object matches the
171+
* class reference</li>
172+
* </ul>
173+
*/
174+
@SuppressWarnings("unchecked")
175+
public <T extends PluginData> Optional<T> getPluginData(Class<T> pluginDataClass) {
176+
if (pluginDataClass == null) {
177+
throw new ContractException(NucleusError.NULL_PLUGIN_DATA_CLASS);
178+
}
179+
PluginData result = null;
180+
for (PluginId pluginId : data.plugins.keySet()) {
181+
Plugin plugin = data.plugins.get(pluginId);
182+
for (PluginData pluginData : plugin.getPluginDatas()) {
183+
if (pluginData.getClass().isAssignableFrom(pluginDataClass)) {
184+
if (result == null) {
185+
result = pluginData;
186+
} else {
187+
throw new ContractException(NucleusError.AMBIGUOUS_PLUGIN_DATA_CLASS);
188+
}
189+
}
190+
}
191+
}
192+
return Optional.ofNullable((T) result);
193+
}
194+
195+
/**
196+
* Returns the plugin data objects associated with the given class reference
197+
*
198+
* @throws ContractException {@linkplain NucleusError#NULL_PLUGIN_DATA_CLASS} if
199+
* the class reference is null
200+
*/
201+
@SuppressWarnings("unchecked")
202+
public <T extends PluginData> List<T> getPluginDatas(Class<T> pluginDataClass) {
203+
if (pluginDataClass == null) {
204+
throw new ContractException(NucleusError.NULL_PLUGIN_DATA_CLASS);
205+
}
206+
List<T> result = new ArrayList<>();
207+
for (PluginId pluginId : data.plugins.keySet()) {
208+
Plugin plugin = data.plugins.get(pluginId);
209+
for (PluginData pluginData : plugin.getPluginDatas()) {
210+
if (pluginData.getClass().isAssignableFrom(pluginDataClass)) {
211+
result.add((T) pluginData);
212+
}
213+
}
214+
}
215+
return result;
216+
}
217+
218+
/**
219+
* Returns the contained plugin for the given plugin id. Tolerate null.
220+
*/
221+
public Optional<Plugin> getPlugin(PluginId pluginId) {
222+
Plugin plugin = data.plugins.get(pluginId);
223+
return Optional.ofNullable(plugin);
224+
}
225+
226+
/**
227+
* Returns the list of plugins in this container.
228+
*/
229+
public List<Plugin> getPlugins() {
230+
return new ArrayList<>(data.plugins.values());
231+
}
232+
233+
/**
234+
* Returns the simulation state.
235+
*
236+
*/
237+
public SimulationState getSimulationState() {
238+
return data.simulationState;
239+
}
240+
241+
public Builder toBuilder() {
242+
return new Builder(data);
243+
}
244+
245+
/**
246+
* Standard implementation consistent with the {@link #equals(Object)} method
247+
*/
248+
@Override
249+
public int hashCode() {
250+
return Objects.hash(data);
251+
}
252+
253+
/**
254+
* Two {@link ScenarioContainer} instances are equal if and only if their
255+
* inputs are equal.
256+
*/
257+
@Override
258+
public boolean equals(Object obj) {
259+
if (this == obj) {
260+
return true;
261+
}
262+
if (obj == null) {
263+
return false;
264+
}
265+
if (getClass() != obj.getClass()) {
266+
return false;
267+
}
268+
ScenarioContainer other = (ScenarioContainer) obj;
269+
return Objects.equals(data, other.data);
270+
}
271+
}

0 commit comments

Comments
 (0)