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