📄 etcproperties.java
字号:
package com.corba.mnq.tool;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.corba.mnq.tool.idl.IdlFile;
/**
* A Property class - the value addition this class provides over
* java.util.Properties is to take a properties file name as argument, read the
* file internally and construct the Properties object. Later, the file is
* checked occasionally at regular time intervals whether it did change, and if
* this is the case it is re-read automatically. See {@link #reloadIfNeeded()}
* and {@link #getProperty(String)}.<br />
* If a property is not defined or empty, per default the system properties are
* searched (which can be defined on the java VM command line using -D). This
* can be overridden by calling {@link #setDefaultProperties(Properties)}.<br />
* Also this class traces each access to a property. <br />
* This class intentionally does not inherit from FFLoggable.
*
* @author Aravindan RS
* @author Christian Spreuer (demf1372)
*/
public class EtcProperties extends Properties {
/** this constant is used by the serialization machinery. */
static final long serialVersionUID = 8331022132777575040L;
/**
* Lazily created by some constructors, to support a loose coupling to
* tracing (java.util.logging) at runtime.
*/
private static Logger log = Logger.getLogger(EtcProperties.class.getName());
/**
* This is the name of a property which controls the maximum rate how often
* {@link #reloadIfNeeded()} checks whether the property file has changed.
* The property value (in milliseconds) suppresses further checks until this
* amount of time has been passed since the last such check. This property
* defaults to {@link #DEFAULT_RELOAD_CHECK_INTERVAL} and has a minimum
* value of {@link #MINIMUM_RELOAD_CHECK_INTERVAL}. Value is (<code>{@value}</code>).
*/
public static final String FFPROPERTIES_RELOAD_CHECK_INTERVAL = "EtcProperties.reload.interval";
/**
* Default value of {@link #FFPROPERTIES_RELOAD_CHECK_INTERVAL} in
* milliseconds. Value is 10 seconds (<code>{@value}</code>).
*/
public static final long DEFAULT_RELOAD_CHECK_INTERVAL = 10 * 1000;
/**
* Minimum value of {@link #FFPROPERTIES_RELOAD_CHECK_INTERVAL} in
* milliseconds. Value is 1 second (<code>{@value}</code>).
*/
public static final long MINIMUM_RELOAD_CHECK_INTERVAL = 1 * 1000;
private static String theProcessName = null;
/** @serial */
private Properties defaultProperties = System.getProperties();
/**
* @serial The name of the properties file. Can be used for reloading.
*/
private String fileName;
/**
* @serial Last timestamp from the properties file. Can be used for
* reloading.
*/
private long reloadedTimeStamp = System.currentTimeMillis();
/** @serial Time of last reload check. */
private long reloadCheckTimeStamp = reloadedTimeStamp;
/**
* @serial Time interval in milliseconds after each reload check where
* checks are suppressed.
*/
private long reloadCheckInterval = DEFAULT_RELOAD_CHECK_INTERVAL;
/** @serial Should all properties be cleared before reloading? */
private boolean cleanupBeforeLoading = false;
/**
* This constructor is equivalent to using Base class directly.
* <p />
* This constructor may be used to implement java.util.logging as it does
* not trigger calls to java.util.logging API.
*/
public EtcProperties() {
// Nothing to do
}
/**
* C'tor loads the Properties from a given IdlFile but may avoid logging.
* <p />
* Later calls to
* {@link FFProperties#getProperty(String) getXXXProperty(...)} will reload
* the file if needed.
* <p />
* This constructor may be used to implement java.util.logging if called
* with <code>startLogging</code> set to <code>false</code>. Otherwise
* it will trigger calls to the java.util.logging API.
*
* @param fPath
* Full path of the file to be loaded.
* @param startLogging
* If <code>false</code>, logging of this class will not be
* turned on (inadvertently). <br />
* If <code>true</code>, logging will be turned on.
*/
public EtcProperties(String fPath, boolean startLogging) {
if (startLogging) {
initializeMyLogging();
}
fileName = fPath;
// Force reloading
File propertiesFile = new File(fPath);
// Properties are "too old".
reloadedTimeStamp = propertiesFile.lastModified() - 1;
// Last check was "long ago".
reloadCheckTimeStamp = System.currentTimeMillis() - reloadCheckInterval
- 1;
reloadIfNeeded();
// In case of errors, just keep what we have at the
// moment, e.g. nothing. Reloading will update it later if it
// succeeds.
}
/**
* Makes sure that logging is initialized for this class. Package visible
* for unit testing.
*/
static synchronized void initializeMyLogging() {
// No real need to be synchronized, this call can be
// executed several times in parallel without harm.
// But to avoid discussions as this is cheap...
// TODO ...
// if (log == null) {
//
// }
}
/**
* C'tor loads the Properties from a given IdlFile.
* <p />
* Later calls to
* {@link FFProperties#getProperty(String) getXXXProperty(...)} will reload
* the file if needed.
* <p />
* This constructor will trigger calls to the java.util.logging API.
*
* @param fPath
* full path of the file to be loaded.
*/
public EtcProperties(String fPath) {
this(fPath, true);
}
/**
* C'tor loads the Properties from a file in a directory that is given in an
* environment variable.
* <p />
* Later calls to
* {@link FFProperties#getProperty(String) getXXXProperty(...)} will reload
* the file if needed.
* <p />
* This constructor will trigger calls to the java.util.logging API.
*
* @param dirEnvironmentVariable
* property name standing for the directory containing the
* specified file. This property is read from System class to get
* the directory name.
* @param fName
* property name containing the name of the file. This is
* appended to the directory name.
*/
public EtcProperties(String dirEnvironmentVariable, String fName) {
this(fileNameFromHomeDir(dirEnvironmentVariable, fName), true);
}
/**
* C'tor loads the Properties from the given stream. Reloading is not
* possible.
* <p />
* This constructor may be used to implement java.util.logging as it does
* not trigger calls to java.util.logging API.
*
* @param inputStream
* the stream which contains all properties.
* @throws IOException
* in case the stream can't be read.
*/
public EtcProperties(InputStream inputStream) throws IOException {
// LOG is not changed - this constructor can be used to
// implement java.util.logging.
// Load properties from a stream.
load(inputStream);
// fileName stays null. This will also prevent reloading, so
// the values of all time variables are OK.
}
/**
* Adds some defaultProperties that are returned in case a property is not
* found. Per default this is set to System.getProperties(). <br />
* Each FFProperty has only one set of default properties, so if you call
* this method twice, the first set gets replaced.
*
* @param defaultProperties
* The default properties to set. May be <code>null</code> or
* an empty set.
*/
public void setDefaultProperties(Properties defaultProperties) {
this.defaultProperties = defaultProperties;
}
/**
* Specify whether reloading should delete obsolete properties. The default
* is <code>false</code> to keep properties which are no longer mentioned
* in the property file.
* <p />
* Set this to <code>true</code> to remove all properties which have been
* removed from (or, generally, are not mentioned in) the properties file.
* Then, reloading will remove also those properties which have been added
* by calling {@link #setProperty(String, String)} but which are not
* mentioned in the file.
*
* @param cleanupBeforeLoading
* if true, all properties will be cleared before re-loading
* them, to get rid of old properties which are not contained in
* the file anymore.
* @see #reloadIfNeeded()
*/
public void setCleanupBeforeLoading(boolean cleanupBeforeLoading) {
this.cleanupBeforeLoading = cleanupBeforeLoading;
}
/**
* Returns the time when the properties were changed. A change is caused by
* {@link #reloadIfNeeded()} or by {@link #setProperty(String, String)}.
* <p />
* This method provides the cheapest reliable way to determine whether one
* or more properties have been changed. It can be used like this:
* <p />
* <code>
* // declare two data members, either both static or both not static:<br />
* // the properties file + its time stamp (in this order):<br />
* private static FFProperties props = new FFProperties("the/file/name.properties");<br />
* private static long propsReloaded = props.getReloadedTimeStamp() - 1;<br />
* <br />
* // To decide whether it is needed to query all properties again:<br />
* // (The expressing is exploiting a possible wrap-around of long arithmetic)<br />
* if (props.getReloadedTimeStamp() - propsReloaded > 0) {<br />
* propsReloaded = props.getReloadedTimeStamp();<br />
* // IdlFile has been reloaded, do a props.getXXX() for all properties.<br />
* ...<br />
* }<br />
* </code>
*
* @return time in ms of the last change of any of the properties.
*/
public synchronized long getReloadedTimeStamp() {
return reloadedTimeStamp;
}
/**
* Returns the filename that is the source of these properties.
*
* @return The name of a file or <code>null</code>.
*/
public String getFileName() {
return fileName;
}
/**
* This method does a small value addition to the get() method of the base
* class by type casting the return value from Object to String type. So
* this type casting is avoided in all calling places. Also, if a value is
* missing, this class returns an empty string instead of null string.
* Furthermore, tracing is added.
* <p>
* The method {@link Properties#getProperty(java.lang.String)} is
* intentionally not overridden by this, so that you still can get a
* <code>null</code> return value if a property is not defined.
*
* @param key
* The key in the Properties whose value is seeked.
* @return The value corresponding to the specified key, never
* <code>null</code>.
*/
public String getValue(String key) {
String value = getProperty(key);
if (value == null) {
value = "";
}
return value;
}
/**
* Overrides method {@link Properties#getProperty(java.lang.String)} to
* include tracing and to
* {@linkplain #reloadIfNeeded() reload the properties if needed}.
*
* @param key
* the name of the property.
* @return the value of the property, or <code>null</code> if not found.
*/
public String getProperty(String key) {
String val;
// Sync only once, and only what is needed, i.e. not logging.
// reloadIfNeeded is sync'ed, and the low-level
// Hashtable.get/put/load calls
synchronized (this) {
reloadIfNeeded();
// This would try to look in super.defaults, which is
// nevertheless always null.
val = super.getProperty(key);
}
if (isStringNotEmpty(val)) {
return val;
}
if (defaultProperties != null) {
val = defaultProperties.getProperty(key);
if (isStringNotEmpty(val)) {
return val;
}
}
return val;
}
/**
* Overrides method
* {@link Properties#getProperty(java.lang.String, java.lang.String)} to
* include tracing and to
* {@linkplain #reloadIfNeeded() reload the properties if needed}.
*
* @param key
* the name of the property.
* @param defaultValue
* value to use if property is not defined.
* @return the value of the property, or an the default value if not found.
* This may return an empty string but not <code>null</code>.
*/
public String getProperty(String key, String defaultValue) {
String value = getProperty(key);
if (value == null) {
return defaultValue;
}
return value;
}
/**
* Asks the properties of this process for a certain key.
*
* @param key
* the name of the property.
* @param defaultValue
* use this if property value is not available.
* @return the value of the property, or the given default value if not
* found.
*/
public short getShortProperty(String key, short defaultValue) {
String value = getProperty(key);
try {
if (isStringNotEmpty(value)) {
return Short.parseShort(value);
}
} catch (NumberFormatException e) {
if (log != null) {
log.log(Level.CONFIG, e.getMessage(), e);
}
}
return defaultValue;
}
/**
* Asks the properties of this process for a certain key.
*
* @param key
* the name of the property.
* @param defaultValue
* use this if property value is not available.
* @return the value of the property, or the given default value if not
* found.
*/
public int getIntProperty(String key, int defaultValue) {
String value = getProperty(key);
try {
if (isStringNotEmpty(value)) {
return Integer.parseInt(value);
}
} catch (NumberFormatException e) {
if (log != null) {
log.log(Level.CONFIG, e.getMessage(), e);
}
}
return defaultValue;
}
/**
* Asks the properties of this process for a certain key.
*
* @param key
* the name of the property.
* @param minValue
* the minimum allowed value.
* @param defaultValue
* use this if property value is not available or too small.
* @return the value of the property, or the given default value if not
* found.
*/
public int getIntProperty(String key, int minValue, int defaultValue) {
String value = getProperty(key);
try {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -