View Javadoc

1   /*
2    * Copyright (c) 1998-2002 The Jgroup Team.
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 jgroup.core;
20  
21  import java.io.File;
22  import java.net.MalformedURLException;
23  import java.net.URL;
24  import java.util.List;
25  
26  import jgroup.core.registry.RegistryFactory;
27  import jgroup.core.registry.RegistryLocator;
28  import jgroup.relacs.config.BootstrapRegistryConfig;
29  import jgroup.relacs.config.ConfigParser;
30  import jgroup.relacs.config.DistributedSystemConfig;
31  import jgroup.util.Network;
32  import jgroup.util.Util;
33  
34  import org.apache.log4j.LogManager;
35  import org.apache.log4j.joran.JoranConfigurator;
36  
37  /**
38   *  The configuration manager class is used initialize the required
39   *  Jgroup system configuration data, including logging configuration.
40   *  It will read the logging configuration and the Jgroup system
41   *  configuration, by parsing the XML files supplied to the JVM using
42   *  the following system properties: <p>
43   *
44   *  <code>jgroup.system.config</code>: XML-based configuration file for
45   *  specifying the required system configurations for Jgroup/ARM.
46   *  <p>
47   *
48   *  <code>jgroup.system.services</code>: XML-based configuration file for
49   *  specifying the services required for Jgroup/ARM.
50   *  <p>
51   *
52   *  <code>jgroup.system.applications</code>: XML-based configuration file for
53   *  specifying the applications used in a Jgroup/ARM system.
54   *  <p>
55   *
56   *  <code>jgroup.log.config</code>: XML-based configuration file for
57   *  log4j, allows the user to limit the amount of debug information
58   *  being sent to the console; among numerous other configuration
59   *  options available through the log4j toolkit.  For details concerning
60   *  the format of the configuration file, please refer to the log4j
61   *  documentation.  The default for this property: 
62   *  <code>config/log4j.xml</code>
63   *  <p>
64   *
65   *  In addition, the following logging related system properties may be
66   *  specified by the user: <p>
67   * 
68   *  <code>jgroup.registry.locator</code>: The registry locator class to be used
69   *  by Jgroup.  The default is <code>jgroup.relacs.registry.RelacsRegistryLocator</code>
70   *  <p>
71   * 
72   *  <code>jgroup.log.app</code>: The application name that will be appended
73   *  to the log filename.  Note that, when using the ARM framework (the
74   *  <code>ExecDaemon</code>) to create replicas, the log.app name for the
75   *  replica will be given the name of the class (exclusive the package name).
76   *  <p>
77   *
78   *  <code>jgroup.log.dir</code>: The directory into which log files will be
79   *  written.  If not specified, the default is used (<code>./log</code>)
80   *  <p>
81   *
82   *  <code>jgroup.log.msgcontent</code>: True/False.  Used to turn on/off
83   *  the logging of message content at both the mss and daemon level.
84   *  <p>
85   * 
86   *  The following system properties are initialized at runtime, allowing the
87   *  log4j toolkit to use these properties in its XML based log file for
88   *  constructing unique files.  Passing these properties to the Java runtime
89   *  will have no effect as they will be overwritten. <p>
90   *
91   *  <code>jgroup.log.machine</code>: The local host of this replica.
92   *  <p>
93   * 
94   *  <code>jgroup.log.time</code>: The time when this replica was initialized. 
95   *  <p>
96   * 
97   *  <code>jgroup.log.date</code>: The date when this replica was initialized.
98   *  <p>
99   *
100  *  @author Hein Meling
101  *  @since Jgroup 1.2
102  */
103 public final class ConfigManager
104 {
105 
106   public static final String DEFAULT_REGISTRY_LOCATOR    = "jgroup.relacs.registry.RelacsRegistryLocator";
107   public static final String DEFAULT_REPLICATION_MANAGER = "jgroup.arm.ReplicaManagerImpl";
108 
109   private static final String DEFAULT_SYSTEM_CONFIG       = "file:target/classes/siteconfig/lx-config.xml";
110   private static final String DEFAULT_SYSTEM_SERVICES     = "file:target/classes/config/services.xml";
111   private static final String DEFAULT_SYSTEM_APPLICATIONS = "file:target/classes/config/applications.xml";
112   private static final String DEFAULT_LOGGING_CONFIG      = "file:target/classes/logging/log4j.xml";
113   private static final String DEFAULT_LOG_DIR             = File.separator + "tmp" + File.separator + "jgroup-logs";
114 
115 
116   /** 
117    *  Indicates if message content should be logged.  To change this
118    *  use the system property: <code>jgroup.log.msgcontent</code>.
119    */
120   public static boolean logMsgContent = false;
121 
122   /**
123    *  Variable used to avoid duplicate reading/parsing of the
124    *  configuration files.  That is to make the init methods idempotent.
125    */
126   private static boolean initialized = false;
127 
128   /**
129    * Variable used to avoid duplicate reading/initialization of the
130    * logging configuration.  That is to make the configureLogging method
131    * idempotent.
132    */
133   private static boolean logInitialized = false;
134 
135   /** The port used by the bootstrap registry */
136   private static int bootstrapPort;
137 
138   /** The distributed system configuration object */
139   private static DistributedSystemConfig dsc;
140 
141 
142   ////////////////////////////////////////////////////////////////////////////////////////////
143   // Public static methods
144   ////////////////////////////////////////////////////////////////////////////////////////////
145 
146   /**
147    *  Invoked to initialize various system configuration variables
148    *  required by Jgroup/ARM.  This includes reading and parsing the
149    *  logging configuration and the distributed system configuration.
150    *
151    *  The method is idempotent (it can be invoked many times without
152    *  changing its behavior), meaning that no configuration files will
153    *  be read and parsed several times.
154    *
155    *  @exception ConfigurationException
156    *    Raised if there was an error parsing the configuration files,
157    *    or the system properties required to specify the configuration
158    *    file names were unset.
159    */
160   public static void init()
161     throws ConfigurationException
162   {
163     configureLogging();
164     String urlConfig = System.getProperty("jgroup.system.config", DEFAULT_SYSTEM_CONFIG);
165     init(urlConfig);
166   }
167 
168 
169   /**
170    * Helper method to parse a specified configuration file instead of the
171    * system configured default.  This is useful for the Java based experiment
172    * framework.
173    *
174    * @param urlConfig
175    * @throws ConfigurationException
176    */
177   public static void init(String urlConfig)
178     throws ConfigurationException
179   {
180     if (initialized)
181       return;
182     initialized = true;
183 
184     /*
185      * Parse the given URL (should be either a distributed system config
186      * or an experiment config; the latter will invoke the parser again
187      * to obtain the distributed system config.)
188      */
189     ConfigParser.parse(urlConfig);
190     /*
191      * Parse the service and application configuration. Multiple services and applications 
192      * configuration files can be specified and separated by comma.
193      */
194     urlConfig = System.getProperty("jgroup.system.services", DEFAULT_SYSTEM_SERVICES);
195     String urlConfigs[] = urlConfig.split(",");
196     for (int i=0; i < urlConfigs.length; i++) {
197       ConfigParser.parse(urlConfigs[i]);
198     }
199     urlConfig = System.getProperty("jgroup.system.applications", DEFAULT_SYSTEM_APPLICATIONS);
200     urlConfigs = urlConfig.split(",");
201     for (int i=0; i < urlConfigs.length; i++) {
202       ConfigParser.parse(urlConfigs[i]);      
203     }
204     setRegistryLocator();
205     BootstrapRegistryConfig brc = 
206       (BootstrapRegistryConfig) ConfigParser.getConfig(BootstrapRegistryConfig.class);
207     bootstrapPort = brc.getPort();
208     dsc = (DistributedSystemConfig) ConfigParser.getConfig(DistributedSystemConfig.class);
209   }
210 
211 
212   /**
213    * Method to set up log directory, and initialize the Log4j configuration.
214    * This can be used externally when custom configuration is required, such
215    * as the experiment framework.
216    *
217    * @throws ConfigurationException
218    *   Thrown if the specified log directory could not be created, or
219    *   if the log4j configuration URL was malformed.
220    */
221   public static void configureLogging()
222     throws ConfigurationException
223   {
224     if (logInitialized)
225       return;
226     logInitialized = true;
227 
228     /*
229      * Get the directory in which log files should be stored;
230      * if the directory does not exist, it is created.
231      */
232     String logDir = System.getProperty("jgroup.log.dir", DEFAULT_LOG_DIR);
233     File dir = new File(logDir);
234     if (!dir.exists()) {
235       /* Directory does not exist; create it. */
236       if (!dir.mkdir())
237         throw new ConfigurationException("Could not create the specified log directory: " + logDir);
238     }
239     /*
240      * Check if the application name is defined; if not 'noapp' is
241      * set to this property so that log4j use that when constructing
242      * the logging filenames.
243      */
244     String logApp = System.getProperty("jgroup.log.app");
245     if (logApp == null || logApp.length() == 0) {
246       System.setProperty("jgroup.log.app", "noapp");
247     }
248     /*
249      * Obtain the property used to set if the message content should be logged.
250      */
251     logMsgContent = Boolean.getBoolean("jgroup.log.msgcontent");
252     /* 
253      * Set the values for the local machine, date and time when the Jgroup 
254      * related application was initialized.  These values can be used in the
255      * log4j.xml file to avoid overwriting the log files of concurrently
256      * running applications on the same host.  The can be used along with the
257      * app property defined above.
258      */
259     System.setProperty("jgroup.log.machine", Network.getLocalMachineName());
260     System.setProperty("jgroup.log.time", Util.getTimeString());
261     System.setProperty("jgroup.log.date", Util.getDateString());
262     /*
263      * Initialize and parse the log4j configuration file.
264      */
265     String logConfig = System.getProperty("jgroup.log.config", DEFAULT_LOGGING_CONFIG);
266     // JoranConfigurator requires log4j version 1.3
267     JoranConfigurator jc = new JoranConfigurator();
268     try {
269       jc.doConfigure(new URL(logConfig), LogManager.getLoggerRepository());
270     } catch (MalformedURLException e) {
271       throw new ConfigurationException("Bad URL provided for log4j configuration: " + logConfig, e);
272     }
273     List errorList = jc.getErrorList();
274     for (int i = 0; i < errorList.size(); i++) {
275       System.out.println(errorList.get(i));
276     }
277   }
278 
279   /**
280    * Set the registry to use based on a system property, 
281    * jgroup.registry. Default is DependableRegistry.
282    * 
283    * @exception ConfigurationException
284    *   Raised if unable to create the registry.
285    */
286   private static void setRegistryLocator()
287     throws ConfigurationException
288   {
289     String locatorName = System.getProperty("jgroup.registry", DEFAULT_REGISTRY_LOCATOR);
290     try {
291       Class clazz = Class.forName(locatorName);
292       RegistryLocator locator = (RegistryLocator) clazz.newInstance();
293       RegistryFactory.setLocator(locator);
294     } catch (ClassNotFoundException e) {
295       throw new ConfigurationException("Registry locator class not found: " + locatorName);
296     } catch (InstantiationException e) {
297       throw new ConfigurationException("Could not instanstiate: " + locatorName);
298     } catch (IllegalAccessException e) {
299       throw new ConfigurationException("Illegal access to : " + locatorName);
300     }
301   }
302 
303 
304   /**
305    *  Retrieve an instance of the given configuration class, that is
306    *  containing the configuration information.  For example, the
307    *  configuration data object associated with the XML tag
308    *  <code>Transport</code>, can be retreived using the class literal
309    *  <code>TransportConfig.class</code>.
310    *
311    *  @param cl
312    *    The class literal of the configuration object to retreive.
313    *  @return 
314    *    An instance of the configuration object retreived.
315    *
316    *  @exception NullPointerException
317    *    If there is no such configuration object in the internal
318    *    configuration map.  This may occur for two reasons; (i) there
319    *    is no such configuration tag specified in the configuration file,
320    *    or (ii) the specified class literal is a non-existant class.
321    *  @exception IllegalStateException
322    *    If the init method was not invoked prior to invoking this method.
323    */
324   public static Object getConfig(Class cl)
325   {
326     return ConfigParser.getConfig(cl);
327   }
328 
329 
330   /**
331    *  Returns the <code>DistributedSystemConfig</code> object.
332    */
333   public static DistributedSystemConfig getDistributedSystem()
334   {
335     return dsc;
336   }
337 
338 
339   /**
340    *  Returns the port for the bootstrap registry.
341    */
342   public static int getBootstrapPort()
343   {
344     return bootstrapPort;
345   }
346 
347 } // END ConfigManager