Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
peersimgrid release 1.0
[simgrid.git] / contrib / psg / src / peersim / config / Configuration.java
1 /*
2  * Copyright (c) 2003-2005 The BISON Project
3  *
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.
7  *
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.
12  *
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.
16  *
17  */
18
19 package peersim.config;
20
21 import java.util.*;
22
23 /**
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.
30  * <p>
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.
34  * <p>
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.
41  * <p>
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>
53  * 
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.
64  * 
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.
76  * 
77  * <p>
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,
84  * 
85  * <pre>
86  *   control.conn ConnectivityObserver
87  *   control.1 WireKOut
88  *   control.2 PrintGraph
89  * </pre>
90  * 
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
98  * way.
99  * 
100  * <pre>
101  *   order.control 1,conn,2
102  * </pre>
103  * 
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.
107  * 
108  * <pre>
109  *   order.control 2
110  * </pre>
111  * 
112  * results in <code>["control.2","control.1","control.conn"]</code>.
113  * <p>
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
117  * 
118  * <pre>
119  *   include.control conn 2
120  * </pre>
121  * 
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.
138  * <p>
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>.
144  * For example,
145  * 
146  * <pre>
147  *   MAG 2
148  *   SIZE 2&circ;MAG
149  * </pre>
150  * 
151  * SIZE=4. You can also have complex expression trees like this:
152  * 
153  * <pre>
154  *   A B+C
155  *   B D+E
156  *   C E+F
157  *   D 1
158  *   E F
159  *   F 2
160  * </pre>
161  * 
162  * that results in A=7, B=3, C=4, D=1, E=2, F=2
163  * 
164  * <p>
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.
172  * 
173  * <p>
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.
178  * 
179  * <p>
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
186  * you write
187  * 
188  * <pre>
189  *   overlay.size SIZE
190  *   SIZE SIZE-1
191  * </pre>
192  * 
193  * you get an error message: Parameter "overlay.size": Probable recursive
194  * definition - exceeded maximum depth {@value #DEFAULT_MAXDEPTH}
195  * 
196  * <h3>Debug</h3>
197  * 
198  * It is possible to obtain debug information about the configuration
199  * properties by activating special configuration properties.
200  * <p>
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
204  * "(DEFAULT)".
205  * <p>
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
210  * they are not read.
211  * <p>
212  * Each line printed by this debug feature is prefixed by the string
213  * "DEBUG".
214  * 
215  * <h3>Use of brackets</h3>
216  * 
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}.
221  * 
222  */
223 public class Configuration
224 {
225
226 // =================== static fields =================================
227 // ===================================================================
228
229 /** Default max depth limit to avoid recursive definitions */
230 public static final int DEFAULT_MAXDEPTH = 100;
231
232 /**
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
238  * they are called.
239  * @config
240  */
241 static final String PAR_DEBUG = "debug.config";
242
243 /**
244  * If parameter {@value #PAR_DEBUG} is equal to this string, additional
245  * context information for debug is printed.
246  */
247 static final String DEBUG_EXTENDED = "context";
248
249 /**
250  * If parameter {value #PAR_DEBUG} is equal to this string, all the
251  * configuration properties are printed at the beginning, not just when
252  * they are called.
253  */
254 static final String DEBUG_FULL = "full";
255
256 /**
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.
260  * @config
261  */
262 static final String PAR_MAXDEPTH = "expressions.maxdepth";
263
264 /**
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.
268  * @config
269  */
270 static final String PAR_ORDER = "order";
271
272 /**
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}
276  * for details.
277  * @config
278  */
279 static final String PAR_INCLUDE = "include";
280
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...
283 /**
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
286  * configuration.
287  */
288 static final String PAR_PROT = "protocol";
289
290 /**
291  * The properties object that stores all configuration information.
292  */
293 private static ConfigContainer config = null;
294
295 // =================== initialization ================================
296 // ===================================================================
297
298 /** to prevent construction */
299 private Configuration()
300 {
301 }
302
303 // =================== static public methods =========================
304 // ===================================================================
305
306 /**
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.
311  * @param p
312  *          The Properties object containing configuration info
313  */
314 public static void setConfig(Properties p)
315 {
316         if (config != null) {
317                 throw new RuntimeException("Setting configuration was attempted twice.");
318         }
319         config = new ConfigContainer(p, false);
320 }
321
322 // -------------------------------------------------------------------
323
324 /**
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.
329  * @param p
330  *          The Properties object containing configuration info
331  */
332 public static void setConfig(Properties p, boolean check)
333 {
334         if (config != null) {
335                 throw new RuntimeException("Setting configuration was attempted twice.");
336         }
337         config = new ConfigContainer(p, check);
338 }
339
340 // -------------------------------------------------------------------
341
342 /**
343  * @return true if and only if name is a specified (existing) property.
344  */
345 public static boolean contains(String name)
346 {
347         return config.contains(name);
348 }
349
350 // -------------------------------------------------------------------
351
352 /**
353  * Reads given configuration property. If not found, throws a
354  * {@link MissingParameterException}.
355  * @param name
356  *          Name of configuration property
357  * @param def
358  *          default value
359  */
360 public static boolean getBoolean(String name, boolean def)
361 {
362         return config.getBoolean(name, def);
363 }
364
365 // -------------------------------------------------------------------
366
367 /**
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.
373  * @param name
374  *          Name of configuration property
375  */
376 public static boolean getBoolean(String name)
377 {
378         return config.getBoolean(name);
379 }
380
381 // -------------------------------------------------------------------
382
383 /**
384  * Reads given configuration property. If not found, returns the default
385  * value.
386  * @param name
387  *          Name of configuration property
388  * @param def
389  *          default value
390  */
391 public static int getInt(String name, int def)
392 {
393         return config.getInt(name, def);
394 }
395
396 // -------------------------------------------------------------------
397
398 /**
399  * Reads given configuration property. If not found, throws a
400  * {@link MissingParameterException}.
401  * @param name
402  *          Name of configuration property
403  */
404 public static int getInt(String name)
405 {
406         return config.getInt(name);
407 }
408
409 // -------------------------------------------------------------------
410
411 /**
412  * Reads given configuration property. If not found, returns the default
413  * value.
414  * @param name
415  *          Name of configuration property
416  * @param def
417  *          default value
418  */
419 public static long getLong(String name, long def)
420 {
421         return config.getLong(name, def);
422 }
423
424 // -------------------------------------------------------------------
425
426 /**
427  * Reads given configuration property. If not found, throws a
428  * {@link MissingParameterException}.
429  * @param name
430  *          Name of configuration property
431  */
432 public static long getLong(String name)
433 {
434         return config.getLong(name);
435 }
436
437 // -------------------------------------------------------------------
438
439 /**
440  * Reads given configuration property. If not found, returns the default
441  * value.
442  * @param name
443  *          Name of configuration property
444  * @param def
445  *          default value
446  */
447 public static double getDouble(String name, double def)
448 {
449         return config.getDouble(name, def);
450 }
451
452 // -------------------------------------------------------------------
453
454 /**
455  * Reads given configuration property. If not found, throws a
456  * MissingParameterException.
457  * @param name
458  *          Name of configuration property
459  */
460 public static double getDouble(String name)
461 {
462         return config.getDouble(name);
463 }
464
465 // -------------------------------------------------------------------
466
467 /**
468  * Reads given configuration property. If not found, returns the default
469  * value.
470  * @param name
471  *          Name of configuration property
472  * @param def
473  *          default value
474  */
475 public static String getString(String name, String def)
476 {
477         return config.getString(name, def);
478 }
479
480 // -------------------------------------------------------------------
481
482 /**
483  * Reads given configuration property. If not found, throws a
484  * MissingParameterException. Removes trailing whitespace characters.
485  * @param name
486  *          Name of configuration property
487  */
488 public static String getString(String name)
489 {
490         return config.getString(name);
491 }
492
493 // -------------------------------------------------------------------
494
495 /**
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
500  * 
501  * @param name
502  *          Name of configuration property
503  * @return the numeric protocol identifier associated to the value of the
504  *         property
505  */
506 public static int getPid(String name)
507 {
508         return config.getPid(name);
509 }
510
511 // -------------------------------------------------------------------
512
513 /**
514  * Calls {@link #getPid(String)}, and returns the default if no property
515  * is defined with the given name.
516  * 
517  * @param name
518  *          Name of configuration property
519  * @param pid
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
523  */
524 public static int getPid(String name, int pid)
525 {       
526         return config.getPid(name, pid);
527 }
528
529 // -------------------------------------------------------------------
530
531 /**
532  * Returns the numeric protocol identifier of the given protocol name.
533  * 
534  * @param protname
535  *          the protocol name.
536  * @return the numeric protocol identifier associated to the protocol name
537  */
538 public static int lookupPid(String protname)
539 {
540         return config.lookupPid(protname);
541 }
542
543 // -------------------------------------------------------------------
544
545 /**
546  * Returns the name of a protocol that has the given identifier.
547  * <p>
548  * Note that this is not a constant time operation in the number of
549  * protocols, although typically there are very few protocols defined.
550  * 
551  * @param pid
552  *          numeric protocol identifier.
553  * @return name of the protocol that has the given id. null if no protocols
554  *         have the given id.
555  */
556 public static String lookupPid(int pid)
557 {
558         return config.lookupPid(pid);
559 }
560
561 // -------------------------------------------------------------------
562
563 /**
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.
568  * @param name
569  *          Name of configuration property
570  */
571 public static Class getClass(String name)
572 {
573         return config.getClass(name);
574 }
575
576 // -------------------------------------------------------------------
577
578 /**
579  * Reads given configuration property. If not found, returns the default
580  * value.
581  * @param name
582  *          Name of configuration property
583  * @param def
584  *          default value
585  * @see #getClass(String)
586  */
587 public static Class getClass(String name, Class def)
588 {
589         return config.getClass(name, def);
590 }
591
592 // -------------------------------------------------------------------
593
594 /**
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.
600  * @param name
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
606  */
607 public static Object getInstance(String name)
608 {
609         return config.getInstance(name);
610 }
611
612 // -------------------------------------------------------------------
613
614 /**
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.
620  * @param name
621  *          Name of configuration property
622  * @param def
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
627  *           the instance.
628  */
629 public static Object getInstance(String name, Object def)
630 {
631         return config.getInstance(name, def);
632 }
633
634 // -------------------------------------------------------------------
635
636 /**
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)}.
640  * @param name
641  *          The component type (i.e. prefix of the list of configuration
642  *          properties) which will be passed to {@link #getNames(String)}.
643  */
644 public static Object[] getInstanceArray(String name)
645 {
646         return config.getInstanceArray(name);
647 }
648
649 // -------------------------------------------------------------------
650
651 /**
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}.
658  * @param name
659  *          the component type (i.e., the prefix)
660  * @return the full property names in the order specified by the
661  *         configuration
662  */
663 public static String[] getNames(String name)
664 {
665         return config.getNames(name);
666 }
667
668 }