1 package org.opentrafficsim.base.parameters;
2
3 import java.io.Serializable;
4 import java.lang.reflect.Field;
5 import java.util.HashMap;
6 import java.util.Map;
7 import java.util.Set;
8
9 import org.djunits.unit.DimensionlessUnit;
10 import org.djunits.value.vdouble.scalar.Dimensionless;
11
12 import nl.tudelft.simulation.language.Throw;
13 import nl.tudelft.simulation.language.reflection.ClassUtil;
14
15
16
17
18
19
20
21
22
23
24
25 public class ParameterSet implements Parameters, Serializable
26 {
27
28
29 private static final long serialVersionUID = 20160400L;
30
31
32 private static final Empty EMPTY = new Empty();
33
34
35 private boolean copyOnWrite = false;
36
37
38 private Map<ParameterType<?>, Object> parameters;
39
40
41 private Map<ParameterType<?>, Object> previous;
42
43
44
45
46 public ParameterSet()
47 {
48 this.parameters = new HashMap<>();
49 this.previous = new HashMap<>();
50 }
51
52
53
54
55
56 public ParameterSet(final Parameters parameters)
57 {
58 if (parameters instanceof ParameterSet)
59 {
60 ParameterSet parameterSet = (ParameterSet) parameters;
61 this.parameters = parameterSet.parameters;
62 this.previous = parameterSet.previous;
63 this.copyOnWrite = true;
64 parameterSet.copyOnWrite = true;
65 }
66 else
67 {
68 parameters.setAllIn(this);
69 }
70 }
71
72
73 @Override
74 public final <T> void setParameter(final ParameterType<T> parameterType, final T value) throws ParameterException
75 {
76 Throw.when(value == null, ParameterException.class,
77 "Parameter of type '%s' was assigned a null value, this is not allowed.", parameterType.getId());
78 saveSetParameter(parameterType, value, false);
79 }
80
81
82 @Override
83 public final <T> void setParameterResettable(final ParameterType<T> parameterType, final T value) throws ParameterException
84 {
85 Throw.when(value == null, ParameterException.class,
86 "Parameter of type '%s' was assigned a null value, this is not allowed.", parameterType.getId());
87 saveSetParameter(parameterType, value, true);
88 }
89
90
91
92
93
94
95
96
97
98 private <T> void saveSetParameter(final ParameterType<T> parameterType, final T value, final boolean resettable)
99 throws ParameterException
100 {
101 parameterType.check(value, this);
102 parameterType.checkConstraint(value);
103 checkCopyOnWrite();
104 if (resettable)
105 {
106 Object prevValue = this.parameters.get(parameterType);
107 if (prevValue == null)
108 {
109
110 this.previous.put(parameterType, EMPTY);
111 }
112 else
113 {
114 this.previous.put(parameterType, prevValue);
115 }
116 }
117 else
118 {
119
120 this.previous.remove(parameterType);
121 }
122 this.parameters.put(parameterType, value);
123 }
124
125
126 @Override
127 public final void resetParameter(final ParameterType<?> parameterType) throws ParameterException
128 {
129 checkCopyOnWrite();
130 Object prevValue = this.previous.remove(parameterType);
131 Throw.when(prevValue == null, ParameterException.class,
132 "Reset on parameter of type '%s' could not be performed, it was not set resettable.", parameterType.getId());
133 if (prevValue instanceof Empty)
134 {
135
136 this.parameters.remove(parameterType);
137 }
138 else
139 {
140 this.parameters.put(parameterType, prevValue);
141 }
142 }
143
144
145
146
147 private void checkCopyOnWrite()
148 {
149 if (this.copyOnWrite)
150 {
151 this.parameters = new HashMap<>(this.parameters);
152 this.previous = new HashMap<>(this.previous);
153 this.copyOnWrite = false;
154 }
155 }
156
157
158 @Override
159 @SuppressWarnings("checkstyle:designforextension")
160 public <T> T getParameter(final ParameterType<T> parameterType) throws ParameterException
161 {
162 @SuppressWarnings("unchecked")
163
164 T result = (T) this.parameters.get(parameterType);
165 Throw.when(result == null, ParameterException.class, "Could not get parameter of type '%s' as it was not set.",
166 parameterType.getId());
167 return result;
168 }
169
170
171 @Override
172 @SuppressWarnings("unchecked")
173 public final <T> T getParameterOrNull(final ParameterType<T> parameterType)
174 {
175
176 return (T) this.parameters.get(parameterType);
177 }
178
179
180 @Override
181 public final boolean contains(final ParameterType<?> parameterType)
182 {
183 return this.parameters.containsKey(parameterType);
184 }
185
186
187
188
189
190 public final Map<ParameterType<?>, Object> getParameters()
191 {
192 return new HashMap<>(this.parameters);
193 }
194
195
196
197
198
199
200
201
202 public final <T> ParameterSet setDefaultParameter(final ParameterType<T> parameter) throws ParameterException
203 {
204 T defaultValue = parameter.getDefaultValue();
205 try
206 {
207 saveSetParameter(parameter, defaultValue, false);
208 }
209 catch (ParameterException pe)
210 {
211
212 throw new RuntimeException(pe);
213 }
214 return this;
215 }
216
217
218
219
220
221
222
223 public final ParameterSet setDefaultParameters(final Class<?> clazz)
224 {
225 return setDefaultParametersLocal(clazz);
226 }
227
228
229
230
231
232
233
234 @SuppressWarnings("unchecked")
235 private <T> ParameterSet setDefaultParametersLocal(final Class<?> clazz)
236 {
237
238 Set<Field> fields = ClassUtil.getAllFields(clazz);
239
240 for (Field field : fields)
241 {
242 if (ParameterType.class.isAssignableFrom(field.getType()))
243 {
244 try
245 {
246 field.setAccessible(true);
247 ParameterType<T> p = (ParameterType<T>) field.get(clazz);
248 saveSetParameter(p, p.getDefaultValue(), false);
249 }
250 catch (IllegalArgumentException iare)
251 {
252
253 throw new RuntimeException(iare);
254 }
255 catch (IllegalAccessException iace)
256 {
257
258 throw new RuntimeException(iace);
259 }
260 catch (ParameterException pe)
261 {
262
263 throw new RuntimeException(pe);
264 }
265 }
266 }
267 return this;
268 }
269
270
271 @Override
272 public final void setAllIn(final Parameters params)
273 {
274 if (params instanceof ParameterSet)
275 {
276 ParameterSet parameterSet = (ParameterSet) params;
277 parameterSet.checkCopyOnWrite();
278 parameterSet.parameters.putAll(this.parameters);
279 }
280 else
281 {
282 setAllOneByOne(params);
283 }
284 }
285
286
287
288
289
290
291 @SuppressWarnings("unchecked")
292 private <T> void setAllOneByOne(final Parameters params)
293 {
294 for (ParameterType<?> parameterType : this.parameters.keySet())
295 {
296 try
297 {
298 params.setParameter((ParameterType<T>) parameterType, (T) this.parameters.get(parameterType));
299 }
300 catch (ParameterException exception)
301 {
302 throw new RuntimeException(exception);
303 }
304 }
305 }
306
307
308 @Override
309 public final String toString()
310 {
311 StringBuilder out = new StringBuilder("Parameters [");
312 String sep = "";
313 for (ParameterType<?> apt : this.parameters.keySet())
314 {
315 try
316 {
317 out.append(sep).append(apt.getId()).append("=").append(apt.printValue(this));
318 sep = ", ";
319 }
320 catch (ParameterException pe)
321 {
322
323 throw new RuntimeException(pe);
324 }
325 }
326 out.append("]");
327 return out.toString();
328 }
329
330
331
332
333 private static class Empty extends Dimensionless
334 {
335
336 private static final long serialVersionUID = 20160414L;
337
338
339
340
341 Empty()
342 {
343 super(Double.NaN, DimensionlessUnit.SI);
344 }
345 }
346
347 }