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