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