View Javadoc
1   package org.opentrafficsim.base.parameters;
2   
3   import java.io.Serializable;
4   
5   import org.opentrafficsim.base.Identifiable;
6   import org.opentrafficsim.base.Type;
7   import org.opentrafficsim.base.parameters.constraint.Constraint;
8   
9   import nl.tudelft.simulation.language.Throw;
10  
11  /**
12   * Defines meta-information of a parameter, defining the parameter uniquely.
13   * <p>
14   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
15   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
16   * <p>
17   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Apr 13, 2016 <br>
18   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
19   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
20   * @param <T> Type of the value.
21   */
22  public class ParameterType<T> extends Type<ParameterType<T>> implements Serializable, Identifiable
23  {
24  
25      /** */
26      private static final long serialVersionUID = 20160400L;
27  
28      /** Short name of parameter. */
29      private final String id;
30  
31      /** Parameter description or full name. */
32      private final String description;
33  
34      /** Default constraint. */
35      private final Constraint<? super T> constraint;
36  
37      /** Class of the value. */
38      private final Class<T> valueClass;
39  
40      /** Default value. */
41      @SuppressWarnings("checkstyle:visibilitymodifier")
42      protected final T defaultValue;
43  
44      /**
45       * Construct a new AbstractParameterType without default value and constraint.
46       * @param id String; short name of the new AbstractParameterType
47       * @param description String; description or full name of the new AbstractParameterType
48       * @param valueClass Class&lt;T&gt;; class of the value of the new AbstractParameterType
49       */
50      public ParameterType(final String id, final String description, final Class<T> valueClass)
51      {
52          this(id, description, valueClass, null, null, false);
53      }
54  
55      /**
56       * Construct a new AbstractParameterType without default value and with constraint.
57       * @param id String; short name of the new AbstractParameterType
58       * @param description String; description or full name of the new AbstractParameterType
59       * @param valueClass Class&lt;T&gt;; class of the value of the new AbstractParameterType
60       * @param constraint Constraint&lt;? super T&gt;; constraint that applies to the value of the new AbstractParameterType
61       */
62      public ParameterType(final String id, final String description, final Class<T> valueClass,
63              final Constraint<? super T> constraint)
64      {
65          this(id, description, valueClass, null, constraint, false);
66      }
67  
68      /**
69       * Construct a new AbstractParameterType with default value, without constraint.
70       * @param id String; short name of the new AbstractParameterType
71       * @param description String; description or full name of the new AbstractParameterType
72       * @param valueClass Class&lt;T&gt;; class of the value of the new AbstractParameterType
73       * @param defaultValue T; default value of the new AbstractParameterType
74       */
75      public ParameterType(final String id, final String description, final Class<T> valueClass, final T defaultValue)
76      {
77          this(id, description, valueClass, defaultValue, null, true);
78      }
79  
80      /**
81       * Construct a new AbstractParameterType with default value and constraint.
82       * @param id String; short name of the new AbstractParameterType
83       * @param description String; description or full name of the new AbstractParameterType
84       * @param valueClass Class&lt;T&gt;; class of the value of the new AbstractParameterType
85       * @param defaultValue T; default value of the new AbstractParameterType
86       * @param constraint Constraint&lt;? super T&gt;; constraint that applies to the value of the new AbstractParameterType
87       */
88      public ParameterType(final String id, final String description, final Class<T> valueClass, final T defaultValue,
89              final Constraint<? super T> constraint)
90      {
91          this(id, description, valueClass, defaultValue, constraint, true);
92      }
93  
94      /**
95       * Protected constructor with default value and constraint, which may check the default value.
96       * @param id String; short name of the new AbstractParameterType
97       * @param description String; description or full name of the new AbstractParameterType
98       * @param valueClass Class&lt;T&gt;; class of the value of the new AbstractParameterType
99       * @param defaultValue T; default value of the new AbstractParameterType
100      * @param constraint Constraint&lt;? super T&gt;; constraint that applies to the value of the new AbstractParameterType
101      * @param hasDefaultValue boolean; if true a check is performed to ensure that the default value is not null and does not
102      *            violate the constraint
103      */
104     private ParameterType(final String id, final String description, final Class<T> valueClass, final T defaultValue,
105             final Constraint<? super T> constraint, final boolean hasDefaultValue)
106     {
107         Throw.whenNull(id, "Id may not be null.");
108         Throw.whenNull(description, "Description may not be null.");
109         Throw.whenNull(valueClass, "Value class may not be null.");
110         if (hasDefaultValue)
111         {
112             Throw.whenNull(defaultValue, "Default values of parameter types may not be null.");
113         }
114         this.id = id;
115         this.description = description;
116         this.valueClass = valueClass;
117         this.defaultValue = defaultValue;
118         this.constraint = constraint;
119         if (this.defaultValue != null)
120         {
121             try
122             {
123                 checkConstraint(this.defaultValue);
124             }
125             catch (ParameterException pe)
126             {
127                 throw new RuntimeException(
128                         "Default value of parameter '" + this.id + "' does not comply with default constraints.", pe);
129             }
130             try
131             {
132                 // Forward empty set of parameters. At creation time of parameter types, values cannot be checked with values of
133                 // other parameter types.
134                 check(defaultValue, new ParameterSet());
135             }
136             catch (ParameterException pe)
137             {
138                 throw new RuntimeException(
139                         "Default value of parameter '" + getId() + "' does not comply with custom constraints.", pe);
140             }
141         }
142     }
143 
144     /**
145      * Retrieve the id of this AbstractParameterType.
146      * @return String; the id of this AbstractParameterType
147      */
148     @Override
149     public final String getId()
150     {
151         return this.id;
152     }
153 
154     /**
155      * Retrieve the description of this AbstractParameterType.
156      * @return String; the description of this AbstractParameterType
157      */
158     public final String getDescription()
159     {
160         return this.description;
161     }
162 
163     /**
164      * Retrieve the class of the value of this AbstractParameterType.
165      * @return valueClass Class&lt;T&gt;; the class of the value of this AbstractParameterType
166      */
167     public final Class<T> getValueClass()
168     {
169         return this.valueClass;
170     }
171 
172     /**
173      * Returns whether this parameter type has a default value.
174      * @return boolean; true if this AbstractParameterType type has a default value; false if it does not have a default value
175      */
176     public final boolean hasDefaultValue()
177     {
178         return this.defaultValue != null;
179     }
180 
181     /**
182      * Retrieve the the default value of this AbstractParameterType.
183      * @return T; the default value of this AbstractParameterType
184      * @throws ParameterException if this AbstractParameterType does not have a default value
185      */
186     public final T getDefaultValue() throws ParameterException
187     {
188         Throw.when(null == this.defaultValue, ParameterException.class, "No default value was set for '%s'.", getId());
189         return this.defaultValue;
190     }
191 
192     /**
193      * Check that a value complies with the constraint of this AbstractParameterType.
194      * @param value T; the value to check
195      * @throws ParameterException if the value does not comply with constraints
196      */
197     public final void checkConstraint(final T value) throws ParameterException
198     {
199         if (this.constraint == null)
200         {
201             return;
202         }
203         Throw.when(!this.constraint.accept(value), ParameterException.class, this.constraint.failMessage(), this.getId());
204     }
205 
206     /**
207      * Default implementation of check method. This default implementation will never throw any Exception.
208      * @param value T; the value to check
209      * @param params Parameters; Set of parameters to check
210      * @throws ParameterException If the value does not comply with constraints.
211      */
212     public void check(final T value, final Parameters params) throws ParameterException
213     {
214         // Default implementation does nothing
215     }
216 
217     /**
218      * Print the given value from the map in Parameters in a presentable format. The default implementation simply returns the
219      * output of toString().
220      * @param parameters Parameters to get the value from
221      * @return String; readable representation of the value
222      * @throws ParameterException If the parameter is not present
223      */
224     public String printValue(final Parameters parameters) throws ParameterException
225     {
226         return parameters.getParameter(this).toString();
227     }
228 
229     /** {@inheritDoc} */
230     @Override
231     public final int hashCode()
232     {
233         final int prime = 31;
234         int result = 1;
235         result = prime * result + ((this.defaultValue == null) ? 0 : this.defaultValue.hashCode());
236         result = prime * result + this.description.hashCode();
237         result = prime * result + this.id.hashCode();
238         result = prime * result + this.valueClass.hashCode();
239         return result;
240     }
241 
242     /** {@inheritDoc} */
243     @Override
244     public final boolean equals(final Object obj)
245     {
246         if (this == obj)
247         {
248             return true;
249         }
250         if (obj == null)
251         {
252             return false;
253         }
254         if (getClass() != obj.getClass())
255         {
256             return false;
257         }
258         ParameterType<?> other = (ParameterType<?>) obj;
259         if (!this.id.equals(other.id))
260         {
261             return false;
262         }
263         if (!this.description.equals(other.description))
264         {
265             return false;
266         }
267         if (!this.valueClass.equals(other.valueClass))
268         {
269             return false;
270         }
271         if (this.defaultValue == null)
272         {
273             if (other.defaultValue != null)
274             {
275                 return false;
276             }
277         }
278         else if (!this.defaultValue.equals(other.defaultValue))
279         {
280             return false;
281         }
282         return true;
283     }
284 
285     /**
286      * Retrieve the constraint.
287      * @return Constraint; the constraint of this AbstractParameterType
288      */
289     public final Constraint<? super T> getConstraint()
290     {
291         return this.constraint;
292     }
293 
294     /** {@inheritDoc} */
295     @SuppressWarnings("checkstyle:designforextension")
296     @Override
297     public String toString()
298     {
299         return "ParameterType [id=" + this.id + ", description=" + this.description + ", valueClass=" + this.valueClass + "]";
300     }
301 
302 }