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