001: /*
002: * $Id: ConfigManager.java,v 1.60 2007/09/18 08:45:05 agoubard Exp $
003: *
004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
005: * See the COPYRIGHT file for redistribution and use restrictions.
006: */
007: package org.xins.server;
008:
009: import java.io.File;
010: import java.io.FileInputStream;
011: import java.io.FileNotFoundException;
012: import java.io.IOException;
013: import java.io.InputStream;
014: import java.net.URL;
015: import java.util.Enumeration;
016: import java.util.Iterator;
017: import java.util.Properties;
018: import java.util.StringTokenizer;
019:
020: import javax.servlet.ServletConfig;
021:
022: import org.apache.log4j.LogManager;
023: import org.apache.log4j.PropertyConfigurator;
024: import org.apache.log4j.helpers.NullEnumeration;
025:
026: import org.xins.common.MandatoryArgumentChecker;
027: import org.xins.common.Utils;
028: import org.xins.common.collections.InvalidPropertyValueException;
029: import org.xins.common.collections.PropertiesPropertyReader;
030: import org.xins.common.collections.PropertyReader;
031: import org.xins.common.collections.PropertyReaderUtils;
032: import org.xins.common.collections.StatsPropertyReader;
033: import org.xins.common.collections.UniqueProperties;
034: import org.xins.common.io.FileWatcher;
035: import org.xins.common.io.HTTPFileWatcher;
036: import org.xins.common.text.TextUtils;
037: import org.xins.logdoc.LogCentral;
038: import org.xins.logdoc.UnsupportedLocaleException;
039:
040: /**
041: * Manager for the runtime configuration file. Owns the watcher for the config
042: * file and is responsible for triggering actions when the file has actually
043: * changed.
044: *
045: * @version $Revision: 1.60 $ $Date: 2007/09/18 08:45:05 $
046: * @author <a href="mailto:mees.witteman@orange-ftgroup.com">Mees Witteman</a>
047: * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a>
048: * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a>
049: */
050: final class ConfigManager {
051:
052: /**
053: * The name of the system property that specifies the location of the
054: * configuration file.
055: */
056: static final String CONFIG_FILE_SYSTEM_PROPERTY = "org.xins.server.config";
057:
058: /**
059: * The name of the runtime property that specifies the interval
060: * for the configuration file modification checks, in seconds.
061: */
062: static final String CONFIG_RELOAD_INTERVAL_PROPERTY = "org.xins.server.config.reload";
063:
064: /**
065: * The name of the runtime property that specifies the list of runtime
066: * properties file to include. The paths must be relative to the
067: * current config file.
068: */
069: static final String CONFIG_INCLUDE_PROPERTY = "org.xins.server.config.include";
070:
071: /**
072: * The default configuration file modification check interval, in seconds.
073: */
074: static final int DEFAULT_CONFIG_RELOAD_INTERVAL = 60;
075:
076: // XXX: Consider adding state checking
077: /**
078: * The object to synchronize on when reading and initializing from the
079: * runtime configuration file.
080: */
081: private static final Object RUNTIME_PROPERTIES_LOCK = new Object();
082:
083: /**
084: * The <code>Engine</code> that owns this <code>ConfigManager</code>. Never
085: * <code>null</code>.
086: */
087: private final Engine _engine;
088:
089: /**
090: * Servlet configuration. Never <code>null</code>.
091: */
092: private final ServletConfig _config;
093:
094: /**
095: * The listener that is notified when the configuration file changes. Only
096: * one instance is created ever.
097: */
098: private final ConfigurationFileListener _configFileListener;
099:
100: /**
101: * The name of the runtime configuration file. Initially <code>null</code>.
102: */
103: private String _configFile;
104:
105: /**
106: * The name of the all runtime configuration files included in the main config file.
107: * Can be <code>null</code> or empty.
108: */
109: private String[] _configFiles;
110:
111: /**
112: * The String representation of the config files. Initialy <code>null</code>.
113: */
114: private String _configFilesPath;
115:
116: /**
117: * Watcher for the runtime configuration file. Initially <code>null</code>.
118: */
119: private FileWatcher _configFileWatcher;
120:
121: /**
122: * The set of properties read from the runtime configuration file. Never
123: * <code>null</code>.
124: */
125: private StatsPropertyReader _runtimeProperties;
126:
127: /**
128: * Flag indicating that the runtime properties were read correcly.
129: */
130: private boolean _propertiesRead;
131:
132: /**
133: * Constructs a new <code>ConfigManager</code> object.
134: *
135: * @param engine
136: * the {@link Engine} that owns this <code>ConfigManager</code>, cannot
137: * be <code>null</code>.
138: *
139: * @param config
140: * the servlet configuration, cannot be <code>null</code>.
141: *
142: * @throws IllegalArgumentException
143: * if <code>engine == null || config == null</code>.
144: */
145: ConfigManager(Engine engine, ServletConfig config)
146: throws IllegalArgumentException {
147:
148: // Check preconditions
149: MandatoryArgumentChecker.check("engine", engine, "config",
150: config);
151:
152: // Initialize fields
153: _engine = engine;
154: _config = config;
155: _configFileListener = new ConfigurationFileListener();
156: }
157:
158: /**
159: * Initializes the logging subsystem with fallback default settings.
160: */
161: static void configureLoggerFallback() {
162:
163: Properties settings = new Properties();
164:
165: // Send all log messages to the logger named 'console'
166: settings.setProperty("log4j.rootLogger", "ALL, console");
167:
168: // Define an appender for the console
169: settings.setProperty("log4j.appender.console",
170: "org.apache.log4j.ConsoleAppender");
171:
172: // Use a pattern-layout for the appender
173: settings.setProperty("log4j.appender.console.layout",
174: "org.apache.log4j.PatternLayout");
175:
176: // Define the pattern for the appender
177: settings.setProperty(
178: "log4j.appender.console.layout.ConversionPattern",
179: "%6c{1} %-6p %x %m%n");
180:
181: // Do not show the debug logs produced by XINS.
182: settings.setProperty("log4j.logger.org.xins.", "INFO");
183:
184: // Perform Log4J configuration
185: PropertyConfigurator.configure(settings);
186: }
187:
188: /**
189: * Determines the name of the runtime configuration file. The system
190: * properties will be queried first. If they do not provide it, then the
191: * servlet initialization properties are tried. Once determined, the name
192: * will be stored internally.
193: */
194: void determineConfigFile() {
195:
196: // Get the value of the appropriate system property
197: String configFile = null;
198: try {
199: configFile = System
200: .getProperty(CONFIG_FILE_SYSTEM_PROPERTY);
201: } catch (SecurityException exception) {
202: Log.log_3230(exception, CONFIG_FILE_SYSTEM_PROPERTY);
203: }
204:
205: // If the name of the configuration file is not set in a system property
206: // (typically passed on the command-line) try to get it from the servlet
207: // initialization properties (typically set in a web.xml file)
208: if (configFile == null || configFile.length() < 1) {
209: Log.log_3231(CONFIG_FILE_SYSTEM_PROPERTY);
210: configFile = _config
211: .getInitParameter(CONFIG_FILE_SYSTEM_PROPERTY);
212: }
213:
214: // Store the name of the configuration file
215: _configFile = configFile;
216: }
217:
218: /**
219: * Unifies the file separator character on the _configFile property and then
220: * reads the runtime properties file, initializes the logging subsystem
221: * with the read properties and then stores those properties on the engine.
222: * If the _configFile is empty, then an empty set of properties is set on
223: * the engine.
224: */
225: void readRuntimeProperties() {
226:
227: UniqueProperties properties = new UniqueProperties();
228: InputStream in = null;
229:
230: // If the value is not set only localhost can access the API.
231: // NOTE: Don't trim the configuration file name, since it may start
232: // with a space or other whitespace character.
233: if (_configFile == null) {
234:
235: // Try to find a xins.properties file in the WEB-INF directory
236: in = _engine
237: .getResourceAsStream("/WEB-INF/xins.properties");
238: if (in == null) {
239:
240: // Use the default settings
241: Log.log_3205(CONFIG_FILE_SYSTEM_PROPERTY);
242: _runtimeProperties = null;
243: _propertiesRead = true;
244: return;
245: } else {
246: Log.log_3248();
247: }
248: }
249:
250: boolean propertiesRead = false;
251: _configFilesPath = _configFile;
252:
253: synchronized (ConfigManager.RUNTIME_PROPERTIES_LOCK) {
254:
255: try {
256: if (in != null) {
257: properties.load(in);
258: in.close();
259: } else if (!_configFile.startsWith("http://")
260: && !_configFile.startsWith("https://")) {
261:
262: // Unify the file separator character
263: _configFile = _configFile.replace('/',
264: File.separatorChar);
265: _configFile = _configFile.replace('\\',
266: File.separatorChar);
267:
268: properties = readLocalRuntimeProperties();
269: } else {
270: properties = readHTTPRuntimeProperties();
271: }
272: propertiesRead = true;
273:
274: // Security issue
275: } catch (SecurityException exception) {
276: Log.log_3302(exception, _configFilesPath);
277:
278: // No such file
279: } catch (FileNotFoundException exception) {
280: String detail = TextUtils.trim(exception.getMessage(),
281: null);
282: Log.log_3301(_configFilesPath, detail);
283:
284: // Other I/O error
285: } catch (IOException exception) {
286: Log.log_3303(exception, _configFilesPath);
287: }
288:
289: // Initialize the logging subsystem
290: Log.log_3300(_configFilesPath);
291:
292: // Attempt to configure Log4J
293: configureLogger(properties);
294:
295: if (!properties.isUnique()) {
296: Log.log_3311(_configFilesPath);
297: propertiesRead = false;
298: }
299:
300: if (propertiesRead) {
301:
302: // Convert to a PropertyReader
303: PropertyReader pr = new PropertiesPropertyReader(
304: properties);
305: _runtimeProperties = new StatsPropertyReader(pr);
306: }
307: _propertiesRead = propertiesRead;
308: }
309: }
310:
311: /**
312: * Read the runtime properties files when files are specified locally.
313: *
314: * @return
315: * The runtime properties read from the files, never <code>null</code>.
316: *
317: * @throws IOException
318: * if the file cannot be found or be read.
319: */
320: private UniqueProperties readLocalRuntimeProperties()
321: throws IOException {
322: UniqueProperties properties = new UniqueProperties();
323: InputStream in = null;
324: try {
325:
326: // Open file, load properties, close file
327: in = new FileInputStream(_configFile);
328: properties.load(in);
329:
330: // Read the included files
331: if (properties.getProperty(CONFIG_INCLUDE_PROPERTY) != null
332: && !properties.getProperty(CONFIG_INCLUDE_PROPERTY)
333: .trim().equals("")) {
334: StringTokenizer stInclude = new StringTokenizer(
335: properties.getProperty(CONFIG_INCLUDE_PROPERTY),
336: ",");
337: File baseFile = new File(_configFile).getParentFile();
338: _configFiles = new String[stInclude.countTokens() + 1];
339: _configFiles[0] = _configFile;
340: _configFilesPath += "+ [";
341: int i = 0;
342: while (stInclude.hasMoreTokens()) {
343: String nextInclude = stInclude.nextToken().trim()
344: .replace('/', File.separatorChar).replace(
345: '\\', File.separatorChar);
346: File includeFile = new File(baseFile, nextInclude);
347: FileInputStream isInclude = new FileInputStream(
348: includeFile);
349: properties.load(isInclude);
350: isInclude.close();
351: _configFiles[i + 1] = nextInclude;
352: _configFilesPath += nextInclude + ";";
353: i++;
354: }
355: _configFilesPath += "]";
356: } else {
357: _configFiles = new String[1];
358: _configFiles[0] = _configFile;
359: }
360:
361: // Always close the input stream
362: } finally {
363: if (in != null) {
364: try {
365: in.close();
366: } catch (Throwable exception) {
367: Utils.logIgnoredException(exception);
368: }
369: }
370: }
371: return properties;
372: }
373:
374: /**
375: * Read the runtime properties files when files are specified locally.
376: *
377: * @return
378: * The runtime properties read from the URLs, never <code>null</code>.
379: *
380: * @throws IOException
381: * if the URL cannot be created or if the connection to the URL failed.
382: */
383: private UniqueProperties readHTTPRuntimeProperties()
384: throws IOException {
385: UniqueProperties properties = new UniqueProperties();
386: InputStream in = null;
387: try {
388:
389: // Open file, load properties, close file
390: URL configURL = new URL(_configFile);
391: in = configURL.openStream();
392: properties.load(in);
393:
394: // Read the included files
395: if (properties.getProperty(CONFIG_INCLUDE_PROPERTY) != null
396: && !properties.getProperty(CONFIG_INCLUDE_PROPERTY)
397: .trim().equals("")) {
398: StringTokenizer stInclude = new StringTokenizer(
399: properties.getProperty(CONFIG_INCLUDE_PROPERTY),
400: ",");
401: _configFiles = new String[stInclude.countTokens() + 1];
402: _configFiles[0] = _configFile;
403: _configFilesPath += "+ [";
404: int i = 0;
405: while (stInclude.hasMoreTokens()) {
406: String nextInclude = stInclude.nextToken().trim()
407: .replace('/', File.separatorChar).replace(
408: '\\', File.separatorChar);
409: URL includeFile = new URL(configURL, nextInclude);
410: InputStream isInclude = includeFile.openStream();
411: properties.load(isInclude);
412: isInclude.close();
413: _configFiles[i + 1] = nextInclude;
414: _configFilesPath += nextInclude + ";";
415: i++;
416: }
417: _configFilesPath += "]";
418: } else {
419: _configFiles = new String[1];
420: _configFiles[0] = _configFile;
421: }
422:
423: // Always close the input stream
424: } finally {
425: if (in != null) {
426: try {
427: in.close();
428: } catch (Throwable exception) {
429: Utils.logIgnoredException(exception);
430: }
431: }
432: }
433: return properties;
434: }
435:
436: /**
437: * Gets the runtime properties.
438: *
439: * @return
440: * the runtime properties, never <code>null</code>.
441: */
442: PropertyReader getRuntimeProperties() {
443: if (_runtimeProperties == null) {
444: return PropertyReaderUtils.EMPTY_PROPERTY_READER;
445: } else {
446: return _runtimeProperties;
447: }
448: }
449:
450: /**
451: * Determines the reload interval for the config file, initializes the API
452: * if the interval has changed and starts the config file watcher.
453: */
454: void init() {
455:
456: // Determine the reload interval
457: int interval = DEFAULT_CONFIG_RELOAD_INTERVAL;
458: if (_configFile != null) {
459: try {
460: interval = determineConfigReloadInterval();
461:
462: // If the interval could not be parsed, then use the default
463: } catch (InvalidPropertyValueException exception) {
464: // ignore
465: }
466: }
467:
468: // Initialize the API
469: boolean initialized = _engine.initAPI();
470:
471: // Start the configuration file watch interval, if the location of the
472: // file is set and the interval is greater than 0
473: if (_configFile != null && interval > 0) {
474: startConfigFileWatcher(interval);
475: }
476:
477: // API initialized successfully, so log each unused property...
478: if (initialized) {
479: logUnusedRuntimeProperties();
480:
481: // ...and log that the framework was (re)initialized
482: Log.log_3415();
483: }
484: }
485:
486: /**
487: * Logs the unused runtime properties. Properties for Log4J (those starting
488: * with <code>"log4j."</code> are ignored.
489: */
490: private void logUnusedRuntimeProperties() {
491: if (_runtimeProperties != null) {
492: Iterator unused = _runtimeProperties.getUnused().getNames();
493: while (unused.hasNext()) {
494: String name = (String) unused.next();
495: if (name != null) {
496: if (!name.startsWith("log4j.")) {
497: Log.log_3434(name);
498: }
499: }
500: }
501: }
502: }
503:
504: /**
505: * Starts the runtime configuration file watch thread.
506: *
507: * @param interval
508: * the interval in seconds, must be greater than or equal to 1.
509: *
510: * @throws IllegalStateException
511: * if no runtime configuration file is specified or if there is already
512: * a file watcher.
513: *
514: * @throws IllegalArgumentException
515: * if <code>interval < 1</code>.
516: */
517: void startConfigFileWatcher(int interval)
518: throws IllegalStateException, IllegalArgumentException {
519:
520: // Check state: Config file must be set
521: if (_configFile == null || _configFile.length() < 1) {
522: throw new IllegalStateException(
523: "Name of runtime configuration file not set.");
524:
525: // Check state: File watcher cannot exist yet
526: } else if (_configFileWatcher != null) {
527: throw new IllegalStateException(
528: "Runtime configuration file watcher exists.");
529:
530: // Check arguments
531: } else if (interval < 1) {
532: throw new IllegalArgumentException("interval (" + interval
533: + ") < 1");
534: }
535:
536: // Create and start a file watch thread
537: if (_configFile.startsWith("http://")
538: || _configFile.startsWith("https://")) {
539: _configFileWatcher = new HTTPFileWatcher(_configFiles,
540: interval, _configFileListener);
541: } else {
542: _configFileWatcher = new FileWatcher(_configFiles,
543: interval, _configFileListener);
544: }
545: _configFileWatcher.start();
546: }
547:
548: /**
549: * Re-initializes the configuration file listener if there is no file
550: * watcher; otherwise interrupts the file watcher.
551: */
552: void reloadPropertiesIfChanged() {
553: if (_configFileWatcher == null) {
554: _configFileListener.reinit();
555: } else {
556: synchronized (_configFileWatcher) {
557: _configFileWatcher.notifyAll();
558: }
559: }
560: }
561:
562: /**
563: * Initializes the logging subsystem.
564: *
565: * @param properties
566: * the runtime properties containing the settings for the logging
567: * subsystem, cannot be <code>null</code>.
568: *
569: * @throws IllegalArgumentException
570: * if <code>properties == null</code>.
571: */
572: void configureLogger(Properties properties)
573: throws IllegalArgumentException {
574:
575: // Check preconditions
576: MandatoryArgumentChecker.check("properties", properties);
577:
578: // Reset Log4J configuration
579: LogManager.getLoggerRepository().resetConfiguration();
580:
581: // Make possible to have an API specific logger
582: String apiLogger = properties.getProperty("log4j.rootLogger."
583: + _config.getServletName());
584: if (apiLogger != null) {
585: properties.setProperty("log4j.rootLogger", apiLogger);
586: }
587:
588: // Reconfigure Log4J
589: PropertyConfigurator.configure(properties);
590:
591: // Determine if Log4J is properly initialized
592: Enumeration appenders = LogManager.getLoggerRepository()
593: .getRootLogger().getAllAppenders();
594:
595: // If the properties did not include Log4J configuration settings, then
596: // fallback to default settings
597: if (appenders instanceof NullEnumeration) {
598: Log.log_3304(_configFilesPath);
599: configureLoggerFallback();
600:
601: // Otherwise log that custom Log4J configuration settings were applied
602: } else {
603: Log.log_3305();
604: }
605: }
606:
607: /**
608: * Determines the interval for checking the runtime properties file for
609: * modifications.
610: *
611: * @return
612: * the interval to use, always >= 1.
613: *
614: * @throws InvalidPropertyValueException
615: * if the interval cannot be determined because it does not qualify as a
616: * positive 32-bit unsigned integer number.
617: */
618: int determineConfigReloadInterval()
619: throws InvalidPropertyValueException {
620:
621: // Check state
622: if (_configFile == null || _configFile.length() < 1) {
623: throw new IllegalStateException(
624: "Name of runtime configuration file not set.");
625: }
626:
627: // Get the runtime property
628: String prop = CONFIG_RELOAD_INTERVAL_PROPERTY;
629: String s = _runtimeProperties.get(prop);
630: int interval;
631:
632: // If the property is set, parse it
633: if (s != null && s.length() >= 1) {
634: try {
635: interval = Integer.parseInt(s);
636:
637: // Negative value
638: if (interval < 0) {
639: Log.log_3409(_configFilesPath, prop, s);
640: throw new InvalidPropertyValueException(prop, s,
641: "Negative value.");
642:
643: // Non-negative value
644: } else {
645: Log.log_3410(_configFilesPath, s);
646: }
647:
648: // Not a valid number string
649: } catch (NumberFormatException nfe) {
650: Log.log_3409(_configFilesPath, prop, s);
651: throw new InvalidPropertyValueException(prop, s,
652: "Not a 32-bit integer number.");
653: }
654:
655: // Property not set, use the default
656: } else {
657: Log.log_3408(_configFilesPath, prop,
658: DEFAULT_CONFIG_RELOAD_INTERVAL);
659: interval = DEFAULT_CONFIG_RELOAD_INTERVAL;
660: }
661:
662: return interval;
663: }
664:
665: /**
666: * Determines the log locale.
667: *
668: * @return
669: * <code>false</code> if the specified locale is not supported,
670: * <code>true</code> otherwise.
671: */
672: boolean determineLogLocale() {
673:
674: String newLocale = null;
675:
676: // If we have runtime properties, then get the log locale
677: if (_runtimeProperties != null) {
678: newLocale = _runtimeProperties
679: .get(LogCentral.LOG_LOCALE_PROPERTY);
680: }
681:
682: // If the log locale is set, apply it
683: if (newLocale != null) {
684: String currentLocale = LogCentral.getLocale();
685: if (!currentLocale.equals(newLocale)) {
686: Log.log_3306(currentLocale, newLocale);
687: try {
688: LogCentral.setLocale(newLocale);
689: Log.log_3307(currentLocale, newLocale);
690: } catch (UnsupportedLocaleException exception) {
691: Log.log_3308(currentLocale, newLocale);
692: return false;
693: }
694: }
695:
696: // No property defines the locale, use the default
697: } else {
698: LogCentral.useDefaultLocale();
699: }
700:
701: return true;
702: }
703:
704: /**
705: * Indicates whether the runtime property file was read successfully.
706: *
707: * @return
708: * <code>true</code> if the runtime properties are loaded correctly,
709: * <code>false</code> otherwise.
710: */
711: boolean propertiesRead() {
712: return _propertiesRead;
713: }
714:
715: /**
716: * Stops the config file watcher thread.
717: */
718: void destroy() {
719:
720: // Stop the FileWatcher
721: if (_configFileWatcher != null) {
722: try {
723: _configFileWatcher.end();
724: } catch (Throwable exception) {
725: Utils.logIgnoredException(exception);
726: }
727: _configFileWatcher = null;
728: }
729: }
730:
731: /**
732: * Listener that reloads the configuration file if it changes.
733: *
734: * @version $Revision: 1.60 $ $Date: 2007/09/18 08:45:05 $
735: * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a>
736: *
737: * @since XINS 1.0.0
738: */
739: private final class ConfigurationFileListener implements
740: FileWatcher.Listener {
741:
742: /**
743: * Constructs a new <code>ConfigurationFileListener</code> object.
744: */
745: private ConfigurationFileListener() {
746: // empty
747: }
748:
749: /**
750: * Re-initializes the framework. The run-time properties are re-read,
751: * the configuration file reload interval is determined, the API is
752: * re-initialized and then the new interval is applied to the watch
753: * thread for the configuration file.
754: */
755: private void reinit() {
756:
757: if (_configFile != null) {
758: Log.log_3407(_configFile);
759: } else {
760: Log.log_3407("/WEB-INF/xins.properties");
761: }
762:
763: boolean reinitialized;
764:
765: synchronized (RUNTIME_PROPERTIES_LOCK) {
766:
767: // Apply the new runtime settings to the logging subsystem
768: readRuntimeProperties();
769:
770: // Re-initialize the API
771: reinitialized = _engine.initAPI();
772:
773: // Update the file watch interval if needed
774: updateFileWatcher();
775: }
776:
777: // API re-initialized successfully, so log each unused property...
778: if (reinitialized) {
779: logUnusedRuntimeProperties();
780:
781: // ...and log that the framework was reinitialized
782: Log.log_3415();
783: }
784: }
785:
786: /**
787: * Updates the file watch interval and initializes the file watcher if
788: * needed.
789: */
790: private void updateFileWatcher() {
791:
792: if (_configFileWatcher == null) {
793: return;
794: }
795:
796: // Determine the interval
797: int newInterval;
798: try {
799: newInterval = determineConfigReloadInterval();
800: } catch (InvalidPropertyValueException exception) {
801: // Logging is already done in determineConfigReloadInterval()
802: return;
803: }
804:
805: // Update the file watch interval
806: int oldInterval = _configFileWatcher.getInterval();
807:
808: if (oldInterval != newInterval) {
809: if (newInterval == 0 && _configFileWatcher != null) {
810: _configFileWatcher.end();
811: _configFileWatcher = null;
812: } else if (newInterval > 0
813: && _configFileWatcher == null) {
814: if (_configFile.startsWith("http://")
815: || _configFile.startsWith("https://")) {
816: _configFileWatcher = new HTTPFileWatcher(
817: _configFiles, newInterval,
818: _configFileListener);
819: } else {
820: _configFileWatcher = new FileWatcher(
821: _configFiles, newInterval,
822: _configFileListener);
823: }
824: _configFileWatcher.start();
825: } else {
826: _configFileWatcher.setInterval(newInterval);
827: Log.log_3403(_configFilesPath, oldInterval,
828: newInterval);
829: }
830: }
831: }
832:
833: /**
834: * Callback method called when the configuration file is found while it
835: * was previously not found.
836: *
837: * <p>This will trigger re-initialization.
838: */
839: public void fileFound() {
840: reinit();
841: }
842:
843: /**
844: * Callback method called when the configuration file is (still) not
845: * found.
846: *
847: * <p>The implementation of this method does not perform any actions.
848: */
849: public void fileNotFound() {
850: Log.log_3400(_configFilesPath);
851: }
852:
853: /**
854: * Callback method called when the configuration file is (still) not
855: * modified.
856: *
857: * <p>The implementation of this method does not perform any actions.
858: */
859: public void fileNotModified() {
860: }
861:
862: /**
863: * Callback method called when the configuration file could not be
864: * examined due to a <code>SecurityException</code>.
865: *
866: * <p>The implementation of this method does not perform any actions.
867: *
868: * @param exception
869: * the caught security exception, should not be <code>null</code>
870: * (although this is not checked).
871: */
872: public void securityException(SecurityException exception) {
873: Log.log_3401(exception, _configFilesPath);
874: }
875:
876: /**
877: * Callback method called when the configuration file is modified since
878: * the last time it was checked.
879: *
880: * <p>This will trigger re-initialization.
881: */
882: public void fileModified() {
883: reinit();
884: }
885: }
886: }
|