2 * Copyright (c) 2003-2005 The BISON Project
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 package peersim.config;
24 * Fully static class to store configuration information. It defines a
25 * method, {@link #setConfig(Properties)}, to set configuration data. This
26 * method is called by the simulator engines as the very first thing they
27 * do. It can be called only once, after that the class becomes read only.
28 * All components can then access this configuration and utility methods to
29 * read property values based on their names.
31 * The design of this class also hides the actual implementation of the
32 * configuration which can be Properties, XML, whatever. Currently only
33 * Properties is supported.
35 * Apart from storing (name,value) pairs, this class also does some
36 * processing, and offers some utility functions. This extended
37 * functionality consists of the following: reading values with type
38 * checking, ordering of entries, pre-processing protocol names, parsing
39 * expressions, resolving underspecified classnames, and finally some basic
40 * debugging possibilities. We discuss these in the following.
42 * Note that the configuration is initialized using a Properties object.
43 * The class of this object might implement some additional pre-processing
44 * on the file or provide an extended syntax for defining property files.
45 * See {@link ParsedProperties} for more details. This is the class that is
46 * currently used by simulation engines.
47 * <h3>Typed reading of values</h3>
48 * Properties can have arbitrary values of type String. This class offers a
49 * set of read methods that perform the appropriate conversion of the
50 * string value to the given type, eg long. They also allow for specifying
51 * default values in case the given property is not specified.
52 * <h3>Resolving class names</h3>
54 * The possibilities for the typed reading of a value includes interpreting
55 * the value as a class name. In this case an object will be constructed.
56 * It is described at method {@link #getInstance(String)} how this is
57 * achieved exactly. What needs to be noted here is that the property value
58 * need not be a fully specified classname. It might contain only the short
59 * class name without the package specification. In this case, it is
60 * attempted to locate a class with that name in the classpath, and if a
61 * unique class is found, it will be used. This simplifies the
62 * configuration files and also allows to remove their dependence on the
63 * exact location of the class.
65 * <h3>Components and their ordering</h3>
66 * The idea of the configuration is that it mostly contains components and
67 * their descriptions (parameters). Although this class is blind to the
68 * semantics of these components, it offers some low level functionality
69 * that helps dealing with them. This functionality is based on the
70 * assumption that components have a type and a name. Both types and names
71 * are strings of alphanumeric and underscore characters. For example,
72 * {@value #PAR_PROT} is a type, "foo" can be a name. Method
73 * {@link #getNames} allow the caller to get the list of names for a given
74 * type. Some other methods, like {@link #getInstanceArray} use this list
75 * to return a list of components.
78 * Assuming the configuration is in Properties format (which is currently
79 * the only format available) component types and names are defined as
80 * follows. Property names containing two non-empty words separated by one
81 * dot (".") character are treated specially (the words contain word
82 * characters: alphanumeric and underscore ("_")). The first word will be
83 * the type, and the second is the name of a component. For example,
86 * control.conn ConnectivityObserver
88 * control.2 PrintGraph
91 * defines control components of names "conn","1" an "2" (arguments of the
92 * components not shown). When {@link #getNames} or
93 * {@link #getInstanceArray} are called, eg
94 * <code>getNames("control")</code>, then the order in which these are
95 * returned is alphabetical:
96 * <code>["control.1","control.2","control.conn"]</code>. If you are not
97 * satisfied with lexicographic order, you can specify the order in this
101 * order.control 1,conn,2
104 * where the names are separated by any non-word character (non
105 * alphanumeric or underscore). If not all names are listed then the given
106 * order is followed by alphabetical order of the rest of the items, e.g.
112 * results in <code>["control.2","control.1","control.conn"]</code>.
114 * It is also possible to exclude elements from the list, while ordering
115 * them. The syntax is identical to that of the above, only the parameter
116 * name begins with <code>include</code>. For example
119 * include.control conn 2
122 * will result in returning <em>only</em> <code>control.conn</code> and
123 * <code>control.2</code>, in this order. Note that for example the
124 * empty list results in a zero length array in this case.
125 * <em>Important!</em> If include is defined then ordering is ignored.
126 * That is, include is stronger than order.
127 * <h3>Protocol names</h3>
128 * As mentioned, the configuration is generally blind to the actual names
129 * of the components. There is an exception: the components of type
130 * {@value #PAR_PROT}. These are pre-processed a bit to enhance
131 * performance: protocol names are mapped to numeric protocol identifiers.
132 * The numeric identifier of a protocol is its index in the array returned
133 * by {@link #getNames}. See above how to control this order. The numeric
134 * identifiers then can be looked up based on the name and vice versa.
135 * Besides, the identifier can be directly requested based on a property
136 * name when the protocol name is the value of a property which is
137 * frequently the case.
139 * <h3>Expressions</h3>
140 * Numeric property values can be complex expressions, that are parsed
141 * using <a href="http://www.singularsys.com/jep/">JEP</a>. You can write
142 * expression using the syntax that you can find <a
143 * href="http://www.singularsys.com/jep/doc/html/op_and_func.html"> here</a>.
151 * SIZE=4. You can also have complex expression trees like this:
162 * that results in A=7, B=3, C=4, D=1, E=2, F=2
165 * Expressions like "sub-expression op sub-expression" are computed based
166 * on the type of the sub-expressions. If both sub-expressions are integer,
167 * the computation is done using integer arithmetics and the result is an
168 * integer. So, for example, 5/2 returns 2. If one of the sub-expression is
169 * floating point, the computation is based on floating-point arithmetics
170 * (double precision) and the result is a floating point value. So, for
171 * example, 5.0/2 returns 2.5.
174 * Expressions are parsed recursively. Note that no optimization is done,
175 * so expression F is evaluated three times here (due to the fact that
176 * appears twice in C and once in B). But since properties are read just
177 * once at initialization, this is not a performance problem.
180 * Finally, recursive definitions are not allowed (and without function
181 * definitions, they make no sense). Since it is difficult to discover
182 * complex recursive chains, a simple trick is used: if the depth of
183 * recursion is greater than a given threshold (configurable, currently
184 * {@value #DEFAULT_MAXDEPTH}, an error message is printed. This avoids to
185 * fill the stack, that results in an anonymous OutOfMemoryError. So, if
193 * you get an error message: Parameter "overlay.size": Probable recursive
194 * definition - exceeded maximum depth {@value #DEFAULT_MAXDEPTH}
198 * It is possible to obtain debug information about the configuration
199 * properties by activating special configuration properties.
201 * If property {@value #PAR_DEBUG} is defined, each config property and the
202 * associated value are printed. Properties that are not present in the
203 * config file but have default values are postfixed with the string
206 * If property {@value #PAR_DEBUG} is defined and it is equal to
207 * {@value #DEBUG_EXTENDED}, information about the configuration method
208 * invoked, and where this method is invoked, is also printed. If it is
209 * equal to {@value #DEBUG_FULL}, all the properties are printed, even if
212 * Each line printed by this debug feature is prefixed by the string
215 * <h3>Use of brackets</h3>
217 * For the sake of completeness, we mention it here that if this class is
218 * initialized using {@link ParsedProperties}, then it is possible to use
219 * some more compressed format to specify the components. See
220 * {@link ParsedProperties#load}.
223 public class Configuration
226 // =================== static fields =================================
227 // ===================================================================
229 /** Default max depth limit to avoid recursive definitions */
230 public static final int DEFAULT_MAXDEPTH = 100;
233 * The debug level for the configuration. If defined, a line is printed for
234 * each configuration parameter read. If defined and equal to
235 * {@value #DEBUG_EXTENDED}, additional context information for debug is
236 * printed. If defined and equal to {@value #DEBUG_FULL}, all the
237 * configuration properties are printed at the beginning, not just when
241 static final String PAR_DEBUG = "debug.config";
244 * If parameter {@value #PAR_DEBUG} is equal to this string, additional
245 * context information for debug is printed.
247 static final String DEBUG_EXTENDED = "context";
250 * If parameter {value #PAR_DEBUG} is equal to this string, all the
251 * configuration properties are printed at the beginning, not just when
254 static final String DEBUG_FULL = "full";
257 * The maximum depth for expressions. This is a simple mechanism to avoid
258 * unbounded recursion. The default is {@value #DEFAULT_MAXDEPTH}, and you
259 * probably don't want to change it.
262 static final String PAR_MAXDEPTH = "expressions.maxdepth";
265 * Used to configure ordering of the components. Determines the ordering in
266 * the array as returned by {@link #getNames}. See the general description
267 * of {@link Configuration} for details.
270 static final String PAR_ORDER = "order";
273 * Used to configure ordering of the components. Determines the ordering in
274 * the array as returned by {@link #getNames}, and can bu used to also
275 * exclude elements. See the general description of {@link Configuration}
279 static final String PAR_INCLUDE = "include";
281 // XXX it's ugly because it replicates the definition of Node.PAR_PROT, but
282 // this would be the only dependence on the rest of the core...
284 * The type name of components describing protocols. This is the only point
285 * at which the class is not blind to the actual semantics of the
288 static final String PAR_PROT = "protocol";
291 * The properties object that stores all configuration information.
293 private static ConfigContainer config = null;
295 // =================== initialization ================================
296 // ===================================================================
298 /** to prevent construction */
299 private Configuration()
303 // =================== static public methods =========================
304 // ===================================================================
307 * Sets the system-wide configuration in Properties format. It can be
308 * called only once. After that the configuration becomes unmodifiable
309 * (read only). If modification is attempted, a RuntimeException is thrown
310 * and no change is made.
312 * The Properties object containing configuration info
314 public static void setConfig(Properties p)
316 if (config != null) {
317 throw new RuntimeException("Setting configuration was attempted twice.");
319 config = new ConfigContainer(p, false);
322 // -------------------------------------------------------------------
325 * Sets the system-wide configuration in Properties format. It can be
326 * called only once. After that the configuration becomes unmodifiable
327 * (read only). If modification is attempted, a RuntimeException is thrown
328 * and no change is made.
330 * The Properties object containing configuration info
332 public static void setConfig(Properties p, boolean check)
334 if (config != null) {
335 throw new RuntimeException("Setting configuration was attempted twice.");
337 config = new ConfigContainer(p, check);
340 // -------------------------------------------------------------------
343 * @return true if and only if name is a specified (existing) property.
345 public static boolean contains(String name)
347 return config.contains(name);
350 // -------------------------------------------------------------------
353 * Reads given configuration property. If not found, throws a
354 * {@link MissingParameterException}.
356 * Name of configuration property
360 public static boolean getBoolean(String name, boolean def)
362 return config.getBoolean(name, def);
365 // -------------------------------------------------------------------
368 * Reads given property. If not found, or the value is empty string then
369 * throws a {@link MissingParameterException}. Empty string is not
370 * accepted as false due to the similar function of {@link #contains} which
371 * returns true in that case. True is returned if the lowercase value of
372 * the property is "true", otherwise false is returned.
374 * Name of configuration property
376 public static boolean getBoolean(String name)
378 return config.getBoolean(name);
381 // -------------------------------------------------------------------
384 * Reads given configuration property. If not found, returns the default
387 * Name of configuration property
391 public static int getInt(String name, int def)
393 return config.getInt(name, def);
396 // -------------------------------------------------------------------
399 * Reads given configuration property. If not found, throws a
400 * {@link MissingParameterException}.
402 * Name of configuration property
404 public static int getInt(String name)
406 return config.getInt(name);
409 // -------------------------------------------------------------------
412 * Reads given configuration property. If not found, returns the default
415 * Name of configuration property
419 public static long getLong(String name, long def)
421 return config.getLong(name, def);
424 // -------------------------------------------------------------------
427 * Reads given configuration property. If not found, throws a
428 * {@link MissingParameterException}.
430 * Name of configuration property
432 public static long getLong(String name)
434 return config.getLong(name);
437 // -------------------------------------------------------------------
440 * Reads given configuration property. If not found, returns the default
443 * Name of configuration property
447 public static double getDouble(String name, double def)
449 return config.getDouble(name, def);
452 // -------------------------------------------------------------------
455 * Reads given configuration property. If not found, throws a
456 * MissingParameterException.
458 * Name of configuration property
460 public static double getDouble(String name)
462 return config.getDouble(name);
465 // -------------------------------------------------------------------
468 * Reads given configuration property. If not found, returns the default
471 * Name of configuration property
475 public static String getString(String name, String def)
477 return config.getString(name, def);
480 // -------------------------------------------------------------------
483 * Reads given configuration property. If not found, throws a
484 * MissingParameterException. Removes trailing whitespace characters.
486 * Name of configuration property
488 public static String getString(String name)
490 return config.getString(name);
493 // -------------------------------------------------------------------
496 * Reads the given property from the configuration interpreting it as a
497 * protocol name. Returns the numeric protocol identifier of this protocol
498 * name. See the discussion of protocol name at {@link Configuration} for
499 * details on how this numeric id is calculated
502 * Name of configuration property
503 * @return the numeric protocol identifier associated to the value of the
506 public static int getPid(String name)
508 return config.getPid(name);
511 // -------------------------------------------------------------------
514 * Calls {@link #getPid(String)}, and returns the default if no property
515 * is defined with the given name.
518 * Name of configuration property
520 * the default protocol identifier
521 * @return the numeric protocol identifier associated to the value of the
522 * property, or the default if not defined
524 public static int getPid(String name, int pid)
526 return config.getPid(name, pid);
529 // -------------------------------------------------------------------
532 * Returns the numeric protocol identifier of the given protocol name.
536 * @return the numeric protocol identifier associated to the protocol name
538 public static int lookupPid(String protname)
540 return config.lookupPid(protname);
543 // -------------------------------------------------------------------
546 * Returns the name of a protocol that has the given identifier.
548 * Note that this is not a constant time operation in the number of
549 * protocols, although typically there are very few protocols defined.
552 * numeric protocol identifier.
553 * @return name of the protocol that has the given id. null if no protocols
556 public static String lookupPid(int pid)
558 return config.lookupPid(pid);
561 // -------------------------------------------------------------------
564 * Reads given configuration property. If not found, throws a
565 * {@link MissingParameterException}. When creating the Class object, a
566 * few attempts are done to resolve the classname. See
567 * {@link Configuration} for details.
569 * Name of configuration property
571 public static Class getClass(String name)
573 return config.getClass(name);
576 // -------------------------------------------------------------------
579 * Reads given configuration property. If not found, returns the default
582 * Name of configuration property
585 * @see #getClass(String)
587 public static Class getClass(String name, Class def)
589 return config.getClass(name, def);
592 // -------------------------------------------------------------------
595 * Reads given configuration property for a class name. It returns an
596 * instance of the class. The class must implement a constructor that takes
597 * a String as an argument. The value of this string will be <tt>name</tt>.
598 * The constructor of the class can see the configuration so it can make
599 * use of this name to read its own parameters from it.
601 * Name of configuration property
602 * @throws MissingParameterException
603 * if the given property is not defined
604 * @throws IllegalParameterException
605 * if there is any problem creating the instance
607 public static Object getInstance(String name)
609 return config.getInstance(name);
612 // -------------------------------------------------------------------
615 * Reads given configuration property for a class name. It returns an
616 * instance of the class. The class must implement a constructor that takes
617 * a String as an argument. The value of this string will be <tt>name</tt>.
618 * The constructor of the class can see the configuration so it can make
619 * use of this name to read its own parameters from it.
621 * Name of configuration property
623 * The default object that is returned if there is no property
624 * defined with the given name
625 * @throws IllegalParameterException
626 * if the given name is defined but there is a problem creating
629 public static Object getInstance(String name, Object def)
631 return config.getInstance(name, def);
634 // -------------------------------------------------------------------
637 * It returns an array of class instances. The instances are constructed by
638 * calling {@link #getInstance(String)} on the names returned by
639 * {@link #getNames(String)}.
641 * The component type (i.e. prefix of the list of configuration
642 * properties) which will be passed to {@link #getNames(String)}.
644 public static Object[] getInstanceArray(String name)
646 return config.getInstanceArray(name);
649 // -------------------------------------------------------------------
652 * Returns an array of names prefixed by the specified name. The array is
653 * sorted as follows. If there is no config entry
654 * <code>{@value #PAR_INCLUDE}+"."+name</code> or
655 * <code>{@value #PAR_ORDER}+"."+name</code> then the order is
656 * alphabetical. Otherwise this entry defines the order. For more
657 * information see {@link Configuration}.
659 * the component type (i.e., the prefix)
660 * @return the full property names in the order specified by the
663 public static String[] getNames(String name)
665 return config.getNames(name);