Java/Development Class/Properties — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
|
(нет различий)
|
Текущая версия на 07:01, 1 июня 2010
Содержание
- 1 Adds new properties to an existing set of properties
- 2 A java.util.Properties class that will check a file or URL for changes periodically
- 3 An utility class to ease up using property-file resource bundles.
- 4 A utility class for replacing properties in strings.
- 5 Converts specified map to java.util.Properties
- 6 Converts Unicode into something that can be embedded in a java properties file
- 7 Copy a set of properties from one Property to another.
- 8 Create Properties from String array
- 9 Encapsulates java.util.Properties to add java primitives and some other java classes
- 10 Extracts a specific property key subset from the known properties
- 11 Gets strong-type-value property from a standard Properties
- 12 JDOM based XML properties
- 13 Load and save properties to files.
- 14 Merge Properties Into Map
- 15 Observable Properties
- 16 Property access utility methods
- 17 Property Loader
- 18 Read a set of properties from the received input stream, strip off any excess white space that exists in those property values,
- 19 Represents a persistent set of properties
- 20 Sorts a property list and turns the sorted list into a string.
- 21 Sorts property list and print out each key=value pair prepended with specific indentation.
- 22 Task to overwrite Properties
- 23 The properties iterator iterates over a set of enumerated properties.
- 24 XML configuration management
- 25 XML Properties
Adds new properties to an existing set of properties
/**
* Copyright 2007 University Of Southern California
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.IOException;
import java.util.Enumeration;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PropertiesHelper
extends Properties {
/**
* Adds new properties to an existing set of properties while
* substituting variables. This function will allow value
* substitutions based on other property values. Value substitutions
* may not be nested. A value substitution will be ${property.key},
* where the dollar-brace and close-brace are being stripped before
* looking up the value to replace it with. Note that the ${..}
* combination must be escaped from the shell.
*
* @param b is the set of properties to add to existing properties.
* @return the combined set of properties.
*/
protected Properties addProperties(Properties b) {
// initial
// Properties result = new Properties(this);
Properties sys = System.getProperties();
Pattern pattern = Pattern.rupile("\\$\\{[-a-zA-Z0-9._]+\\}");
for (Enumeration e = b.propertyNames(); e.hasMoreElements(); ) {
String key = (String) e.nextElement();
String value = b.getProperty(key);
// unparse value ${prop.key} inside braces
Matcher matcher = pattern.matcher(value);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
// extract name of properties from braces
String newKey = value.substring(matcher.start() + 2, matcher.end() - 1);
// try to find a matching value in result properties
String newVal = getProperty(newKey);
// if still not found, try system properties
if (newVal == null) {
newVal = sys.getProperty(newKey);
}
// replace braced string with the actual value or empty string
matcher.appendReplacement(sb, newVal == null ? "" : newVal);
}
matcher.appendTail(sb);
setProperty(key, sb.toString());
}
return this;
}
/**
* Adds new properties to an existing set of properties while
* substituting variables. This function will allow value
* substitutions based on other property values. Value substitutions
* may not be nested. A value substitution will be ${property.key},
* where the dollar-brace and close-brace are being stripped before
* looking up the value to replace it with. Note that the ${..}
* combination must be escaped from the shell.
*
* @param a is the initial set of known properties (besides System ones)
* @param b is the set of properties to add to a
* @return the combined set of properties from a and b.
*/
protected static Properties addProperties(Properties a, Properties b) {
// initial
Properties result = new Properties(a);
Properties sys = System.getProperties();
Pattern pattern = Pattern.rupile("\\$\\{[-a-zA-Z0-9._]+\\}");
for (Enumeration e = b.propertyNames(); e.hasMoreElements(); ) {
String key = (String) e.nextElement();
String value = b.getProperty(key);
// unparse value ${prop.key} inside braces
Matcher matcher = pattern.matcher(value);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
// extract name of properties from braces
String newKey = value.substring(matcher.start() + 2, matcher.end() - 1);
// try to find a matching value in result properties
String newVal = result.getProperty(newKey);
// if still not found, try system properties
if (newVal == null) {
newVal = sys.getProperty(newKey);
}
// replace braced string with the actual value or empty string
matcher.appendReplacement(sb, newVal == null ? "" : newVal);
}
matcher.appendTail(sb);
result.setProperty(key, sb.toString());
}
// final
return result;
}
public PropertiesHelper() {
super();
}
public PropertiesHelper(Properties defaults) {
super(defaults);
}
protected PropertiesHelper(String propFilename, Properties defaults) throws
IOException,
MissingResourceException {
// create empty new instance
super(defaults);
}
/**
* Accessor: Overwrite any properties from within the program.
*
* @param key is the key to look up
* @param value is the new property value to place in the system.
* @return the old value, or null if it didn"t exist before.
*/
/** public Object setProperty(String key, String value) {
return System.setProperty(key, value);
}
**/
/**
* Accessor: access to the internal properties as read from file.
* An existing system property of the same key will have precedence
* over any project property. This method will remove leading and
* trailing ASCII control characters and whitespaces.
*
* @param key is the key to look up
* @return the value for the key, or null, if not found.
*/
/** public String getProperty(String key) {
String result =
System.getProperty(key, this.m_props.getProperty(key));
return (result == null ? result : result.trim());
}
**/
/**
* Accessor: access to the internal properties as read from file
* An existing system property of the same key will have precedence
* over any project property. This method will remove leading and
* trailing ASCII control characters and whitespaces.
*
* @param key is the key to look up
* @param defValue is a default to use, if no value can be found for the key.
* @return the value for the key, or the default value, if not found.
*/
/** public String getProperty(String key, String defValue) {
String result =
System.getProperty(key, this.m_props.getProperty(key, defValue));
return (result == null ? result : result.trim());
}
**/
/**
* Extracts a specific property key subset from the known properties.
* The prefix may be removed from the keys in the resulting dictionary,
* or it may be kept. In the latter case, exact matches on the prefix
* will also be copied into the resulting dictionary.
*
* @param prefix is the key prefix to filter the properties by.
* @param keepPrefix if true, the key prefix is kept in the resulting
* dictionary. As side-effect, a key that matches the prefix exactly
* will also be copied. If false, the resulting dictionary"s keys are
* shortened by the prefix. An exact prefix match will not be copied,
* as it would result in an empty string key.
* @return a property dictionary matching the filter key. May be
* an empty dictionary, if no prefix matches were found.
*
* @see #getProperty( String ) is used to assemble matches
*/
public Properties matchingSubset(String prefix, boolean keepPrefix) {
Properties result = new Properties();
// sanity check
if (prefix == null || prefix.length() == 0) {
return result;
}
String prefixMatch; // match prefix strings with this
String prefixSelf; // match self with this
if (prefix.charAt(prefix.length() - 1) != ".") {
// prefix does not end in a dot
prefixSelf = prefix;
prefixMatch = prefix + ".";
} else {
// prefix does end in one dot, remove for exact matches
prefixSelf = prefix.substring(0, prefix.length() - 1);
prefixMatch = prefix;
}
// POSTCONDITION: prefixMatch and prefixSelf are initialized!
// now add all matches into the resulting properties.
// Remark 1: #propertyNames() will contain the System properties!
// Remark 2: We need to give priority to System properties. This is done
// automatically by calling this class"s getProperty method.
String key;
for (Enumeration e = propertyNames(); e.hasMoreElements(); ) {
key = (String) e.nextElement();
if (keepPrefix) {
// keep full prefix in result, also copy direct matches
if (key.startsWith(prefixMatch) || key.equals(prefixSelf)) {
result.setProperty(key,
getProperty(key));
}
} else {
// remove full prefix in result, dont copy direct matches
if (key.startsWith(prefixMatch)) {
result.setProperty(key.substring(prefixMatch.length()),
getProperty(key));
}
}
}
// done
return result;
}
/**
* Extracts a specific property key subset from the properties passed.
* The prefix may be removed from the keys in the resulting dictionary,
* or it may be kept. In the latter case, exact matches on the prefix
* will also be copied into the resulting dictionary.
*
*
* @param prefix is the key prefix to filter the properties by.
* @param keepPrefix if true, the key prefix is kept in the resulting
* dictionary. As side-effect, a key that matches the prefix exactly
* will also be copied. If false, the resulting dictionary"s keys are
* shortened by the prefix. An exact prefix match will not be copied,
* as it would result in an empty string key.
* @return a property dictionary matching the filter key. May be
* an empty dictionary, if no prefix matches were found.
*
* @see #getProperty( String ) is used to assemble matches
*/
public static Properties matchingSubset(Properties properties, String prefix,
boolean keepPrefix) {
Properties result = new Properties();
// sanity check
if (prefix == null || prefix.length() == 0) {
return result;
}
String prefixMatch; // match prefix strings with this
String prefixSelf; // match self with this
if (prefix.charAt(prefix.length() - 1) != ".") {
// prefix does not end in a dot
prefixSelf = prefix;
prefixMatch = prefix + ".";
} else {
// prefix does end in one dot, remove for exact matches
prefixSelf = prefix.substring(0, prefix.length() - 1);
prefixMatch = prefix;
}
// POSTCONDITION: prefixMatch and prefixSelf are initialized!
// now add all matches into the resulting properties.
// Remark 1: #propertyNames() will contain the System properties!
// Remark 2: We need to give priority to System properties. This is done
// automatically by calling this class"s getProperty method.
String key;
for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
key = (String) e.nextElement();
if (keepPrefix) {
// keep full prefix in result, also copy direct matches
if (key.startsWith(prefixMatch) || key.equals(prefixSelf)) {
result.setProperty(key,
properties.getProperty(key));
}
} else {
// remove full prefix in result, dont copy direct matches
if (key.startsWith(prefixMatch)) {
result.setProperty(key.substring(prefixMatch.length()),
properties.getProperty(key));
}
}
}
// done
return result;
}
}
A java.util.Properties class that will check a file or URL for changes periodically
/*
* RefreshingProperties.java
*
* Created on November 11, 2005, 10:15 PM
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This is a java.util.Properties class that will check a file or URL for changes
* periodically. It has a threaded and non-threaded mode, and will reload a URL
* every recheck time, or inspect the last modified date on a file on check.
* @author
* @version $Revision: 1.4 $
*/
public class RefreshingProperties extends Properties {
/**
* DOCUMENT ME!
*/
private static final Logger LOG = Logger.getLogger( RefreshingProperties.class.getCanonicalName() );
/**
* DOCUMENT ME!
*/
private ArrayList<RefreshingProperties.RefreshListener> listeners = new ArrayList<RefreshingProperties.RefreshListener>();
/**
* DOCUMENT ME!
*/
private Thread updater;
/**
* DOCUMENT ME!
*/
private URL url;
/**
* DOCUMENT ME!
*/
private long lastCheck;
/**
* DOCUMENT ME!
*/
private long recheckTime = 5 * 60 * 1000;
private boolean loading = false;
private ArrayList<RefreshingProperties> augmentProps = new ArrayList<RefreshingProperties>();
private ArrayList<RefreshingProperties> overrideProps = new ArrayList<RefreshingProperties>();
private boolean noImportMode = false;
/**
* Creates a new RefreshingProperties object.
* This constructor will use the default settings of threaded mode and recheck at 5 minutes.
* @param url URL to read from.
* @throws IOException Thrown on read errors.
*/
public RefreshingProperties(URL url) throws IOException {
init(url,recheckTime,true);
}
/**
* Creates a new RefreshingProperties object.
* This will use the default recheck at 5 minutes.
* @param url URL to read from
* @param useThread Indicates whether the check should run in threaded or non-threaded road.
* @throws IOException Thrown on read errors.
*/
public RefreshingProperties(URL url,boolean useThread) throws IOException {
init(url,recheckTime,useThread);
}
/**
* Creates a new RefreshingProperties object.
* Uses the default threaded mode.
* @param recheckTime number of milliseconds between rechecks
* @param url URL to load from
* @throws IOException Thrown on read errors.
*/
public RefreshingProperties(URL url,long recheckTime) throws IOException {
init(url,recheckTime,true);
}
/**
* Creates a new RefreshingProperties object.
* @param url URL to read from
* @param recheckTime recheck time in milliseconds
* @param useThread Whether the recheck should be threaded or unthreaded.
* @throws IOException Thrown on read errors.
*/
public RefreshingProperties(URL url,long recheckTime,boolean useThread) throws IOException {
init(url,recheckTime,useThread);
}
/**
* Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for
* parallelism with the <tt>getProperty</tt> method. Enforces use of
* strings for property keys and values. The value returned is the
* result of the <tt>Hashtable</tt> call to <code>put</code>.
*
* @param key the key to be placed into this property list.
* @param value the value corresponding to <tt>key</tt>.
* @return the previous value of the specified key in this property
* list, or <code>null</code> if it did not have one.
* @see #getProperty
* @since 1.2
*/
public Object setProperty(String key,String value) {
Object retValue;
threadCheck();
retValue = super.setProperty(key,value);
return retValue;
}
/**
* Searches for the property with the specified key in this property list.
* If the key is not found in this property list, the default property list,
* and its defaults, recursively, are then checked. The method returns
* <code>null</code> if the property is not found.
*
* @param key the property key.
* @return the value in this property list with the specified key value.
* @see #setProperty
* @see #defaults
*/
public String getProperty(String key) {
threadCheck();
String retValue;
retValue = super.getProperty(key);
return retValue;
}
/**
* Searches for the property with the specified key in this property list.
* If the key is not found in this property list, the default property list,
* and its defaults, recursively, are then checked. The method returns the
* default value argument if the property is not found.
*
* @param key the hashtable key.
* @param defaultValue a default value.
*
* @return the value in this property list with the specified key value.
* @see #setProperty
* @see #defaults
*/
public String getProperty(String key,String defaultValue) {
String retValue;
threadCheck();
retValue = super.getProperty(key,defaultValue);
return retValue;
}
/**
* DOCUMENT ME!
*
* @param listener DOCUMENT ME!
*/
public void addRefreshListener(RefreshingProperties.RefreshListener listener) {
this.listeners.add(listener);
}
/**
* Creates a shallow copy of this hashtable. All the structure of the
* hashtable itself is copied, but the keys and values are not cloned.
* This is a relatively expensive operation.
*
* @return a clone of the hashtable.
*/
public Object clone() {
Object retValue;
threadCheck();
retValue = super.clone();
return retValue;
}
/**
* Tests if some key maps into the specified value in this hashtable.
* This operation is more expensive than the <code>containsKey</code>
* method.<p>
*
* Note that this method is identical in functionality to containsValue,
* (which is part of the Map interface in the collections framework).
*
* @return <code>true</code> if and only if some key maps to the
* <code>value</code> argument in this hashtable as
* determined by the <tt>equals</tt> method;
* <code>false</code> otherwise.
* @see #containsKey(Object)
* @see #containsValue(Object)
* @see Map
* @param value a value to search for.
*/
public boolean contains(Object value) {
threadCheck();
boolean retValue;
retValue = super.contains(value);
return retValue;
}
/**
* Tests if the specified object is a key in this hashtable.
*
* @return <code>true</code> if and only if the specified object
* is a key in this hashtable, as determined by the
* <tt>equals</tt> method; <code>false</code> otherwise.
* @see #contains(Object)
* @param key possible key.
*/
public boolean containsKey(Object key) {
boolean retValue;
threadCheck();
retValue = super.containsKey(key);
return retValue;
}
/**
* Returns true if this Hashtable maps one or more keys to this value.<p>
*
* Note that this method is identical in functionality to contains
* (which predates the Map interface).
*
* @return <tt>true</tt> if this map maps one or more keys to the
* specified value.
* @see Map
* @since 1.2
* @param value value whose presence in this Hashtable is to be tested.
*/
public boolean containsValue(Object value) {
boolean retValue;
threadCheck();
retValue = super.containsValue(value);
return retValue;
}
/**
* Returns an enumeration of the values in this hashtable.
* Use the Enumeration methods on the returned object to fetch the elements
* sequentially.
*
* @return an enumeration of the values in this hashtable.
* @see java.util.Enumeration
* @see #keys()
* @see #values()
* @see Map
*/
public java.util.Enumeration<Object> elements() {
java.util.Enumeration retValue;
threadCheck();
retValue = super.elements();
return retValue;
}
/**
* Returns a Set view of the entries contained in this Hashtable.
* Each element in this collection is a Map.Entry. The Set is
* backed by the Hashtable, so changes to the Hashtable are reflected in
* the Set, and vice-versa. The Set supports element removal
* (which removes the corresponding entry from the Hashtable),
* but not element addition.
*
* @return a set view of the mappings contained in this map.
* @see Map.Entry
* @since 1.2
*/
public java.util.Set<java.util.Map.Entry<Object,Object>> entrySet() {
java.util.Set retValue;
threadCheck();
retValue = super.entrySet();
return retValue;
}
/**
* Returns the value to which the specified key is mapped in this hashtable.
*
* @return the value to which the key is mapped in this hashtable;
* <code>null</code> if the key is not mapped to any value in
* this hashtable.
* @see #put(Object, Object)
* @param key a key in the hashtable.
*/
public Object get(Object key) {
threadCheck();
Object retValue;
for( RefreshingProperties over : this.overrideProps ){
Object overValue = over.get(key);
if( overValue != null){
return overValue;
}
}
retValue = super.get(key);
if( retValue == null ){
for( RefreshingProperties aug : this.augmentProps ){
Object augValue = aug.get( key );
if( augValue != null ){
retValue = augValue;
break;
}
}
}
return retValue;
}
/**
* Returns a Set view of the keys contained in this Hashtable. The Set
* is backed by the Hashtable, so changes to the Hashtable are reflected
* in the Set, and vice-versa. The Set supports element removal
* (which removes the corresponding entry from the Hashtable), but not
* element addition.
*
* @return a set view of the keys contained in this map.
* @since 1.2
*/
public java.util.Set<Object> keySet() {
java.util.Set retValue;
threadCheck();
retValue = super.keySet();
for( RefreshingProperties props : this.augmentProps ){
retValue.addAll( props.keySet() );
}
for( RefreshingProperties props : this.overrideProps ){
retValue.addAll( props.keySet() );
}
return retValue;
}
/**
* Returns an enumeration of the keys in this hashtable.
*
* @return an enumeration of the keys in this hashtable.
* @see Enumeration
* @see #elements()
* @see #keySet()
* @see Map
*/
public java.util.Enumeration<Object> keys() {
java.util.Enumeration retValue;
threadCheck();
retValue = (new Vector( this.keySet() )).elements();
return retValue;
}
/**
* Returns an enumeration of all the keys in this property list,
* including distinct keys in the default property list if a key
* of the same name has not already been found from the main
* properties list.
*
* @return an enumeration of all the keys in this property list, including
* the keys in the default property list.
* @see java.util.Enumeration
* @see java.util.Properties#defaults
*/
public java.util.Enumeration<Object> propertyNames() {
java.util.Enumeration retValue;
threadCheck();
retValue = super.propertyNames();
return retValue;
}
/**
* Maps the specified <code>key</code> to the specified
* <code>value</code> in this hashtable. Neither the key nor the
* value can be <code>null</code>. <p>
*
* The value can be retrieved by calling the <code>get</code> method
* with a key that is equal to the original key.
*
* @return the previous value of the specified key in this hashtable,
* or <code>null</code> if it did not have one.
* @see Object#equals(Object)
* @see #get(Object)
* @param key the hashtable key.
* @param value the value.
*/
public Object put(Object key,Object value) {
threadCheck();
if( !this.noImportMode && key instanceof String && ((String) key ).startsWith("@import.") ){
String keyString = ((String) key );
String importType = keyString.substring( 8, keyString.lastIndexOf(".") );
ImportRefreshListener irl = null;
if( importType.equals("override") ){
irl = new ImportRefreshListener( this, true );
} else if( importType.equals("augment") ) {
irl = new ImportRefreshListener( this, false );
} else {
throw new RuntimeException("Import type: "+importType+" unknown.");
}
try{
boolean useThread = (this.updater != null );
RefreshingProperties importedProp = new RefreshingProperties( new URL( this.url, (String) value ), this.recheckTime, useThread );
if( irl.clobber ){
this.overrideProps.add( importedProp );
} else {
this.augmentProps.add( importedProp );
}
importedProp.addRefreshListener( irl );
this.importLoad( importedProp, irl.clobber );
} catch(Exception e){
throw new RuntimeException("Exception creaing child properties", e);
}
}
return super.put(key,value);
}
/**
* Copies all of the mappings from the specified Map to this Hashtable
* These mappings will replace any mappings that this Hashtable had for any
* of the keys currently in the specified Map.
*
* @since 1.2
* @param t Mappings to be stored in this map.
*/
public void putAll(java.util.Map t) {
threadCheck();
super.putAll(t);
}
/**
* Removes the key (and its corresponding value) from this
* hashtable. This method does nothing if the key is not in the hashtable.
*
* @return the value to which the key had been mapped in this hashtable,
* or <code>null</code> if the key did not have a mapping.
* @param key the key that needs to be removed.
*/
public Object remove(Object key) {
threadCheck();
Object retValue;
retValue = super.remove(key);
return retValue;
}
/**
* DOCUMENT ME!
*
* @param listener DOCUMENT ME!
*/
public void removeRefreshListener(RefreshingProperties.RefreshListener listener) {
this.listeners.remove(listener);
}
/**
* Returns a Collection view of the values contained in this Hashtable.
* The Collection is backed by the Hashtable, so changes to the Hashtable
* are reflected in the Collection, and vice-versa. The Collection
* supports element removal (which removes the corresponding entry from
* the Hashtable), but not element addition.
*
* @return a collection view of the values contained in this map.
* @since 1.2
*/
public java.util.Collection<Object> values() {
java.util.Collection retValue;
threadCheck();
ArrayList values = new ArrayList();
for( Object key : this.keySet() ){
values.add( this.get(key ) );
}
return values;
}
/**
* DOCUMENT ME!
*/
private void check() {
try {
if(this.url.getProtocol().equals("file") ) {
File f = new File(this.url.getFile());
if( f.lastModified() > this.lastCheck ){
this.load();
}
} else if( !this.url.getProtocol().equals("file") && System.currentTimeMillis() - this.lastCheck > this.recheckTime ){
this.load();
}
this.lastCheck = System.currentTimeMillis();
} catch(IOException e) {
RefreshingProperties.LOG.log(Level.WARNING,"Exception reloading properies.",e);
}
}
private void importLoad( RefreshingProperties source, boolean clobber ){
Enumeration keys = source.keys();
while( keys.hasMoreElements() ){
String key = (String) keys.nextElement();
if( clobber || this.getProperty( key ) == null )
this.put( key, source.getProperty( key ) );
}
this.fireEvents();
}
/**
* DOCUMENT ME!
*
* @param url DOCUMENT ME!
* @param recheckTime DOCUMENT ME!
* @param useThread DOCUMENT ME!
*
* @throws IOException DOCUMENT ME!
*/
private void init(URL url,long recheckTime,boolean useThread) throws IOException {
this.url = url;
this.recheckTime = recheckTime;
if(useThread) {
this.updater = new UpdateThread(this);
this.updater.start();
}
this.check();
}
/**
* DOCUMENT ME!
*
* @throws IOException DOCUMENT ME!
*/
private void load() throws IOException {
this.loading = true;
InputStream is = null;
super.clear();
is = this.url.openStream();
super.load(is);
is.close();
RefreshingProperties.LOG.log(Level.FINEST,"Loading of " + this.url + " at " + new Date());
this.fireEvents();
this.loading = false;
}
private void fireEvents(){
RefreshingProperties.ReloadEvent event = new ReloadEvent(this, this.url,System.currentTimeMillis());
for(RefreshingProperties.RefreshListener listener : this.listeners) {
listener.propertiesRefreshNotify(event);
}
}
/**
* DOCUMENT ME!
*/
private void threadCheck() {
if(!this.loading && this.updater == null) {
check();
}
}
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision: 1.4 $
*/
public static interface RefreshListener {
/**
* DOCUMENT ME!
*
* @param event DOCUMENT ME!
*/
public void propertiesRefreshNotify(RefreshingProperties.ReloadEvent event);
}
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision: 1.4 $
*/
public static class ReloadEvent {
/**
* DOCUMENT ME!
*/
private URL url;
/**
* DOCUMENT ME!
*/
private long time;
private RefreshingProperties source;
/**
* Creates a new ReloadEvent object.
*
* @param url DOCUMENT ME!
* @param time DOCUMENT ME!
*/
public ReloadEvent(RefreshingProperties source, URL url,long time) {
this.setSource(source);
this.url = url;
this.time = time;
}
/**
* DOCUMENT ME!
*
* @param time DOCUMENT ME!
*/
public void setTime(long time) {
this.time = time;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public long getTime() {
return time;
}
/**
* DOCUMENT ME!
*
* @param url DOCUMENT ME!
*/
public void setUrl(URL url) {
this.url = url;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public URL getUrl() {
return url;
}
public RefreshingProperties getSource() {
return source;
}
public void setSource(RefreshingProperties source) {
this.source = source;
}
}
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision: 1.4 $
*/
private class UpdateThread extends Thread {
/**
* DOCUMENT ME!
*/
private RefreshingProperties props;
/**
* Creates a new UpdateThread object.
*
* @param props DOCUMENT ME!
*/
UpdateThread(RefreshingProperties props) {
this.setDaemon(true);
this.props = props;
}
/**
* DOCUMENT ME!
*/
public void run() {
boolean running = true;
while(running) {
props.LOG.log(Level.FINEST,"RefeshingProperties thread check of " + props.url + " at " + new Date());
try {
Thread.sleep(props.recheckTime);
} catch(InterruptedException e) {
RefreshingProperties.LOG.log(Level.WARNING,"Interrupted.",e);
}
props.check();
}
}
}
private class ImportRefreshListener implements RefreshListener {
private RefreshingProperties target;
private boolean clobber;
ImportRefreshListener( RefreshingProperties target, boolean clobber ){
this.target = target;
this.clobber = clobber;
}
public void propertiesRefreshNotify(ReloadEvent event) {
target.fireEvents();
}
}
}
An utility class to ease up using property-file resource bundles.
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ---------------------
* ReadOnlyIterator.java
* ---------------------
* (C)opyright 2003-2008, by Thomas Morgner and Contributors.
*
* Original Author: Thomas Morgner;
* Contributor(s): David Gilbert (for Object Refinery Limited);
*
* $Id: ResourceBundleSupport.java,v 1.12 2008/12/18 09:57:32 mungady Exp $
*
* Changes
* -------
* 18-Dec-2008 : Use ResourceBundleWrapper - see JFreeChart patch 1607918 by
* Jess Thrysoee (DG);
*
*/
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JMenu;
import javax.swing.KeyStroke;
import sun.rmi.runtime.Log;
/**
* An utility class to ease up using property-file resource bundles.
* <p/>
* The class support references within the resource bundle set to minimize the
* occurence of duplicate keys. References are given in the format:
* <pre>
* a.key.name=@referenced.key
* </pre>
* <p/>
* A lookup to a key in an other resource bundle should be written by
* <pre>
* a.key.name=@@resourcebundle_name@referenced.key
* </pre>
*
* @author Thomas Morgner
*/
public class ResourceBundleSupport
{
/**
* The resource bundle that will be used for local lookups.
*/
private ResourceBundle resources;
/**
* A cache for string values, as looking up the cache is faster than looking
* up the value in the bundle.
*/
private TreeMap cache;
/**
* The current lookup path when performing non local lookups. This prevents
* infinite loops during such lookups.
*/
private TreeSet lookupPath;
/**
* The name of the local resource bundle.
*/
private String resourceBase;
/**
* The locale for this bundle.
*/
private Locale locale;
/**
* Creates a new instance.
*
* @param locale the locale.
* @param baseName the base name of the resource bundle, a fully qualified
* class name
*/
public ResourceBundleSupport(final Locale locale, final String baseName)
{
this(locale, ResourceBundleWrapper.getBundle(baseName, locale), baseName);
}
/**
* Creates a new instance.
*
* @param locale the locale for which this resource bundle is
* created.
* @param resourceBundle the resourcebundle
* @param baseName the base name of the resource bundle, a fully
* qualified class name
*/
protected ResourceBundleSupport(final Locale locale,
final ResourceBundle resourceBundle,
final String baseName)
{
if (locale == null)
{
throw new NullPointerException("Locale must not be null");
}
if (resourceBundle == null)
{
throw new NullPointerException("Resources must not be null");
}
if (baseName == null)
{
throw new NullPointerException("BaseName must not be null");
}
this.locale = locale;
this.resources = resourceBundle;
this.resourceBase = baseName;
this.cache = new TreeMap();
this.lookupPath = new TreeSet();
}
/**
* Creates a new instance.
*
* @param locale the locale for which the resource bundle is
* created.
* @param resourceBundle the resourcebundle
*/
public ResourceBundleSupport(final Locale locale,
final ResourceBundle resourceBundle)
{
this(locale, resourceBundle, resourceBundle.toString());
}
/**
* Creates a new instance.
*
* @param baseName the base name of the resource bundle, a fully qualified
* class name
*/
public ResourceBundleSupport(final String baseName)
{
this(Locale.getDefault(), ResourceBundleWrapper.getBundle(baseName),
baseName);
}
/**
* Creates a new instance.
*
* @param resourceBundle the resourcebundle
* @param baseName the base name of the resource bundle, a fully
* qualified class name
*/
protected ResourceBundleSupport(final ResourceBundle resourceBundle,
final String baseName)
{
this(Locale.getDefault(), resourceBundle, baseName);
}
/**
* Creates a new instance.
*
* @param resourceBundle the resourcebundle
*/
public ResourceBundleSupport(final ResourceBundle resourceBundle)
{
this(Locale.getDefault(), resourceBundle, resourceBundle.toString());
}
/**
* The base name of the resource bundle.
*
* @return the resource bundle"s name.
*/
protected final String getResourceBase()
{
return this.resourceBase;
}
/**
* Gets a string for the given key from this resource bundle or one of its
* parents. If the key is a link, the link is resolved and the referenced
* string is returned instead.
*
* @param key the key for the desired string
* @return the string for the given key
* @throws NullPointerException if <code>key</code> is <code>null</code>
* @throws MissingResourceException if no object for the given key can be
* found
* @throws ClassCastException if the object found for the given key is
* not a string
*/
public synchronized String getString(final String key)
{
final String retval = (String) this.cache.get(key);
if (retval != null)
{
return retval;
}
this.lookupPath.clear();
return internalGetString(key);
}
/**
* Performs the lookup for the given key. If the key points to a link the
* link is resolved and that key is looked up instead.
*
* @param key the key for the string
* @return the string for the given key
*/
protected String internalGetString(final String key)
{
if (this.lookupPath.contains(key))
{
throw new MissingResourceException
("InfiniteLoop in resource lookup",
getResourceBase(), this.lookupPath.toString());
}
final String fromResBundle = this.resources.getString(key);
if (fromResBundle.startsWith("@@"))
{
// global forward ...
final int idx = fromResBundle.indexOf("@", 2);
if (idx == -1)
{
throw new MissingResourceException
("Invalid format for global lookup key.", getResourceBase(), key);
}
try
{
final ResourceBundle res = ResourceBundleWrapper.getBundle
(fromResBundle.substring(2, idx));
return res.getString(fromResBundle.substring(idx + 1));
}
catch (Exception e)
{
System.out.println("Error during global lookup:"+ e);
throw new MissingResourceException
("Error during global lookup", getResourceBase(), key);
}
}
else if (fromResBundle.startsWith("@"))
{
// local forward ...
final String newKey = fromResBundle.substring(1);
this.lookupPath.add(key);
final String retval = internalGetString(newKey);
this.cache.put(key, retval);
return retval;
}
else
{
this.cache.put(key, fromResBundle);
return fromResBundle;
}
}
/**
* Returns an scaled icon suitable for buttons or menus.
*
* @param key the name of the resource bundle key
* @param large true, if the image should be scaled to 24x24, or false for
* 16x16
* @return the icon.
*/
public Icon getIcon(final String key, final boolean large)
{
final String name = getString(key);
return createIcon(name, true, large);
}
/**
* Returns an unscaled icon.
*
* @param key the name of the resource bundle key
* @return the icon.
*/
public Icon getIcon(final String key)
{
final String name = getString(key);
return createIcon(name, false, false);
}
/**
* Returns the mnemonic stored at the given resourcebundle key. The mnemonic
* should be either the symbolic name of one of the KeyEvent.VK_* constants
* (without the "VK_") or the character for that key.
* <p/>
* For the enter key, the resource bundle would therefore either contain
* "ENTER" or "\n".
* <pre>
* a.resourcebundle.key=ENTER
* an.other.resourcebundle.key=\n
* </pre>
*
* @param key the resourcebundle key
* @return the mnemonic
*/
public Integer getMnemonic(final String key)
{
final String name = getString(key);
return createMnemonic(name);
}
/**
* Returns an optional mnemonic.
*
* @param key the key.
*
* @return The mnemonic.
*/
public Integer getOptionalMnemonic(final String key)
{
final String name = getString(key);
if (name != null && name.length() > 0)
{
return createMnemonic(name);
}
return null;
}
/**
* Returns the keystroke stored at the given resourcebundle key.
* <p/>
* The keystroke will be composed of a simple key press and the plattform"s
* MenuKeyMask.
* <p/>
* The keystrokes character key should be either the symbolic name of one of
* the KeyEvent.VK_* constants or the character for that key.
* <p/>
* For the "A" key, the resource bundle would therefore either contain
* "VK_A" or "a".
* <pre>
* a.resourcebundle.key=VK_A
* an.other.resourcebundle.key=a
* </pre>
*
* @param key the resourcebundle key
* @return the mnemonic
* @see Toolkit#getMenuShortcutKeyMask()
*/
public KeyStroke getKeyStroke(final String key)
{
return getKeyStroke(key, getMenuKeyMask());
}
/**
* Returns an optional key stroke.
*
* @param key the key.
*
* @return The key stroke.
*/
public KeyStroke getOptionalKeyStroke(final String key)
{
return getOptionalKeyStroke(key, getMenuKeyMask());
}
/**
* Returns the keystroke stored at the given resourcebundle key.
* <p/>
* The keystroke will be composed of a simple key press and the given
* KeyMask. If the KeyMask is zero, a plain Keystroke is returned.
* <p/>
* The keystrokes character key should be either the symbolic name of one of
* the KeyEvent.VK_* constants or the character for that key.
* <p/>
* For the "A" key, the resource bundle would therefore either contain
* "VK_A" or "a".
* <pre>
* a.resourcebundle.key=VK_A
* an.other.resourcebundle.key=a
* </pre>
*
* @param key the resourcebundle key.
* @param mask the mask.
*
* @return the mnemonic
* @see Toolkit#getMenuShortcutKeyMask()
*/
public KeyStroke getKeyStroke(final String key, final int mask)
{
final String name = getString(key);
return KeyStroke.getKeyStroke(createMnemonic(name).intValue(), mask);
}
/**
* Returns an optional key stroke.
*
* @param key the key.
* @param mask the mask.
*
* @return The key stroke.
*/
public KeyStroke getOptionalKeyStroke(final String key, final int mask)
{
final String name = getString(key);
if (name != null && name.length() > 0)
{
return KeyStroke.getKeyStroke(createMnemonic(name).intValue(), mask);
}
return null;
}
/**
* Returns a JMenu created from a resource bundle definition.
* <p/>
* The menu definition consists of two keys, the name of the menu and the
* mnemonic for that menu. Both keys share a common prefix, which is
* extended by ".name" for the name of the menu and ".mnemonic" for the
* mnemonic.
* <p/>
* <pre>
* # define the file menu
* menu.file.name=File
* menu.file.mnemonic=F
* </pre>
* The menu definition above can be used to create the menu by calling
* <code>createMenu ("menu.file")</code>.
*
* @param keyPrefix the common prefix for that menu
* @return the created menu
*/
public JMenu createMenu(final String keyPrefix)
{
final JMenu retval = new JMenu();
retval.setText(getString(keyPrefix + ".name"));
retval.setMnemonic(getMnemonic(keyPrefix + ".mnemonic").intValue());
return retval;
}
/**
* Returns a URL pointing to a resource located in the classpath. The
* resource is looked up using the given key.
* <p/>
* Example: The load a file named "logo.gif" which is stored in a java
* package named "org.jfree.resources":
* <pre>
* mainmenu.logo=org/jfree/resources/logo.gif
* </pre>
* The URL for that file can be queried with: <code>getResource("mainmenu.logo");</code>.
*
* @param key the key for the resource
* @return the resource URL
*/
public URL getResourceURL(final String key)
{
final String name = getString(key);
final URL in = ObjectUtilities.getResource(name, ResourceBundleSupport.class);
if (in == null)
{
System.out.println("Unable to find file in the class path: " + name + "; key=" + key);
}
return in;
}
/**
* Attempts to load an image from classpath. If this fails, an empty image
* icon is returned.
*
* @param resourceName the name of the image. The name should be a global
* resource name.
* @param scale true, if the image should be scaled, false otherwise
* @param large true, if the image should be scaled to 24x24, or
* false for 16x16
* @return the image icon.
*/
private ImageIcon createIcon(final String resourceName, final boolean scale,
final boolean large)
{
final URL in = ObjectUtilities.getResource(resourceName, ResourceBundleSupport.class);
;
if (in == null)
{
System.out.println("Unable to find file in the class path: " + resourceName);
return new ImageIcon(createTransparentImage(1, 1));
}
final Image img = Toolkit.getDefaultToolkit().createImage(in);
if (img == null)
{
System.out.println("Unable to instantiate the image: " + resourceName);
return new ImageIcon(createTransparentImage(1, 1));
}
if (scale)
{
if (large)
{
return new ImageIcon(img.getScaledInstance(24, 24, Image.SCALE_SMOOTH));
}
return new ImageIcon(img.getScaledInstance(16, 16, Image.SCALE_SMOOTH));
}
return new ImageIcon(img);
}
/**
* Creates the Mnemonic from the given String. The String consists of the
* name of the VK constants of the class KeyEvent without VK_*.
*
* @param keyString the string
* @return the mnemonic as integer
*/
private Integer createMnemonic(final String keyString)
{
if (keyString == null)
{
throw new NullPointerException("Key is null.");
}
if (keyString.length() == 0)
{
throw new IllegalArgumentException("Key is empty.");
}
int character = keyString.charAt(0);
if (keyString.startsWith("VK_"))
{
try
{
final Field f = KeyEvent.class.getField(keyString);
final Integer keyCode = (Integer) f.get(null);
character = keyCode.intValue();
}
catch (Exception nsfe)
{
// ignore the exception ...
}
}
return new Integer(character);
}
/**
* Returns the plattforms default menu shortcut keymask.
*
* @return the default key mask.
*/
private int getMenuKeyMask()
{
try
{
return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
}
catch (UnsupportedOperationException he)
{
// headless exception extends UnsupportedOperation exception,
// but the HeadlessException is not defined in older JDKs...
return InputEvent.CTRL_MASK;
}
}
/**
* Creates a transparent image. These can be used for aligning menu items.
*
* @param width the width.
* @param height the height.
* @return the created transparent image.
*/
private BufferedImage createTransparentImage(final int width,
final int height)
{
final BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final int[] data = img.getRGB(0, 0, width, height, null, 0, width);
Arrays.fill(data, 0x00000000);
img.setRGB(0, 0, width, height, data, 0, width);
return img;
}
/**
* Creates a transparent icon. The Icon can be used for aligning menu
* items.
*
* @param width the width of the new icon
* @param height the height of the new icon
* @return the created transparent icon.
*/
public Icon createTransparentIcon(final int width, final int height)
{
return new ImageIcon(createTransparentImage(width, height));
}
/**
* Formats the message stored in the resource bundle (using a
* MessageFormat).
*
* @param key the resourcebundle key
* @param parameter the parameter for the message
* @return the formated string
*/
public String formatMessage(final String key, final Object parameter)
{
return formatMessage(key, new Object[]{parameter});
}
/**
* Formats the message stored in the resource bundle (using a
* MessageFormat).
*
* @param key the resourcebundle key
* @param par1 the first parameter for the message
* @param par2 the second parameter for the message
* @return the formated string
*/
public String formatMessage(final String key,
final Object par1,
final Object par2)
{
return formatMessage(key, new Object[]{par1, par2});
}
/**
* Formats the message stored in the resource bundle (using a
* MessageFormat).
*
* @param key the resourcebundle key
* @param parameters the parameter collection for the message
* @return the formated string
*/
public String formatMessage(final String key, final Object[] parameters)
{
final MessageFormat format = new MessageFormat(getString(key));
format.setLocale(getLocale());
return format.format(parameters);
}
/**
* Returns the current locale for this resource bundle.
*
* @return the locale.
*/
public Locale getLocale()
{
return this.locale;
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* --------------------------
* ResourceBundleWrapper.java
* --------------------------
* (C)opyright 2008, by Jess Thrysoee and Contributors.
*
* Original Author: Jess Thrysoee;
* Contributor(s): David Gilbert (for Object Refinery Limited);
*
* Changes
* -------
* 18-Dec-2008 : Version 1 (JT);
*
*/
/**
* Wrapper of ResourceBundle.getBundle() methods. This wrapper is introduced to
* avoid a dramatic performance penalty by superfluous resource (and classes
* loaded by Class.forName) lookups on web server in applets.
*
* <pre>
* public class AppletC extends javax.swing.JApplet {
* public void init() {
* ResourceBundleWrapper.removeCodeBase(getCodeBase(),
* (URLClassLoader) getClass().getClassLoader());
* ...
* </pre>
*
* @see
*
* @since 1.0.15
*/
class ResourceBundleWrapper {
/**
* A special class loader with no code base lookup. This field may be
* <code>null</code> (the field is only initialised if removeCodeBase() is
* called from an applet.
*/
private static URLClassLoader noCodeBaseClassLoader;
/**
* Private constructor.
*/
private ResourceBundleWrapper() {
// all methods are static, no need to instantiate
}
/**
* Instantiate a {@link URLClassLoader} for resource lookups where the
* codeBase URL is removed. This method is typically called from an
* applet"s init() method. If this method is never called, the
* <code>getBundle()</code> methods map to the standard
* {@link ResourceBundle} lookup methods.
*
* @param codeBase the codeBase URL.
* @param urlClassLoader the class loader.
*/
public static void removeCodeBase(URL codeBase,
URLClassLoader urlClassLoader) {
List urlsNoBase = new ArrayList();
URL[] urls = urlClassLoader.getURLs();
for (int i = 0; i < urls.length; i++) {
if (! urls[i].sameFile(codeBase)) {
urlsNoBase.add(urls[i]);
}
}
// substitute the filtered URL list
URL[] urlsNoBaseArray = (URL[]) urlsNoBase.toArray(new URL[0]);
noCodeBaseClassLoader = URLClassLoader.newInstance(urlsNoBaseArray);
}
/**
* Finds and returns the specified resource bundle.
*
* @param baseName the base name.
*
* @return The resource bundle.
*/
public static final ResourceBundle getBundle(String baseName) {
// the noCodeBaseClassLoader is configured by a call to the
// removeCodeBase() method, typically in the init() method of an
// applet...
if (noCodeBaseClassLoader != null) {
return ResourceBundle.getBundle(baseName, Locale.getDefault(),
noCodeBaseClassLoader);
}
else {
// standard ResourceBundle behaviour
return ResourceBundle.getBundle(baseName);
}
}
/**
* Finds and returns the specified resource bundle.
*
* @param baseName the base name.
* @param locale the locale.
*
* @return The resource bundle.
*/
public static final ResourceBundle getBundle(String baseName,
Locale locale) {
// the noCodeBaseClassLoader is configured by a call to the
// removeCodeBase() method, typically in the init() method of an
// applet...
if (noCodeBaseClassLoader != null) {
return ResourceBundle.getBundle(baseName, locale,
noCodeBaseClassLoader);
}
else {
// standard ResourceBundle behaviour
return ResourceBundle.getBundle(baseName, locale);
}
}
/**
* Maps directly to <code>ResourceBundle.getBundle(baseName, locale,
* loader)</code>.
*
* @param baseName the base name.
* @param locale the locale.
* @param loader the class loader.
*
* @return The resource bundle.
*/
public static ResourceBundle getBundle(String baseName, Locale locale,
ClassLoader loader) {
return ResourceBundle.getBundle(baseName, locale, loader);
}
}
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ---------------------
* ObjectUtilitiess.java
* ---------------------
* (C) Copyright 2003-2005, by Object Refinery Limited.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: ObjectUtilities.java,v 1.21 2008/09/10 09:24:41 mungady Exp $
*
* Changes
* -------
* 25-Mar-2003 : Version 1 (DG);
* 15-Sep-2003 : Fixed bug in clone(List) method (DG);
* 25-Nov-2004 : Modified clone(Object) method to fail with objects that
* cannot be cloned, added new deepClone(Collection) method.
* Renamed ObjectUtils --> ObjectUtilities (DG);
* 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
* 18-Aug-2005 : Added casts to suppress compiler warnings, as suggested in
* patch 1260622 (DG);
*
*/
/**
* A collection of useful static utility methods for handling classes and object
* instantiation.
*
* @author Thomas Morgner
*/
final class ObjectUtilities {
/**
* A constant for using the TheadContext as source for the classloader.
*/
public static final String THREAD_CONTEXT = "ThreadContext";
/**
* A constant for using the ClassContext as source for the classloader.
*/
public static final String CLASS_CONTEXT = "ClassContext";
/**
* By default use the thread context.
*/
private static String classLoaderSource = THREAD_CONTEXT;
/**
* The custom classloader to be used (if not null).
*/
private static ClassLoader classLoader;
/**
* Default constructor - private.
*/
private ObjectUtilities() {
}
/**
* Returns the internal configuration entry, whether the classloader of
* the thread context or the context classloader should be used.
*
* @return the classloader source, either THREAD_CONTEXT or CLASS_CONTEXT.
*/
public static String getClassLoaderSource() {
return classLoaderSource;
}
/**
* Defines the internal configuration entry, whether the classloader of
* the thread context or the context classloader should be used.
* <p/>
* This setting can only be defined using the API, there is no safe way
* to put this into an external configuration file.
*
* @param classLoaderSource the classloader source,
* either THREAD_CONTEXT or CLASS_CONTEXT.
*/
public static void setClassLoaderSource(final String classLoaderSource) {
ObjectUtilities.classLoaderSource = classLoaderSource;
}
/**
* Returns <code>true</code> if the two objects are equal OR both
* <code>null</code>.
*
* @param o1 object 1 (<code>null</code> permitted).
* @param o2 object 2 (<code>null</code> permitted).
* @return <code>true</code> or <code>false</code>.
*/
public static boolean equal(final Object o1, final Object o2) {
if (o1 == o2) {
return true;
}
if (o1 != null) {
return o1.equals(o2);
}
else {
return false;
}
}
/**
* Returns a hash code for an object, or zero if the object is
* <code>null</code>.
*
* @param object the object (<code>null</code> permitted).
* @return The object"s hash code (or zero if the object is
* <code>null</code>).
*/
public static int hashCode(final Object object) {
int result = 0;
if (object != null) {
result = object.hashCode();
}
return result;
}
/**
* Returns a clone of the specified object, if it can be cloned, otherwise
* throws a CloneNotSupportedException.
*
* @param object the object to clone (<code>null</code> not permitted).
* @return A clone of the specified object.
* @throws CloneNotSupportedException if the object cannot be cloned.
*/
public static Object clone(final Object object)
throws CloneNotSupportedException {
if (object == null) {
throw new IllegalArgumentException("Null "object" argument.");
}
try {
final Method method = object.getClass().getMethod("clone",
(Class[]) null);
if (Modifier.isPublic(method.getModifiers())) {
return method.invoke(object, (Object[]) null);
}
}
catch (NoSuchMethodException e) {
System.out.println("Object without clone() method is impossible.");
}
catch (IllegalAccessException e) {
System.out.println("Object.clone(): unable to call method.");
}
catch (InvocationTargetException e) {
System.out.println("Object without clone() method is impossible.");
}
throw new CloneNotSupportedException("Failed to clone.");
}
/**
* Returns a new collection containing clones of all the items in the
* specified collection.
*
* @param collection the collection (<code>null</code> not permitted).
* @return A new collection containing clones of all the items in the
* specified collection.
* @throws CloneNotSupportedException if any of the items in the collection
* cannot be cloned.
*/
public static Collection deepClone(final Collection collection)
throws CloneNotSupportedException {
if (collection == null) {
throw new IllegalArgumentException("Null "collection" argument.");
}
// all JDK-Collections are cloneable ...
// and if the collection is not clonable, then we should throw
// a CloneNotSupportedException anyway ...
final Collection result
= (Collection) ObjectUtilities.clone(collection);
result.clear();
final Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
final Object item = iterator.next();
if (item != null) {
result.add(clone(item));
}
else {
result.add(null);
}
}
return result;
}
/**
* Returns the classloader, which was responsible for loading the given
* class.
*
* @param c the classloader, either an application class loader or the
* boot loader.
* @return the classloader, never null.
* @throws SecurityException if the SecurityManager does not allow to grab
* the context classloader.
*/
public static ClassLoader getClassLoader(final Class c) {
final String localClassLoaderSource;
synchronized(ObjectUtilities.class)
{
if (classLoader != null) {
return classLoader;
}
localClassLoaderSource = classLoaderSource;
}
if ("ThreadContext".equals(localClassLoaderSource)) {
final ClassLoader threadLoader = Thread.currentThread().getContextClassLoader();
if (threadLoader != null) {
return threadLoader;
}
}
// Context classloader - do not cache ..
final ClassLoader applicationCL = c.getClassLoader();
if (applicationCL == null) {
return ClassLoader.getSystemClassLoader();
}
else {
return applicationCL;
}
}
/**
* Returns the resource specified by the <strong>absolute</strong> name.
*
* @param name the name of the resource
* @param c the source class
* @return the url of the resource or null, if not found.
*/
public static URL getResource(final String name, final Class c) {
final ClassLoader cl = getClassLoader(c);
if (cl == null) {
return null;
}
return cl.getResource(name);
}
/**
* Returns the resource specified by the <strong>relative</strong> name.
*
* @param name the name of the resource relative to the given class
* @param c the source class
* @return the url of the resource or null, if not found.
*/
public static URL getResourceRelative(final String name, final Class c) {
final ClassLoader cl = getClassLoader(c);
final String cname = convertName(name, c);
if (cl == null) {
return null;
}
return cl.getResource(cname);
}
/**
* Transform the class-relative resource name into a global name by
* appending it to the classes package name. If the name is already a
* global name (the name starts with a "/"), then the name is returned
* unchanged.
*
* @param name the resource name
* @param c the class which the resource is relative to
* @return the tranformed name.
*/
private static String convertName(final String name, Class c) {
if (name.startsWith("/")) {
// strip leading slash..
return name.substring(1);
}
// we cant work on arrays, so remove them ...
while (c.isArray()) {
c = c.getComponentType();
}
// extract the package ...
final String baseName = c.getName();
final int index = baseName.lastIndexOf(".");
if (index == -1) {
return name;
}
final String pkgName = baseName.substring(0, index);
return pkgName.replace(".", "/") + "/" + name;
}
/**
* Returns the inputstream for the resource specified by the
* <strong>absolute</strong> name.
*
* @param name the name of the resource
* @param context the source class
* @return the url of the resource or null, if not found.
*/
public static InputStream getResourceAsStream(final String name,
final Class context) {
final URL url = getResource(name, context);
if (url == null) {
return null;
}
try {
return url.openStream();
}
catch (IOException e) {
return null;
}
}
/**
* Returns the inputstream for the resource specified by the
* <strong>relative</strong> name.
*
* @param name the name of the resource relative to the given class
* @param context the source class
* @return the url of the resource or null, if not found.
*/
public static InputStream getResourceRelativeAsStream
(final String name, final Class context) {
final URL url = getResourceRelative(name, context);
if (url == null) {
return null;
}
try {
return url.openStream();
}
catch (IOException e) {
return null;
}
}
/**
* Tries to create a new instance of the given class. This is a short cut
* for the common bean instantiation code.
*
* @param className the class name as String, never null.
* @param source the source class, from where to get the classloader.
* @return the instantiated object or null, if an error occured.
*/
public static Object loadAndInstantiate(final String className,
final Class source) {
try {
final ClassLoader loader = getClassLoader(source);
final Class c = loader.loadClass(className);
return c.newInstance();
}
catch (Exception e) {
return null;
}
}
/**
* Tries to create a new instance of the given class. This is a short cut
* for the common bean instantiation code. This method is a type-safe method
* and will not instantiate the class unless it is an instance of the given
* type.
*
* @param className the class name as String, never null.
* @param source the source class, from where to get the classloader.
* @param type the type.
* @return the instantiated object or null, if an error occurred.
*/
public static Object loadAndInstantiate(final String className,
final Class source,
final Class type) {
try {
final ClassLoader loader = getClassLoader(source);
final Class c = loader.loadClass(className);
if (type.isAssignableFrom(c)) {
return c.newInstance();
}
}
catch (Exception e) {
return null;
}
return null;
}
/**
* Returns <code>true</code> if this is version 1.4 or later of the
* Java runtime.
*
* @return A boolean.
*/
public static boolean isJDK14() {
return false;
}
private static String[] parseVersions (String version)
{
if (version == null)
{
return new String[0];
}
final ArrayList versions = new ArrayList();
final StringTokenizer strtok = new StringTokenizer(version, ".");
while (strtok.hasMoreTokens())
{
versions.add (strtok.nextToken());
}
return (String[]) versions.toArray(new String[versions.size()]);
}
}
A utility class for replacing properties in strings.
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.util;
import java.util.Properties;
import java.io.File;
/**
* A utility class for replacing properties in strings.
*
* @author
* @version <tt>$Revision: 2898 $</tt>
*/
public final class StringPropertyReplacer
{
/** New line string constant */
public static final String NEWLINE = System.getProperty("line.separator", "\n");
/** File separator value */
private static final String FILE_SEPARATOR = File.separator;
/** Path separator value */
private static final String PATH_SEPARATOR = File.pathSeparator;
/** File separator alias */
private static final String FILE_SEPARATOR_ALIAS = "/";
/** Path separator alias */
private static final String PATH_SEPARATOR_ALIAS = ":";
// States used in property parsing
private static final int NORMAL = 0;
private static final int SEEN_DOLLAR = 1;
private static final int IN_BRACKET = 2;
/**
* Go through the input string and replace any occurance of ${p} with
* the System.getProperty(p) value. If there is no such property p defined,
* then the ${p} reference will remain unchanged.
*
* If the property reference is of the form ${p:v} and there is no such property p,
* then the default value v will be returned.
*
* If the property reference is of the form ${p1,p2} or ${p1,p2:v} then
* the primary and the secondary properties will be tried in turn, before
* returning either the unchanged input, or the default value.
*
* The property ${/} is replaced with System.getProperty("file.separator")
* value and the property ${:} is replaced with System.getProperty("path.separator").
*
* @param string - the string with possible ${} references
* @return the input string with all property references replaced if any.
* If there are no valid references the input string will be returned.
*/
public static String replaceProperties(final String string)
{
return replaceProperties(string, null);
}
/**
* Go through the input string and replace any occurance of ${p} with
* the props.getProperty(p) value. If there is no such property p defined,
* then the ${p} reference will remain unchanged.
*
* If the property reference is of the form ${p:v} and there is no such property p,
* then the default value v will be returned.
*
* If the property reference is of the form ${p1,p2} or ${p1,p2:v} then
* the primary and the secondary properties will be tried in turn, before
* returning either the unchanged input, or the default value.
*
* The property ${/} is replaced with System.getProperty("file.separator")
* value and the property ${:} is replaced with System.getProperty("path.separator").
*
* @param string - the string with possible ${} references
* @param props - the source for ${x} property ref values, null means use System.getProperty()
* @return the input string with all property references replaced if any.
* If there are no valid references the input string will be returned.
*/
public static String replaceProperties(final String string, final Properties props)
{
final char[] chars = string.toCharArray();
StringBuffer buffer = new StringBuffer();
boolean properties = false;
int state = NORMAL;
int start = 0;
for (int i = 0; i < chars.length; ++i)
{
char c = chars[i];
// Dollar sign outside brackets
if (c == "$" && state != IN_BRACKET)
state = SEEN_DOLLAR;
// Open bracket immediatley after dollar
else if (c == "{" && state == SEEN_DOLLAR)
{
buffer.append(string.substring(start, i - 1));
state = IN_BRACKET;
start = i - 1;
}
// No open bracket after dollar
else if (state == SEEN_DOLLAR)
state = NORMAL;
// Closed bracket after open bracket
else if (c == "}" && state == IN_BRACKET)
{
// No content
if (start + 2 == i)
{
buffer.append("${}"); // REVIEW: Correct?
}
else // Collect the system property
{
String value = null;
String key = string.substring(start + 2, i);
// check for alias
if (FILE_SEPARATOR_ALIAS.equals(key))
{
value = FILE_SEPARATOR;
}
else if (PATH_SEPARATOR_ALIAS.equals(key))
{
value = PATH_SEPARATOR;
}
else
{
// check from the properties
if (props != null)
value = props.getProperty(key);
else
value = System.getProperty(key);
if (value == null)
{
// Check for a default value ${key:default}
int colon = key.indexOf(":");
if (colon > 0)
{
String realKey = key.substring(0, colon);
if (props != null)
value = props.getProperty(realKey);
else
value = System.getProperty(realKey);
if (value == null)
{
// Check for a composite key, "key1,key2"
value = resolveCompositeKey(realKey, props);
// Not a composite key either, use the specified default
if (value == null)
value = key.substring(colon+1);
}
}
else
{
// No default, check for a composite key, "key1,key2"
value = resolveCompositeKey(key, props);
}
}
}
if (value != null)
{
properties = true;
buffer.append(value);
}
else
{
buffer.append("${");
buffer.append(key);
buffer.append("}");
}
}
start = i + 1;
state = NORMAL;
}
}
// No properties
if (properties == false)
return string;
// Collect the trailing characters
if (start != chars.length)
buffer.append(string.substring(start, chars.length));
// Done
return buffer.toString();
}
/**
* Try to resolve a "key" from the provided properties by
* checking if it is actually a "key1,key2", in which case
* try first "key1", then "key2". If all fails, return null.
*
* It also accepts "key1," and ",key2".
*
* @param key the key to resolve
* @param props the properties to use
* @return the resolved key or null
*/
private static String resolveCompositeKey(String key, Properties props)
{
String value = null;
// Look for the comma
int comma = key.indexOf(",");
if (comma > -1)
{
// If we have a first part, try resolve it
if (comma > 0)
{
// Check the first part
String key1 = key.substring(0, comma);
if (props != null)
value = props.getProperty(key1);
else
value = System.getProperty(key1);
}
// Check the second part, if there is one and first lookup failed
if (value == null && comma < key.length() - 1)
{
String key2 = key.substring(comma + 1);
if (props != null)
value = props.getProperty(key2);
else
value = System.getProperty(key2);
}
}
// Return whatever we"ve found or null
return value;
}
}
Converts specified map to java.util.Properties
/*
* Copyright 2006-2007 The Scriptella Project Team.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.ruparator;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
/**
* Collections utility methods.
*
* @author Fyodor Kupolov
* @version 1.0
*/
public final class CollectionUtils {
private CollectionUtils() {//Singleton
}
/**
* Comparator similar to {@link String#CASE_INSENSITIVE_ORDER}, but
* handles only ASCII characters
*/
private static final Comparator<String> ASCII_CASE_INSENSITIVE_ORDER = new Comparator<String>() {
public int compare(String s1, String s2) {
int n1 = s1.length(), n2 = s2.length();
int n = n1 < n2 ? n1 : n2;
for (int i = 0; i < n; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
if (c1 >= "A" && c1 <= "Z") { //Fast lower case
c1 = (char) (c1 | 0x20);
}
if (c2 >= "A" && c2 <= "Z") {
c2 = (char) (c2 | 0x20);
}
if (c1 != c2) {
return c1 - c2;
}
}
}
return n1 - n2;
}
};
/**
* Create a map optimized for case insensitive search for keys.
* The case insensitive rules are simplified to ASCII chars for performance reasons.
*
* @return case insensitive map.
*/
public static <V> Map<String, V> newCaseInsensitiveAsciiMap() {
return new TreeMap<String, V>(ASCII_CASE_INSENSITIVE_ORDER);
}
/**
* Returns parameterized version of {@link Properties} the instance
* remains the same.
*
* @param properties properties to represent as a map.
*/
@SuppressWarnings("unchecked")
public static Map<String, String> asMap(Properties properties) {
return (Map) properties;
}
/**
* Converts specified map to {@link java.util.Properties}. The keys and String values
* are migrated unchnaged, other types of values are {@link Object#toString() converted to String}.
* @param map map to convert.
* @return converted map as Properties.
*/
public static Properties asProperties(Map<String, ?> map) {
Properties props = new Properties();
for (Map.Entry<String, ?> entry : map.entrySet()) {
Object v = entry.getValue();
if (v != null) {
props.put(entry.getKey(), v.toString());
}
}
return props;
}
}
Converts Unicode into something that can be embedded in a java properties file
/*
JSPWiki - a JSP-based WikiWiki clone.
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
import java.security.SecureRandom;
import java.util.Random;
public class StringUtils
{
/**
* Converts a string from the Unicode representation into something that can be
* embedded in a java properties file. All references outside the ASCII range
* are replaced with \\uXXXX.
*
* @param s The string to convert
* @return the ASCII string
*/
public static String native2Ascii(String s)
{
StringBuffer sb = new StringBuffer();
for(int i = 0; i < s.length(); i++)
{
char aChar = s.charAt(i);
if ((aChar < 0x0020) || (aChar > 0x007e))
{
sb.append("\\");
sb.append("u");
sb.append(toHex((aChar >> 12) & 0xF));
sb.append(toHex((aChar >> 8) & 0xF));
sb.append(toHex((aChar >> 4) & 0xF));
sb.append(toHex( aChar & 0xF));
}
else
{
sb.append(aChar);
}
}
return sb.toString();
}
private static char toHex(int nibble)
{
final char[] hexDigit =
{
"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"
};
return hexDigit[nibble & 0xF];
}
}
Copy a set of properties from one Property to another.
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Properties;
/*
Derby - Class org.apache.derby.iapi.util.PropertyUtil
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
public class Main {
/**
* Copy a set of properties from one Property to another.
* <p>
*
* @param src_prop Source set of properties to copy from.
* @param dest_prop Dest Properties to copy into.
*
**/
public static void copyProperties(Properties src_prop, Properties dest_prop)
{
for (Enumeration propertyNames = src_prop.propertyNames();
propertyNames.hasMoreElements(); )
{
Object key = propertyNames.nextElement();
dest_prop.put(key, src_prop.get(key));
}
}
}
Create Properties from String array
/*
JSPWiki - a JSP-based WikiWiki clone.
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
import java.security.SecureRandom;
import java.util.Properties;
import java.util.Random;
public class StringUtils
{
/**
* Creates a Properties object based on an array which contains alternatively
* a key and a value. It is useful for generating default mappings.
* For example:
* <pre>
* String[] properties = { "jspwiki.property1", "value1",
* "jspwiki.property2", "value2 };
*
* Properties props = TextUtil.createPropertes( values );
*
* System.out.println( props.getProperty("jspwiki.property1") );
* </pre>
* would output "value1".
*
* @param values Alternating key and value pairs.
* @return Property object
* @see java.util.Properties
* @throws IllegalArgumentException if the property array is missing
* a value for a key.
* @since 2.2.
*/
public static Properties createProperties( String[] values )
throws IllegalArgumentException
{
if( values.length % 2 != 0 )
throw new IllegalArgumentException( "One value is missing.");
Properties props = new Properties();
for( int i = 0; i < values.length; i += 2 )
{
props.setProperty( values[i], values[i+1] );
}
return props;
}
}
Encapsulates java.util.Properties to add java primitives and some other java classes
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.TimeZone;
/**
* <strong>Internal class, do not use directly.</strong>
*
* This class encapsulates <code>java.util.Properties</code> to add java
* primitives and some other java classes.
*
* @author The Apache MINA Project (dev@mina.apache.org)
*/
public class BaseProperties extends Properties {
private static final long serialVersionUID = 5572645129592131953L;
/**
* Default constructor.
*/
public BaseProperties() {
}
/**
* Load existing property.
*/
public BaseProperties(final Properties prop) {
super(prop);
}
// ////////////////////////////////////////
// ////// Properties Get Methods ////////
// ////////////////////////////////////////
/**
* Get boolean value.
*/
public boolean getBoolean(final String str) throws Exception {
String prop = getProperty(str);
if (prop == null) {
throw new Exception(str + " not found");
}
return prop.toLowerCase().equals("true");
}
public boolean getBoolean(final String str, final boolean bol) {
try {
return getBoolean(str);
} catch (Exception ex) {
return bol;
}
}
/**
* Get integer value.
*/
public int getInteger(final String str) throws Exception {
String value = getProperty(str);
if (value == null) {
throw new Exception(str + " not found");
}
try {
return Integer.parseInt(value);
} catch (NumberFormatException ex) {
throw new Exception("BaseProperties.getInteger()", ex);
}
}
public int getInteger(final String str, final int intVal) {
try {
return getInteger(str);
} catch (Exception ex) {
return intVal;
}
}
/**
* Get long value.
*/
public long getLong(final String str) throws Exception {
String value = getProperty(str);
if (value == null) {
throw new Exception(str + " not found");
}
try {
return Long.parseLong(value);
} catch (NumberFormatException ex) {
throw new Exception("BaseProperties.getLong()", ex);
}
}
public long getLong(final String str, final long val) {
try {
return getLong(str);
} catch (Exception ex) {
return val;
}
}
/**
* Get double value.
*/
public double getDouble(final String str) throws Exception {
String value = getProperty(str);
if (value == null) {
throw new Exception(str + " not found");
}
try {
return Double.parseDouble(value);
} catch (NumberFormatException ex) {
throw new Exception("BaseProperties.getDouble()", ex);
}
}
public double getDouble(final String str, final double doubleVal) {
try {
return getDouble(str);
} catch (Exception ex) {
return doubleVal;
}
}
/**
* Get <code>InetAddress</code>.
*/
public InetAddress getInetAddress(final String str) throws Exception {
String value = getProperty(str);
if (value == null) {
throw new Exception(str + " not found");
}
try {
return InetAddress.getByName(value);
} catch (UnknownHostException ex) {
throw new Exception("Host " + value + " not found");
}
}
public InetAddress getInetAddress(final String str, final InetAddress addr) {
try {
return getInetAddress(str);
} catch (Exception ex) {
return addr;
}
}
/**
* Get <code>String</code>.
*/
public String getString(final String str) throws Exception {
String value = getProperty(str);
if (value == null) {
throw new Exception(str + " not found");
}
return value;
}
public String getString(final String str, final String s) {
try {
return getString(str);
} catch (Exception ex) {
return s;
}
}
/**
* Get <code>File</code> object.
*/
public File getFile(final String str) throws Exception {
String value = getProperty(str);
if (value == null) {
throw new Exception(str + " not found");
}
return new File(value);
}
public File getFile(final String str, final File fl) {
try {
return getFile(str);
} catch (Exception ex) {
return fl;
}
}
/**
* Get <code>Class</code> object
*/
public Class<?> getClass(final String str) throws Exception {
String value = getProperty(str);
if (value == null) {
throw new Exception(str + " not found");
}
try {
return Class.forName(value);
} catch (ClassNotFoundException ex) {
throw new Exception("BaseProperties.getClass()", ex);
}
}
public Class<?> getClass(final String str, final Class<?> cls) {
try {
return getClass(str);
} catch (Exception ex) {
return cls;
}
}
/**
* Get <code>TimeZone</code>
*/
public TimeZone getTimeZone(final String str) throws Exception {
String value = getProperty(str);
if (value == null) {
throw new Exception(str + " not found");
}
return TimeZone.getTimeZone(value);
}
public TimeZone getTimeZone(final String str, final TimeZone tz) {
try {
return getTimeZone(str);
} catch (Exception ex) {
return tz;
}
}
/**
* Get <code>DateFormat</code> object.
*/
public SimpleDateFormat getDateFormat(final String str) throws Exception {
String value = getProperty(str);
if (value == null) {
throw new Exception(str + " not found");
}
try {
return new SimpleDateFormat(value);
} catch (IllegalArgumentException e) {
throw new Exception("Date format was incorrect: " + value, e);
}
}
public SimpleDateFormat getDateFormat(final String str,
final SimpleDateFormat fmt) {
try {
return getDateFormat(str);
} catch (Exception ex) {
return fmt;
}
}
/**
* Get <code>Date</code> object.
*/
public Date getDate(final String str, final DateFormat fmt)
throws Exception {
String value = getProperty(str);
if (value == null) {
throw new Exception(str + " not found");
}
try {
return fmt.parse(value);
} catch (ParseException ex) {
throw new Exception("BaseProperties.getdate()", ex);
}
}
public Date getDate(final String str, final DateFormat fmt, final Date dt) {
try {
return getDate(str, fmt);
} catch (Exception ex) {
return dt;
}
}
// ////////////////////////////////////////
// ////// Properties Set Methods ////////
// ////////////////////////////////////////
/**
* Set boolean value.
*/
public void setProperty(final String key, final boolean val) {
setProperty(key, String.valueOf(val));
}
/**
* Set integer value.
*/
public void setProperty(final String key, final int val) {
setProperty(key, String.valueOf(val));
}
/**
* Set double value.
*/
public void setProperty(final String key, final double val) {
setProperty(key, String.valueOf(val));
}
/**
* Set float value.
*/
public void setProperty(final String key, final float val) {
setProperty(key, String.valueOf(val));
}
/**
* Set long value.
*/
public void setProperty(final String key, final long val) {
setProperty(key, String.valueOf(val));
}
/**
* Set <code>InetAddress</code>.
*/
public void setInetAddress(final String key, final InetAddress val) {
setProperty(key, val.getHostAddress());
}
/**
* Set <code>File</code> object.
*/
public void setProperty(final String key, final File val) {
setProperty(key, val.getAbsolutePath());
}
/**
* Set <code>DateFormat</code> object.
*/
public void setProperty(final String key, final SimpleDateFormat val) {
setProperty(key, val.toPattern());
}
/**
* Set <code>TimeZone</code> object.
*/
public void setProperty(final String key, final TimeZone val) {
setProperty(key, val.getID());
}
/**
* Set <code>Date</code> object.
*/
public void setProperty(final String key, final Date val,
final DateFormat fmt) {
setProperty(key, fmt.format(val));
}
/**
* Set <code>Class</code> object.
*/
public void setProperty(final String key, final Class<?> val) {
setProperty(key, val.getName());
}
}
Extracts a specific property key subset from the known properties
/**
* Copyright 2007 University Of Southern California
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.IOException;
import java.util.Enumeration;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PropertiesHelper
extends Properties {
/**
* Adds new properties to an existing set of properties while
* substituting variables. This function will allow value
* substitutions based on other property values. Value substitutions
* may not be nested. A value substitution will be ${property.key},
* where the dollar-brace and close-brace are being stripped before
* looking up the value to replace it with. Note that the ${..}
* combination must be escaped from the shell.
*
* @param b is the set of properties to add to existing properties.
* @return the combined set of properties.
*/
protected Properties addProperties(Properties b) {
// initial
// Properties result = new Properties(this);
Properties sys = System.getProperties();
Pattern pattern = Pattern.rupile("\\$\\{[-a-zA-Z0-9._]+\\}");
for (Enumeration e = b.propertyNames(); e.hasMoreElements(); ) {
String key = (String) e.nextElement();
String value = b.getProperty(key);
// unparse value ${prop.key} inside braces
Matcher matcher = pattern.matcher(value);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
// extract name of properties from braces
String newKey = value.substring(matcher.start() + 2, matcher.end() - 1);
// try to find a matching value in result properties
String newVal = getProperty(newKey);
// if still not found, try system properties
if (newVal == null) {
newVal = sys.getProperty(newKey);
}
// replace braced string with the actual value or empty string
matcher.appendReplacement(sb, newVal == null ? "" : newVal);
}
matcher.appendTail(sb);
setProperty(key, sb.toString());
}
return this;
}
/**
* Adds new properties to an existing set of properties while
* substituting variables. This function will allow value
* substitutions based on other property values. Value substitutions
* may not be nested. A value substitution will be ${property.key},
* where the dollar-brace and close-brace are being stripped before
* looking up the value to replace it with. Note that the ${..}
* combination must be escaped from the shell.
*
* @param a is the initial set of known properties (besides System ones)
* @param b is the set of properties to add to a
* @return the combined set of properties from a and b.
*/
protected static Properties addProperties(Properties a, Properties b) {
// initial
Properties result = new Properties(a);
Properties sys = System.getProperties();
Pattern pattern = Pattern.rupile("\\$\\{[-a-zA-Z0-9._]+\\}");
for (Enumeration e = b.propertyNames(); e.hasMoreElements(); ) {
String key = (String) e.nextElement();
String value = b.getProperty(key);
// unparse value ${prop.key} inside braces
Matcher matcher = pattern.matcher(value);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
// extract name of properties from braces
String newKey = value.substring(matcher.start() + 2, matcher.end() - 1);
// try to find a matching value in result properties
String newVal = result.getProperty(newKey);
// if still not found, try system properties
if (newVal == null) {
newVal = sys.getProperty(newKey);
}
// replace braced string with the actual value or empty string
matcher.appendReplacement(sb, newVal == null ? "" : newVal);
}
matcher.appendTail(sb);
result.setProperty(key, sb.toString());
}
// final
return result;
}
public PropertiesHelper() {
super();
}
public PropertiesHelper(Properties defaults) {
super(defaults);
}
protected PropertiesHelper(String propFilename, Properties defaults) throws
IOException,
MissingResourceException {
// create empty new instance
super(defaults);
}
/**
* Accessor: Overwrite any properties from within the program.
*
* @param key is the key to look up
* @param value is the new property value to place in the system.
* @return the old value, or null if it didn"t exist before.
*/
/** public Object setProperty(String key, String value) {
return System.setProperty(key, value);
}
**/
/**
* Accessor: access to the internal properties as read from file.
* An existing system property of the same key will have precedence
* over any project property. This method will remove leading and
* trailing ASCII control characters and whitespaces.
*
* @param key is the key to look up
* @return the value for the key, or null, if not found.
*/
/** public String getProperty(String key) {
String result =
System.getProperty(key, this.m_props.getProperty(key));
return (result == null ? result : result.trim());
}
**/
/**
* Accessor: access to the internal properties as read from file
* An existing system property of the same key will have precedence
* over any project property. This method will remove leading and
* trailing ASCII control characters and whitespaces.
*
* @param key is the key to look up
* @param defValue is a default to use, if no value can be found for the key.
* @return the value for the key, or the default value, if not found.
*/
/** public String getProperty(String key, String defValue) {
String result =
System.getProperty(key, this.m_props.getProperty(key, defValue));
return (result == null ? result : result.trim());
}
**/
/**
* Extracts a specific property key subset from the known properties.
* The prefix may be removed from the keys in the resulting dictionary,
* or it may be kept. In the latter case, exact matches on the prefix
* will also be copied into the resulting dictionary.
*
* @param prefix is the key prefix to filter the properties by.
* @param keepPrefix if true, the key prefix is kept in the resulting
* dictionary. As side-effect, a key that matches the prefix exactly
* will also be copied. If false, the resulting dictionary"s keys are
* shortened by the prefix. An exact prefix match will not be copied,
* as it would result in an empty string key.
* @return a property dictionary matching the filter key. May be
* an empty dictionary, if no prefix matches were found.
*
* @see #getProperty( String ) is used to assemble matches
*/
public Properties matchingSubset(String prefix, boolean keepPrefix) {
Properties result = new Properties();
// sanity check
if (prefix == null || prefix.length() == 0) {
return result;
}
String prefixMatch; // match prefix strings with this
String prefixSelf; // match self with this
if (prefix.charAt(prefix.length() - 1) != ".") {
// prefix does not end in a dot
prefixSelf = prefix;
prefixMatch = prefix + ".";
} else {
// prefix does end in one dot, remove for exact matches
prefixSelf = prefix.substring(0, prefix.length() - 1);
prefixMatch = prefix;
}
// POSTCONDITION: prefixMatch and prefixSelf are initialized!
// now add all matches into the resulting properties.
// Remark 1: #propertyNames() will contain the System properties!
// Remark 2: We need to give priority to System properties. This is done
// automatically by calling this class"s getProperty method.
String key;
for (Enumeration e = propertyNames(); e.hasMoreElements(); ) {
key = (String) e.nextElement();
if (keepPrefix) {
// keep full prefix in result, also copy direct matches
if (key.startsWith(prefixMatch) || key.equals(prefixSelf)) {
result.setProperty(key,
getProperty(key));
}
} else {
// remove full prefix in result, dont copy direct matches
if (key.startsWith(prefixMatch)) {
result.setProperty(key.substring(prefixMatch.length()),
getProperty(key));
}
}
}
// done
return result;
}
/**
* Extracts a specific property key subset from the properties passed.
* The prefix may be removed from the keys in the resulting dictionary,
* or it may be kept. In the latter case, exact matches on the prefix
* will also be copied into the resulting dictionary.
*
*
* @param prefix is the key prefix to filter the properties by.
* @param keepPrefix if true, the key prefix is kept in the resulting
* dictionary. As side-effect, a key that matches the prefix exactly
* will also be copied. If false, the resulting dictionary"s keys are
* shortened by the prefix. An exact prefix match will not be copied,
* as it would result in an empty string key.
* @return a property dictionary matching the filter key. May be
* an empty dictionary, if no prefix matches were found.
*
* @see #getProperty( String ) is used to assemble matches
*/
public static Properties matchingSubset(Properties properties, String prefix,
boolean keepPrefix) {
Properties result = new Properties();
// sanity check
if (prefix == null || prefix.length() == 0) {
return result;
}
String prefixMatch; // match prefix strings with this
String prefixSelf; // match self with this
if (prefix.charAt(prefix.length() - 1) != ".") {
// prefix does not end in a dot
prefixSelf = prefix;
prefixMatch = prefix + ".";
} else {
// prefix does end in one dot, remove for exact matches
prefixSelf = prefix.substring(0, prefix.length() - 1);
prefixMatch = prefix;
}
// POSTCONDITION: prefixMatch and prefixSelf are initialized!
// now add all matches into the resulting properties.
// Remark 1: #propertyNames() will contain the System properties!
// Remark 2: We need to give priority to System properties. This is done
// automatically by calling this class"s getProperty method.
String key;
for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
key = (String) e.nextElement();
if (keepPrefix) {
// keep full prefix in result, also copy direct matches
if (key.startsWith(prefixMatch) || key.equals(prefixSelf)) {
result.setProperty(key,
properties.getProperty(key));
}
} else {
// remove full prefix in result, dont copy direct matches
if (key.startsWith(prefixMatch)) {
result.setProperty(key.substring(prefixMatch.length()),
properties.getProperty(key));
}
}
}
// done
return result;
}
}
Gets strong-type-value property from a standard Properties
/*
JSPWiki - a JSP-based WikiWiki clone.
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
import java.security.SecureRandom;
import java.util.Properties;
import java.util.Random;
public class StringUtils
{
/**
* Gets an integer-valued property from a standard Properties
* list. If the value does not exist, or is a non-integer, returns defVal.
*
* @since 2.1.48.
* @param props The property set to look through
* @param key The key to look for
* @param defVal If the property is not found or is a non-integer, returns this value.
* @return The property value as an integer (or defVal).
*/
public static int getIntegerProperty( Properties props,
String key,
int defVal )
{
String val = props.getProperty( key );
return parseIntParameter( val, defVal );
}
/**
* Gets a boolean property from a standard Properties list.
* Returns the default value, in case the key has not been set.
* <P>
* The possible values for the property are "true"/"false", "yes"/"no", or
* "on"/"off". Any value not recognized is always defined as "false".
*
* @param props A list of properties to search.
* @param key The property key.
* @param defval The default value to return.
*
* @return True, if the property "key" was set to "true", "on", or "yes".
*
* @since 2.0.11
*/
public static boolean getBooleanProperty( Properties props,
String key,
boolean defval )
{
String val = props.getProperty( key );
if( val == null ) return defval;
return isPositive( val );
}
/**
* Fetches a String property from the set of Properties. This differs from
* Properties.getProperty() in a couple of key respects: First, property value
* is trim()med (so no extra whitespace back and front), and well, that"s it.
*
* @param props The Properties to search through
* @param key The property key
* @param defval A default value to return, if the property does not exist.
* @return The property value.
* @since 2.1.151
*/
public static String getStringProperty( Properties props,
String key,
String defval )
{
String val = props.getProperty( key );
if( val == null ) return defval;
return val.trim();
}
/**
* Returns true, if the string "val" denotes a positive string. Allowed
* values are "yes", "on", and "true". Comparison is case-insignificant.
* Null values are safe.
*
* @param val Value to check.
* @return True, if val is "true", "on", or "yes"; otherwise false.
*
* @since 2.0.26
*/
public static boolean isPositive( String val )
{
if( val == null ) return false;
val = val.trim();
return val.equalsIgnoreCase("true") || val.equalsIgnoreCase("on") ||
val.equalsIgnoreCase("yes");
}
/**
* Parses an integer parameter, returning a default value
* if the value is null or a non-number.
*
* @param value The value to parse
* @param defvalue A default value in case the value is not a number
* @return The parsed value (or defvalue).
*/
public static int parseIntParameter( String value, int defvalue )
{
int val = defvalue;
try
{
val = Integer.parseInt( value.trim() );
}
catch( Exception e ) {}
return val;
}
}
JDOM based XML properties
/*
* Copyright 2003-2005 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import com.jdon.util.jdom.DataUnformatFilter;
/**
* Provides the the ability to use simple XML property files. Each property is
* in the form X.Y.Z, which would map to an XML snippet of:
* <pre>
* <X>
* <Y>
* <Z>someValue</Z>
* </Y>
* </X>
* </pre>
*
* The XML file is passed in to the constructor and must be readable and
* writtable. Setting property values will automatically persist those value
* to disk or outputStream.
*/
public class XMLProperties {
private Document doc;
/**
* Parsing the XML file every time we need a property is slow. Therefore,
* we use a Map to cache property values that are accessed more than once.
*/
private Map propertyCache = new HashMap();
/**
* Creates a new XMLProperties object.
*
* @parm file the full path the file that properties should be read from
* and written to.
*/
public XMLProperties(String fileName) {
try {
SAXBuilder builder = new SAXBuilder();
// Strip formatting
DataUnformatFilter format = new DataUnformatFilter();
builder.setXMLFilter(format);
doc = builder.build(new File(fileName));
}
catch (Exception e) {
System.err.println("Error creating XML parser in "
+ "PropertyManager.java");
e.printStackTrace();
}
}
/**
* Creates a new XMLProperties object.
*
* @parm file the full path the file that properties should be read from
* and written to.
*/
public XMLProperties(InputStream inputStream) {
try {
SAXBuilder builder = new SAXBuilder();
// Strip formatting
DataUnformatFilter format = new DataUnformatFilter();
builder.setXMLFilter(format);
doc = builder.build(inputStream);
}
catch (Exception e) {
System.err.println("Error creating XML parser in "
+ "PropertyManager.java");
e.printStackTrace();
}
}
public XMLProperties(Reader reader) {
try {
SAXBuilder builder = new SAXBuilder();
// Strip formatting
DataUnformatFilter format = new DataUnformatFilter();
builder.setXMLFilter(format);
doc = builder.build(reader);
}
catch (Exception e) {
System.err.println("Error creating XML parser in "
+ "PropertyManager.java");
e.printStackTrace();
}
}
/**
* Returns the value of the specified property.
*
* @param name the name of the property to get.
* @return the value of the specified property.
*/
public String getProperty(String name) {
if (propertyCache.containsKey(name)) {
return (String)propertyCache.get(name);
}
String[] propName = parsePropertyName(name);
// Search for this property by traversing down the XML heirarchy.
Element element = doc.getRootElement();
for (int i = 0; i < propName.length; i++) {
element = element.getChild(propName[i]);
if (element == null) {
// This node doesn"t match this part of the property name which
// indicates this property doesn"t exist so return null.
return null;
}
}
// At this point, we found a matching property, so return its value.
// Empty strings are returned as null.
String value = element.getText();
if ("".equals(value)) {
return null;
}
else {
// Add to cache so that getting property next time is fast.
value = value.trim();
propertyCache.put(name, value);
return value;
}
}
/**
* Return all children property names of a parent property as a String array,
* or an empty array if the if there are no children. For example, given
* the properties <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, and <tt>X.Y.C</tt>, then
* the child properties of <tt>X.Y</tt> are <tt>A</tt>, <tt>B</tt>, and
* <tt>C</tt>.
*
* @param parent the name of the parent property.
* @return all child property values for the given parent.
*/
public String [] getChildrenProperties(String parent) {
String[] propName = parsePropertyName(parent);
// Search for this property by traversing down the XML heirarchy.
Element element = doc.getRootElement();
for (int i = 0; i < propName.length; i++) {
element = element.getChild(propName[i]);
if (element == null) {
// This node doesn"t match this part of the property name which
// indicates this property doesn"t exist so return empty array.
return new String [] { };
}
}
// We found matching property, return names of children.
List children = element.getChildren();
int childCount = children.size();
String [] childrenNames = new String[childCount];
for (int i=0; i<childCount; i++) {
childrenNames[i] = ((Element)children.get(i)).getName();
}
return childrenNames;
}
/**
* Sets the value of the specified property. If the property doesn"t
* currently exist, it will be automatically created.
*
* @param name the name of the property to set.
* @param value the new value for the property.
*/
public void setProperty(String name, String value) {
// Set cache correctly with prop name and value.
propertyCache.put(name, value);
String[] propName = parsePropertyName(name);
// Search for this property by traversing down the XML heirarchy.
Element element = doc.getRootElement();
for (int i=0; i<propName.length; i++) {
// If we don"t find this part of the property in the XML heirarchy
// we add it as a new node
if (element.getChild(propName[i]) == null) {
element.addContent(new Element(propName[i]));
}
element = element.getChild(propName[i]);
}
// Set the value of the property in this node.
element.setText(value);
}
/**
* Deletes the specified property.
*
* @param name the property to delete.
*/
public void deleteProperty(String name) {
String[] propName = parsePropertyName(name);
// Search for this property by traversing down the XML heirarchy.
Element element = doc.getRootElement();
for (int i=0; i<propName.length-1; i++) {
element = element.getChild(propName[i]);
// Can"t find the property so return.
if (element == null) {
return;
}
}
// Found the correct element to remove, so remove it...
element.removeChild(propName[propName.length-1]);
}
/**
* Saves the properties to disk as an XML document. A temporary file is
* used during the writing process for maximum safety.
*/
public synchronized void saveProperties(String fileName) {
OutputStream out = null;
boolean error = false;
File file = new File(fileName);
// Write data out to a temporary file first.
File tempFile = null;
try {
tempFile = new File(file.getParentFile(), file.getName() + ".tmp");
// Use JDOM"s XMLOutputter to do the writing and formatting. The
// file should always come out pretty-printed.
XMLOutputter outputter = new XMLOutputter();
out = new BufferedOutputStream(new FileOutputStream(tempFile));
outputter.output(doc, out);
}
catch (Exception e) {
e.printStackTrace();
// There were errors so abort replacing the old property file.
error = true;
}
finally {
try { out.close(); }
catch (Exception e) {
e.printStackTrace();
error = true;
}
}
// No errors occured, so we should be safe in replacing the old
if (!error) {
// Delete the old file so we can replace it.
file.delete();
// Rename the temp file. The delete and rename won"t be an
// automic operation, but we should be pretty safe in general.
// At the very least, the temp file should remain in some form.
tempFile.renameTo(file);
}
}
public synchronized void savePropertiesToStream(OutputStream out) {
boolean error = false;
try {
// Use JDOM"s XMLOutputter to do the writing and formatting. The
// file should always come out pretty-printed.
XMLOutputter outputter = new XMLOutputter();
outputter.output(doc, out);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try { out.close(); }
catch (Exception e) {
e.printStackTrace();
}
}
}
public synchronized void savePropertiesToStream(Writer writer) {
boolean error = false;
try {
// Use JDOM"s XMLOutputter to do the writing and formatting. The
// file should always come out pretty-printed.
XMLOutputter outputter = new XMLOutputter();
outputter.output(doc, writer);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try { writer.close(); }
catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Returns an array representation of the given Jive property. Jive
* properties are always in the format "prop.name.is.this" which would be
* represented as an array of four Strings.
*
* @param name the name of the Jive property.
* @return an array representation of the given Jive property.
*/
private String[] parsePropertyName(String name) {
// Figure out the number of parts of the name (this becomes the size
// of the resulting array).
int size = 1;
for (int i=0; i<name.length(); i++) {
if (name.charAt(i) == ".") {
size++;
}
}
String[] propName = new String[size];
// Use a StringTokenizer to tokenize the property name.
StringTokenizer tokenizer = new StringTokenizer(name, ".");
int i = 0;
while (tokenizer.hasMoreTokens()) {
propName[i] = tokenizer.nextToken();
i++;
}
return propName;
}
}
Load and save properties to files.
/*
* Copyright Javelin Software, All rights reserved.
*/
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
/**
* PropertiesUtil is used to load and save properties to files.
* <p>
* @author Robin Sharp
*/
public class PropertiesUtil
{
public PropertiesUtil()
{
}
public static Map getByValue( Properties properties, String value )
{
Map map = new HashMap();
Iterator iter = properties.entrySet().iterator();
do
{
if(!iter.hasNext() )
break;
java.util.Map.Entry entry = (java.util.Map.Entry)iter.next();
if(entry.getValue().equals(value ) )
map.put(entry.getKey(), entry.getValue() );
} while(true );
return map;
}
public static Properties load( Properties properties, String fileName ) throws IOException
{
if(fileName == null )
{
throw new IllegalArgumentException( "FileName is not set." );
}
else
{
return load( properties, new File(fileName ) );
}
}
public static Properties load( Properties properties, File file ) throws IOException
{
if(file == null )
{
throw new IllegalArgumentException( "File is not set." );
}
else
{
return load( properties, ((InputStream ) ( new FileInputStream(file ) )) );
}
}
public static Properties load( Properties properties, URL url ) throws IOException
{
if( url == null )
{
throw new IllegalArgumentException( "Url is not set." );
}
else
{
URLConnection connection = url.openConnection();
return load( properties, connection.getInputStream() );
}
}
public static Properties load( Properties properties, Class relativeClass, String relativeFileName ) throws IOException
{
if(relativeClass == null )
{
throw new IllegalArgumentException( "Relative Class is not set." );
}
if(relativeFileName == null )
{
throw new IllegalArgumentException( "Relative File Name is not set." );
}
else
{
return load( properties, relativeClass.getResourceAsStream(relativeFileName ) );
}
}
public static Properties load( Properties properties, InputStream inputStream ) throws IOException
{
try
{
if( properties == null )
{
throw new IllegalArgumentException( "Properties is not set." );
}
if( inputStream == null )
{
throw new IllegalArgumentException( "InputStream is not set." );
}
properties.load( new BufferedInputStream(inputStream ) );
}
finally
{
if(inputStream != null )
inputStream.close();
}
return properties;
}
public static void store( Properties properties, String fileName ) throws IOException
{
if(fileName == null )
{
throw new IllegalArgumentException( "FileName is not set." );
}
else
{
store( properties, new File(fileName ) );
return;
}
}
public static void store( Properties properties, File file )
throws IOException
{
if(file == null )
{
throw new IllegalArgumentException( "File is not set." );
} else
{
store( properties, ((OutputStream ) ( new FileOutputStream(file ) )) );
return;
}
}
public static void store( Properties properties, URL url ) throws IOException
{
if( url == null )
{
throw new IllegalArgumentException( "Url is not set." );
} else
{
URLConnection connection = url.openConnection();
connection.setDoOutput(true );
store( properties, connection.getOutputStream() );
return;
}
}
public static void store( Properties properties, Class relativeClass, String relativeFileName )
throws IOException
{
if(relativeClass == null )
throw new IllegalArgumentException( "Relative Class is not set." );
if(relativeFileName == null )
{
throw new IllegalArgumentException( "Relative File Name is not set." );
}
else
{
String className = relativeClass.getName().substring(relativeClass.getName().lastIndexOf( "." ) + 1);
URL url = relativeClass.getResource(String.valueOf(String.valueOf( className ) ).concat( ".class" ) );
String fileName = url.getFile();
fileName = String.valueOf(fileName.substring(1, fileName.length() - className.length() - 6) ) + String.valueOf(relativeFileName );
store( properties, fileName );
return;
}
}
public static void store( Properties properties, OutputStream outputStream ) throws IOException
{
try
{
if( properties == null )
{
throw new IllegalArgumentException( "Properties is not set." );
}
if( outputStream == null )
{
throw new IllegalArgumentException( "OutputStream is not set." );
}
properties.store( new BufferedOutputStream( outputStream ), null );
}
finally
{
if( outputStream != null )
{
outputStream.close();
}
}
}
public static void main(String args[])
{
try
{
System.out.println(load( new Properties(), "C:/data/ccm_wa/dordev/Countrywide~csdrzs/Countrywide/src/com/javelin/util/test.properties" ) );
System.out.println(load( new Properties(), new File( "C:/data/ccm_wa/dordev/Countrywide~csdrzs/Countrywide/src/com/javelin/util/test.properties" ) ));
System.out.println(load( new Properties(), new URL( "file:///C:/data/ccm_wa/dordev/Countrywide~csdrzs/Countrywide/src/com/javelin/util/test.properties" ) ));
System.out.println(load( new Properties(), PropertiesUtil.class, "test.properties" ) );
Properties properties = new Properties();
properties.put( "1", "2" );
properties.put( "2", "2" );
properties.put( "3", "3" );
store( properties, "C:/data/ccm_wa/dordev/Countrywide~csdrzs/Countrywide/src/com/javelin/util/test1.properties" );
store( properties, new File( "C:/data/ccm_wa/dordev/Countrywide~csdrzs/Countrywide/src/com/javelin/util/test2.properties" ) );
store( properties, PropertiesUtil.class, "test4.properties" );
System.out.println(getByValue( properties, "2" ) );
}
catch(Exception e )
{
e.printStackTrace();
}
}
}
Merge Properties Into Map
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Miscellaneous collection utility methods.
* Mainly for internal use within the framework.
*
* @author Juergen Hoeller
* @author Rob Harrop
* @since 1.1.3
*/
abstract class CollectionUtils {
/**
* Merge the given Properties instance into the given Map,
* copying all properties (key-value pairs) over.
* <p>Uses <code>Properties.propertyNames()</code> to even catch
* default properties linked into the original Properties instance.
* @param props the Properties instance to merge (may be <code>null</code>)
* @param map the target Map to merge the properties into
*/
public static void mergePropertiesIntoMap(Properties props, Map map) {
if (map == null) {
throw new IllegalArgumentException("Map must not be null");
}
if (props != null) {
for (Enumeration en = props.propertyNames(); en.hasMoreElements();) {
String key = (String) en.nextElement();
map.put(key, props.getProperty(key));
}
}
}
/**
* Return <code>true</code> if the supplied Collection is <code>null</code>
* or empty. Otherwise, return <code>false</code>.
* @param collection the Collection to check
* @return whether the given Collection is empty
*/
public static boolean isEmpty(Collection collection) {
return (collection == null || collection.isEmpty());
}
/**
* Return <code>true</code> if the supplied Map is <code>null</code>
* or empty. Otherwise, return <code>false</code>.
* @param map the Map to check
* @return whether the given Map is empty
*/
public static boolean isEmpty(Map map) {
return (map == null || map.isEmpty());
}
/**
* Check whether the given Collection contains the given element instance.
* <p>Enforces the given instance to be present, rather than returning
* <code>true</code> for an equal element as well.
* @param collection the Collection to check
* @param element the element to look for
* @return <code>true</code> if found, <code>false</code> else
*/
public static boolean containsInstance(Collection collection, Object element) {
if (collection != null) {
for (Iterator it = collection.iterator(); it.hasNext();) {
Object candidate = it.next();
if (candidate == element) {
return true;
}
}
}
return false;
}
/**
* Return <code>true</code> if any element in "<code>candidates</code>" is
* contained in "<code>source</code>"; otherwise returns <code>false</code>.
* @param source the source Collection
* @param candidates the candidates to search for
* @return whether any of the candidates has been found
*/
public static boolean containsAny(Collection source, Collection candidates) {
if (isEmpty(source) || isEmpty(candidates)) {
return false;
}
for (Iterator it = candidates.iterator(); it.hasNext();) {
if (source.contains(it.next())) {
return true;
}
}
return false;
}
/**
* Return the first element in "<code>candidates</code>" that is contained in
* "<code>source</code>". If no element in "<code>candidates</code>" is present in
* "<code>source</code>" returns <code>null</code>. Iteration order is
* {@link Collection} implementation specific.
* @param source the source Collection
* @param candidates the candidates to search for
* @return the first present object, or <code>null</code> if not found
*/
public static Object findFirstMatch(Collection source, Collection candidates) {
if (isEmpty(source) || isEmpty(candidates)) {
return null;
}
for (Iterator it = candidates.iterator(); it.hasNext();) {
Object candidate = it.next();
if (source.contains(candidate)) {
return candidate;
}
}
return null;
}
/**
* Find a value of the given type in the given Collection.
* @param collection the Collection to search
* @param type the type to look for
* @return a value of the given type found, or <code>null</code> if none
* @throws IllegalArgumentException if more than one value of the given type found
*/
public static Object findValueOfType(Collection collection, Class type) throws IllegalArgumentException {
if (isEmpty(collection)) {
return null;
}
Class typeToUse = (type != null ? type : Object.class);
Object value = null;
for (Iterator it = collection.iterator(); it.hasNext();) {
Object obj = it.next();
if (typeToUse.isInstance(obj)) {
if (value != null) {
throw new IllegalArgumentException("More than one value of type [" + typeToUse.getName() + "] found");
}
value = obj;
}
}
return value;
}
/**
* Determine whether the given Collection only contains a single unique object.
* @param collection the Collection to check
* @return <code>true</code> if the collection contains a single reference or
* multiple references to the same instance, <code>false</code> else
*/
public static boolean hasUniqueObject(Collection collection) {
if (isEmpty(collection)) {
return false;
}
boolean hasCandidate = false;
Object candidate = null;
for (Iterator it = collection.iterator(); it.hasNext();) {
Object elem = it.next();
if (!hasCandidate) {
hasCandidate = true;
candidate = elem;
}
else if (candidate != elem) {
return false;
}
}
return true;
}
}
Observable Properties
// ObservableProperties.java
// $Id: ObservableProperties.java,v 1.8 2000/08/16 21:37:58 ylafon Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
import java.io.File;
import java.util.Properties;
import java.util.StringTokenizer;
/**
* An enhanced property class that provides support to monitor changes. This
* class extends the basic properties class of Java, by providing monitoring
* support. It also provides more type conversion.
*
* @see PropertyMonitoring
*/
public class ObservableProperties extends Properties {
private static final boolean debug = false;
PropertyMonitoring observers[] = null;
int observers_count = 0;
/**
* Subscribe for property monitoring.
*
* @param observer
* The object that handles the PropertyMonitoring interface.
*/
public synchronized void registerObserver(PropertyMonitoring o) {
// Try looking for an empty slot:
for (int i = 0; i < observers.length; i++) {
if (observers[i] == null) {
observers[i] = o;
return;
}
}
// Add the observer to the registered oned, resizing array if needed
if (observers_count + 1 >= observers.length) {
PropertyMonitoring m[] = new PropertyMonitoring[observers.length * 2];
System.arraycopy(observers, 0, m, 0, observers.length);
observers = m;
}
observers[observers_count++] = o;
}
/**
* Unsubscribe this object from the observers list.
*
* @param observer
* The observer to unsubscribe.
* @return A boolean <strong>true</strong> if object was succesfully
* unsubscribed, <strong>false</strong> otherwise.
*/
public synchronized boolean unregisterObserver(PropertyMonitoring o) {
for (int i = 0; i < observers.length; i++) {
if (observers[i] == o) {
observers[i] = null;
return true;
}
}
return false;
}
/**
* Update a property value. Assign a value to a property. If the property
* value has really changed notify our observers of the change.
*
* @param name
* The name of the property to assign.
* @param value
* The new value for this property, or <strong>null</strong> if the
* property setting is to be cancelled.
* @return A boolean <strong>true</strong> if change was accepted by our
* observers, <strong>false</strong> otherwise.
*/
public synchronized boolean putValue(String name, String value) {
if (debug)
System.out.println("ObservableProperties: put " + name + "=[" + value + "]");
// If null value, remove the prop definition:
if (value == null) {
super.remove(name);
return true;
}
// Otherwise, proceed:
String old = (String) get(name);
if ((old == null) || (!old.equals(value))) {
super.put(name, value);
for (int i = 0; i < observers.length; i++) {
if (observers[i] == null)
continue;
if (debug)
System.out.println("ObservableProperties: notifies " + observers[i]);
if (!observers[i].propertyChanged(name)) {
if (old != null)
super.put(name, old);
return false;
}
}
}
return true;
}
/**
* Get this property value, as a boolean.
*
* @param name
* The name of the property to be fetched.
* @param def
* The default value, if the property isn"t defined.
* @return A Boolean instance.
*/
public boolean getBoolean(String name, boolean def) {
String v = getProperty(name, null);
if (v != null)
return "true".equalsIgnoreCase(v) ? true : false;
return def;
}
/**
* Get this property value, as a String.
*
* @param name
* The name of the property to be fetched.
* @param def
* The default value, if the property isn"t defined.
* @return An instance of String.
*/
public String getString(String name, String def) {
String v = getProperty(name, null);
if (v != null)
return v;
return def;
}
/**
* Get this property as a String array. By convention, properties that are get
* as string arrays should be encoded as a <strong>|</strong> separated list
* of Strings.
*
* @param name
* The property"s name.
* @param def
* The default value (if undefined).
* @return A String array, or <strong>null</strong> if the property is
* undefined.
*/
public String[] getStringArray(String name, String def[]) {
String v = getProperty(name, null);
if (v == null)
return def;
// Parse the property value:
StringTokenizer st = new StringTokenizer(v, "|");
int len = st.countTokens();
String ret[] = new String[len];
for (int i = 0; i < ret.length; i++) {
ret[i] = st.nextToken();
}
return ret;
}
/**
* Get this property value, as an integer.
*
* @param name
* The name of the property to be fetched.
* @param def
* The default value, if the property isn"t defined.
* @return An integer value.
*/
public int getInteger(String name, int def) {
String v = getProperty(name, null);
if (v != null) {
try {
if (v.startsWith("0x")) {
return Integer.valueOf(v.substring(2), 16).intValue();
}
if (v.startsWith("#")) {
return Integer.valueOf(v.substring(1), 16).intValue();
}
return Integer.valueOf(v).intValue();
} catch (NumberFormatException e) {
}
}
return def;
}
public long getLong(String name, long def) {
String v = getProperty(name, null);
if (v != null) {
try {
return Long.valueOf(v).longValue();
} catch (NumberFormatException e) {
}
}
return def;
}
/**
* Get this property value, as a double.
*
* @param name
* The name of the property.
* @param def
* The default value if undefined.
* @return A double value.
*/
public double getDouble(String name, double def) {
String v = getProperty(name, null);
if (v != null) {
try {
return Double.valueOf(v).doubleValue();
} catch (NumberFormatException ex) {
}
}
return def;
}
/**
* Get this property value, as a File.
*
* @param name
* The name of the property to be fetched.
* @param def
* The default value, if the property isn"t defined.
* @return An instance of File.
*/
public File getFile(String name, File def) {
String v = getProperty(name, null);
if (v != null)
return new File(v);
return def;
}
/**
* Build an httpdProperties instance from a Properties instance.
*
* @param props
* The Properties instance.
*/
public ObservableProperties(Properties props) {
super(props);
this.observers = new PropertyMonitoring[5];
this.observers_count = 0;
}
}
// PropertyMonitoring.java
// $Id: PropertyMonitoring.java,v 1.3 2000/08/16 21:37:58 ylafon Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
interface PropertyMonitoring {
/**
* The callback method, invoked when any property change occurs.
*
* @param name
* The name of the property that changed.
* @return A boolean, if <strong>true</strong>, accept the new property
* value, otherwise, reject it and reset the property to its old
* value.
*/
public boolean propertyChanged(String name);
}
Property access utility methods
/*
* Copyright 2004, 2005, 2006 Odysseus Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Property access utility methods.
*
* @author Christoph Beck
*/
public class PropertyUtils {
private static HashMap descriptorCache = new HashMap();
/**
* Get map with property descriptors for the specified bean class
*/
private static Map getPropertyDescriptors(Class clazz) {
HashMap map = (HashMap)descriptorCache.get(clazz);
if (map == null) {
BeanInfo beanInfo = null;
try {
beanInfo = Introspector.getBeanInfo(clazz);
} catch (IntrospectionException e) {
return Collections.EMPTY_MAP;
}
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
if (descriptors == null)
descriptors = new PropertyDescriptor[0];
map = new HashMap(descriptors.length);
for (int i = 0; i < descriptors.length; i++)
map.put(descriptors[i].getName(), descriptors[i]);
descriptorCache.put(clazz, map);
}
return map;
}
/**
* Get property names of the specified bean class
*/
public static Iterator getPropertyNames(Class clazz) {
return getPropertyDescriptors(clazz).keySet().iterator();
}
/**
* Get specified property descriptor
*/
public static PropertyDescriptor getPropertyDescriptor(Class clazz, String property) {
return (PropertyDescriptor)getPropertyDescriptors(clazz).get(property);
}
/**
* Get specified property value
*/
public static Object getProperty(Object bean, String property) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(), property);
if (descriptor == null)
throw new NoSuchMethodException("Cannot find property " + bean.getClass().getName() + "." + property);
Method method = descriptor.getReadMethod();
if (method == null)
throw new NoSuchMethodException("Cannot find getter for " + bean.getClass().getName() + "." + property);
return method.invoke(bean, null);
}
/**
* Get specified nested property value
*/
public static Object getNestedProperty(Object bean, String property) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (property.indexOf(".") > 0) {
String[] path = property.split("\\.");
for (int i = 0; i < path.length && bean != null; i++) {
bean = getProperty(bean, path[i]);
}
return bean;
} else {
return getProperty(bean, property);
}
}
/**
* Set specified property value
*/
public static void setProperty(Object bean, String property, Object value) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
PropertyDescriptor descriptor = getPropertyDescriptor(bean.getClass(), property);
if (descriptor == null)
throw new NoSuchMethodException("Cannot find property " + bean.getClass().getName() + "." + property);
Method method = descriptor.getWriteMethod();
if (method == null)
throw new NoSuchMethodException("Cannot find setter for " + bean.getClass().getName() + "." + property);
method.invoke(bean, new Object[]{ value });
}
/**
* Set nested property given by property path, starting at specified
* index. Dynamically create beans if necessary. Take care not to
* leave the bean changed if an exception occurs.
*/
private static void setNestedPropertyWithCreate(Object bean, String[] path, int start, Object value) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
for (int i = start; i < path.length - 1; i++) {
Object object = getProperty(bean, path[i]);
if (object == null) {
PropertyDescriptor descr =
getPropertyDescriptor(bean.getClass(), path[i]);
object = descr.getPropertyType().newInstance();
setNestedPropertyWithCreate(object, path, i + 1, value);
setProperty(bean, path[i], object);
return;
}
bean = object;
}
setProperty(bean, path[path.length - 1], value);
}
/**
* Set specified nested property value
*/
public static void setNestedProperty(Object bean, String property, Object value) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
int lastDot = property.lastIndexOf(".");
if (lastDot > 0) {
setNestedPropertyWithCreate(bean, property.split("\\."), 0, value);
} else {
setProperty(bean, property, value);
}
}
}
Property Loader
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Properties;
import java.util.ResourceBundle;
public class PropertyLoader {
public static Properties loadProperties(String name, ClassLoader loader) throws Exception {
if (name.startsWith("/"))
name = name.substring(1);
if (name.endsWith(SUFFIX))
name = name.substring(0, name.length() - SUFFIX.length());
Properties result = new Properties();
InputStream in = null;
if (loader == null)
loader = ClassLoader.getSystemClassLoader();
if (LOAD_AS_RESOURCE_BUNDLE) {
name = name.replace("/", ".");
ResourceBundle rb = ResourceBundle.getBundle(name, Locale.getDefault(), loader);
for (Enumeration keys = rb.getKeys(); keys.hasMoreElements();) {
result.put((String) keys.nextElement(), rb.getString((String) keys.nextElement()));
}
} else {
name = name.replace(".", "/");
if (!name.endsWith(SUFFIX))
name = name.concat(SUFFIX);
in = loader.getResourceAsStream(name);
if (in != null) {
result = new Properties();
result.load(in); // can throw IOException
}
}
in.close();
return result;
}
public static Properties loadProperties(final String name) throws Exception {
return loadProperties(name, Thread.currentThread().getContextClassLoader());
}
private static final boolean LOAD_AS_RESOURCE_BUNDLE = false;
private static final String SUFFIX = ".properties";
}
Read a set of properties from the received input stream, strip off any excess white space that exists in those property values,
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Properties;
/*
Derby - Class org.apache.derby.iapi.util.PropertyUtil
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
public class Main {
/**
* Read a set of properties from the received input stream, strip
* off any excess white space that exists in those property values,
* and then add those newly-read properties to the received
* Properties object; not explicitly removing the whitespace here can
* lead to problems.
*
* This method exists because of the manner in which the jvm reads
* properties from file--extra spaces are ignored after a _key_, but
* if they exist at the _end_ of a property decl line (i.e. as part
* of a _value_), they are preserved, as outlined in the Java API:
*
* "Any whitespace after the key is skipped; if the first non-
* whitespace character after the key is = or :, then it is ignored
* and any whitespace characters after it are also skipped. All
* remaining characters on the line become part of the associated
* element string."
*
* @param iStr An input stream from which the new properties are to be
* loaded (should already be initialized).
* @param prop A set of properties to which the properties from
* iStr will be added (should already be initialized).
* properties loaded from "iStr" (with the extra whitespace (if any)
* removed from all values), will be returned via the parameter.
*
**/
public static void loadWithTrimmedValues(InputStream iStr,
Properties prop) throws IOException {
if ((iStr == null) || (prop == null)) {
// shouldn"t happen; just ignore this call and return.
return;
}
// Else, load the properties from the received input stream.
Properties p = new Properties();
p.load(iStr);
// Now, trim off any excess whitespace, if any, and then
// add the properties from file to the received Properties
// set.
for (Enumeration propKeys = p.propertyNames();
propKeys.hasMoreElements();) {
// get the value, trim off the whitespace, then store it
// in the received properties object.
String tmpKey = (String)propKeys.nextElement();
String tmpValue = p.getProperty(tmpKey);
tmpValue = tmpValue.trim();
prop.put(tmpKey, tmpValue);
}
return;
}
}
Represents a persistent set of properties
/*
* Copyright 2006-2007 The Scriptella Project Team.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* Represents a persistent set of properties.
* <p>This class is a replacement for {@link Properties} class.
* <p>Please note that {@link #put(String,Object)} has additional semantics.
*
* @author Fyodor Kupolov
* @version 1.0
*/
public class PropertiesMap implements Map<String, Object> {
private Map<String, Object> props;
public PropertiesMap() {
props = new LinkedHashMap<String, Object>();
}
public PropertiesMap(int initialCapacity) {
props = new LinkedHashMap<String, Object>(initialCapacity);
}
public PropertiesMap(Map<String, ?> props) {
this(props.size());
putAll(props);
}
/**
* Creates a properties map from the stream.
*
* @param is stream to {@link #load(java.io.InputStream) load} properties from.
* @throws IOException if I/O error occurs
* @see #load(java.io.InputStream)
*/
public PropertiesMap(InputStream is) throws IOException {
this();
load(is);
}
public int size() {
return props.size();
}
public boolean isEmpty() {
return props.isEmpty();
}
public boolean containsKey(Object key) {
return props.containsKey(key);
}
public boolean containsValue(Object value) {
return props.containsValue(value);
}
public Object get(Object key) {
return props.get(key);
}
/**
* Put the property to underlying map.
* <p>The properties are immutable, i.e. if the property is already present in the map, the new value is ignored.
*
* @param key property name
* @param value property value
* @return value associated with specified key,
* or null if there was no mapping for key.
*/
public Object put(String key, Object value) {
Object old = props.get(key);
if (old == null) {
props.put(key, value);
}
return old;
}
public Object remove(Object key) {
return props.remove(key);
}
public void putAll(Map<? extends String, ? extends Object> t) {
for (Entry<? extends String, ? extends Object> entry : t.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
public void clear() {
props.clear();
}
public Set<String> keySet() {
return props.keySet();
}
public Collection<Object> values() {
return props.values();
}
public Set<Entry<String, Object>> entrySet() {
return props.entrySet();
}
public boolean equals(Object o) {
return props.equals(o);
}
public int hashCode() {
return props.hashCode();
}
/**
* Loads properties using {@link Properties#load(java.io.InputStream)}.
* <p>Properties order is preserved
*
* @param is input stream with properties.
* @throws IOException if I/O error occurs.
*/
public void load(InputStream is) throws IOException {
new Properties() { //Overrides Properties to preserve insertion order
public Object put(final Object k, final Object v) {
return PropertiesMap.this.put((String) k, v);
}
}.load(is);
}
public String toString() {
return String.valueOf(props);
}
}
Sorts a property list and turns the sorted list into a string.
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Properties;
/*
Derby - Class org.apache.derby.iapi.util.PropertyUtil
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
public class Main {
/**
* Sorts a property list and turns the sorted list into a string.
*
* @param list property list to sort
*
* @return a string version of the sorted list
*/
public static String sortProperties( Properties list )
{
// stringify them with no indentation
return sortProperties(list, null);
}
/**
* Sorts property list and print out each key=value pair prepended with
* specific indentation. If indent is null, do not prepend with
* indentation.
*
* The output string shows up in two styles, style 1 looks like
* { key1=value1, key2=value2, key3=value3 }
*
* style 2 looks like
* key1=value1
* key2=value2
* key3=value3
* where indent goes between the new line and the keys
*
* To get style 1, pass in a null indent
* To get sytle 2, pass in non-null indent (whatever you want to go before
* the key value)
*/
public static String sortProperties( Properties list, String indent )
{
int size = list == null ? 0 : list.size();
int count = 0;
String[] array = new String[size];
String key;
String value;
StringBuffer buffer;
// Calculate the number of properties in the property list and
// build an array of all the property names.
// We need to go thru the enumeration because Properties has a
// recursive list of defaults.
if (list != null)
{
for (Enumeration propertyNames = list.propertyNames();
propertyNames.hasMoreElements(); )
{
if (count == size)
{
// need to expand the array
size = size*2;
String[] expandedArray = new String[size];
System.arraycopy(array, 0, expandedArray, 0, count);
array = expandedArray;
}
key = (String) propertyNames.nextElement();
array[ count++ ] = key;
}
// now sort the array
java.util.Arrays.sort(array, 0, count);
}
// now stringify the array
buffer = new StringBuffer();
if (indent == null)
buffer.append( "{ " );
for ( int ictr = 0; ictr < count; ictr++ )
{
if ( ictr > 0 && indent == null)
buffer.append( ", " );
key = array[ ictr ];
if (indent != null)
buffer.append( indent );
buffer.append( key ); buffer.append( "=" );
value = list.getProperty( key, "MISSING_VALUE" );
buffer.append( value );
if (indent != null)
buffer.append( "\n" );
}
if (indent == null)
buffer.append( " }" );
return buffer.toString();
}
}
Sorts property list and print out each key=value pair prepended with specific indentation.
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Properties;
/*
Derby - Class org.apache.derby.iapi.util.PropertyUtil
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
public class Main {
/**
* Sorts property list and print out each key=value pair prepended with
* specific indentation. If indent is null, do not prepend with
* indentation.
*
* The output string shows up in two styles, style 1 looks like
* { key1=value1, key2=value2, key3=value3 }
*
* style 2 looks like
* key1=value1
* key2=value2
* key3=value3
* where indent goes between the new line and the keys
*
* To get style 1, pass in a null indent
* To get sytle 2, pass in non-null indent (whatever you want to go before
* the key value)
*/
public static String sortProperties( Properties list, String indent )
{
int size = list == null ? 0 : list.size();
int count = 0;
String[] array = new String[size];
String key;
String value;
StringBuffer buffer;
// Calculate the number of properties in the property list and
// build an array of all the property names.
// We need to go thru the enumeration because Properties has a
// recursive list of defaults.
if (list != null)
{
for (Enumeration propertyNames = list.propertyNames();
propertyNames.hasMoreElements(); )
{
if (count == size)
{
// need to expand the array
size = size*2;
String[] expandedArray = new String[size];
System.arraycopy(array, 0, expandedArray, 0, count);
array = expandedArray;
}
key = (String) propertyNames.nextElement();
array[ count++ ] = key;
}
// now sort the array
java.util.Arrays.sort(array, 0, count);
}
// now stringify the array
buffer = new StringBuffer();
if (indent == null)
buffer.append( "{ " );
for ( int ictr = 0; ictr < count; ictr++ )
{
if ( ictr > 0 && indent == null)
buffer.append( ", " );
key = array[ ictr ];
if (indent != null)
buffer.append( indent );
buffer.append( key ); buffer.append( "=" );
value = list.getProperty( key, "MISSING_VALUE" );
buffer.append( value );
if (indent != null)
buffer.append( "\n" );
}
if (indent == null)
buffer.append( " }" );
return buffer.toString();
}
}
Task to overwrite Properties
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.File;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;
/**
* Task to overwrite Properties: used for JRP, TRP and Torque.properties
*
* @author
* @created January 29, 2003
* @version $Id: OverwriteProperties.java 516448 2007-03-09 16:25:47Z ate $
*/
public class OverwriteProperties
{
/** The file to merge properties into */
protected File baseProperties;
/** The file to pull the properties from */
protected File properties;
/** The directory to look in for include files */
protected File includeRoot;
/** Description of the Field */
public boolean verbose = false;
/** An array of all the properties */
protected ArrayList baseArray = new ArrayList(1024);
/** An array of all the properties that will be removed */
protected ArrayList removeArray = new ArrayList(128);
/** Description of the Field */
protected HashMap baseMap = new HashMap();
/** What to use as a line seperator */
protected String lineSeparator = System.getProperty("line.separator", "\r\n");
/**
* Sets the file to merge properties into
*
* @param baseProperties The file path to merge properties into
*/
public void setBaseProperties(File baseProperties)
{
this.baseProperties = baseProperties;
}
/**
* Sets the file to pull properties from
*
* @param properties The file path to the pull the merge properties from
*/
public void setProperties(File properties)
{
this.properties = properties;
}
/**
* Sets the directory to look for includes in.
*
* @param includeRoot the directory to look in.
*/
public void setIncludeRoot(File includeRoot)
{
this.includeRoot = includeRoot;
}
/**
* Sets whether to output extra debugging info
*
* @param verbose The new verbose value
*/
public void setVerbose(boolean verbose)
{
this.verbose = verbose;
}
/**
* Return the file to merge propertie into
*
* @return The baseProperties value
*/
public File getBaseProperties()
{
return baseProperties;
}
/**
* Gets the properties attribute of the OverwriteProperties object
*
* @return The properties value
*/
public File getProperties()
{
return properties;
}
/**
* Gets the includeRoot attribute of the OverwriteProperties object
*
* @return The includeRoot value
*/
public File getIncludeRoot()
{
return includeRoot;
}
/**
* Gets the verbose attribute of the OverwriteProperties object
*
* @return The verbose value
*/
public boolean getVerbose()
{
return verbose;
}
/**
* The main program for the OverwriteProperties class
*
* @param args The command line arguments
* @exception Exception Description of the Exception
*/
public static void main(String[] args)
throws Exception
{
OverwriteProperties overwriteProperties = new OverwriteProperties();
try
{
if (args.length < 3)
{
System.out.println("Usage: java OverwriteProperties c:/temp/File1.props c:/temp/File2.props c:/include-root/");
System.out.println("Usage: File1 will be modified, new parameters from File 2 will be added,");
System.out.println(
"Usage: and same parameters will be updated. The include-root is where include files are found.");
throw new Exception("Incorrect number of arguments supplied");
}
overwriteProperties.setBaseProperties(new File(args[0]));
overwriteProperties.setProperties(new File(args[1]));
overwriteProperties.setIncludeRoot(new File(args[2]));
overwriteProperties.execute();
}
catch (FileNotFoundException ex)
{
System.err.println(ex.getMessage());
}
catch (IOException ex)
{
System.err.println(ex.getMessage());
}
catch (SecurityException ex)
{
System.err.println(ex.getMessage());
}
}
/** Description of the Method */
public void execute() throws FileNotFoundException, IOException, SecurityException
{
if (verbose)
{
System.out.println("Merging into file " + getBaseProperties() + " file " + getProperties());
}
if (!getBaseProperties().exists())
{
throw new FileNotFoundException("Could not find file:" + getBaseProperties());
}
if (!getProperties().exists())
{
throw new FileNotFoundException("Could not find file:" + getProperties());
}
if (!getIncludeRoot().exists() || !getIncludeRoot().isDirectory())
{
throw new FileNotFoundException("Could not find directory:" + getIncludeRoot());
}
BufferedReader reader = new BufferedReader(new FileReader(baseProperties));
int index = 0;
String key = null;
String line = null;
while ((line = reader.readLine()) != null)
{
StringTokenizer tokenizer = new StringTokenizer(line, "=");
baseArray.add(index, line);
if (verbose)
{
System.out.println("While reading baseArray[" + index + "] = " + line);
}
if (tokenizer.countTokens() >= 1
&& !line.startsWith("#")
&& !line.startsWith("include")
&& !line.startsWith("module.packages"))
{
key = tokenizer.nextToken().trim();
if (key != null && key.length() > 0)
{
baseMap.put(key, new Integer(index));
if (verbose)
{
System.out.println("baseMap[" + key + "," + index + "]");
}
}
}
index++;
}
reader.close();
if (verbose)
{
System.out.println("\nOverwrite with Delta\n");
}
readProperties(properties, index);
boolean flags[] = removeProperties();
baseArray.trimToSize();
writeToFile(flags);
}
/**
* Description of the Method
*
* @param flags Description of the Parameter
* @exception FileNotFoundException Description of the Exception
* @exception IOException Description of the Exception
*/
public void writeToFile(boolean[] flags)
throws FileNotFoundException, IOException
{
FileOutputStream writer = new FileOutputStream(baseProperties);
writer.flush();
for (int i = 0; i < baseArray.size(); i++)
{
if (true == flags[i])
{
if (verbose)
{
System.out.println("Skipping property[" + i + "] = " + baseArray.get(i));
}
continue;
}
if (verbose)
{
System.out.println("Writing property[" + i + "] = " + baseArray.get(i));
}
writer.write(((String) baseArray.get(i)).getBytes());
writer.write(lineSeparator.getBytes());
writer.flush();
}
writer.close();
}
/**
* Description of the Method
*
* @return Description of the Return Value
*/
public boolean[] removeProperties()
{
boolean flags[] = new boolean[baseArray.size()];
for (int i = 0; i < baseArray.size(); i++)
{
flags[i] = false;
}
for (int ix = 0; ix < removeArray.size(); ix++)
{
String prefix = (String) removeArray.get(ix);
for (int iy = 0; iy < baseArray.size(); iy++)
{
String line = (String) baseArray.get(iy);
if (line.startsWith(prefix))
{
flags[iy] = true;
if (verbose)
{
System.out.println("flagging removal of property: " + line);
}
}
}
}
return flags;
}
/**
* Reads in the properties from the specified file
*
* @param propFile Description of the Parameter
* @param index Description of the Parameter
* @exception FileNotFoundException Description of the Exception
* @exception IOException Description of the Exception
*/
public void readProperties(File propFile, int index)
throws FileNotFoundException, IOException
{
BufferedReader reader = new BufferedReader(new FileReader(propFile));
String key = null;
String line = null;
while ((line = reader.readLine()) != null)
{
StringTokenizer tokenizer = new StringTokenizer(line, "=");
int count = tokenizer.countTokens();
if (count == 2 && line.startsWith("include"))
{
key = tokenizer.nextToken().trim();
File includeFile = new File(includeRoot + tokenizer.nextToken().trim());
if (verbose)
{
System.out.println("include File = " + includeFile);
}
readProperties(includeFile, index);
continue;
}
if (count >= 1 && line.startsWith("module.packages"))
{
baseArray.add(index, line);
if (verbose)
{
System.out.println("Adding module.package to baseArray[" + index + "] = " + line);
}
index++;
key = line.trim();
if (baseMap.containsKey(key))
{
int ix = ((Integer) baseMap.get(key)).intValue();
baseArray.set(ix, line);
if (verbose)
{
System.out.println("Resetting baseArray[" + ix + "] = " + line);
}
}
continue;
}
if (count >= 1 && line.startsWith("-"))
{
// remove from base
String prefix = line.trim().substring(1);
removeArray.add(prefix);
if (verbose)
{
System.out.println("Flagging for removal = " + line);
}
continue;
}
if (count >= 1 && !line.startsWith("#"))
{
key = tokenizer.nextToken().trim();
if (key != null && key.length() > 0)
{
if (baseMap.containsKey(key))
{
int ix = ((Integer) baseMap.get(key)).intValue();
baseArray.set(ix, line);
if (verbose)
{
System.out.println("Resetting baseArray[" + ix + "] = " + line);
}
}
else
{
baseArray.add(index, line);
if (verbose)
{
System.out.println("Adding new entry to baseArray[" + index + "] = " + line);
}
baseMap.put(key, new Integer(index));
if (verbose)
{
System.out.println("baseMap[" + key + "," + index + "]");
}
index++;
}
}
}
}
reader.close();
}
}
The properties iterator iterates over a set of enumerated properties.
/**
*
* JFreeReport : a free Java reporting library
*
*
* Project Info: http://reporting.pentaho.org/
*
* (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------
* PropertiesIterator.java
* ------------
* (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
*/
import java.util.Iterator;
import java.util.Properties;
/**
* The properties iterator iterates over a set of enumerated properties. The
* properties are named by an optional prefix plus a number, which is counted up
* on each iteration: <p/>
* <ul>
* <li>prefix_0 </li>
* <li>prefix_1 </li>
* <li>prefix_2 </li>
* <li>... </li>
* </ul>
* <p/> The iterator iterates over all subsequent numbered proprties until the
* number-sequence is finished.
*
* @author Thomas Morgner
*
*/
public class PropertiesIterator implements Iterator {
/**
* The underlying properties collection.
*/
private Properties properties;
/**
* The property name prefix.
*/
private String prefix;
/**
* An incremental counter.
*/
private int count;
/**
* Creates a new properties iterator without an prefix.
*
* @param properties
* the underlying properties collection.
*/
public PropertiesIterator(final Properties properties) {
this(properties, null);
}
/**
* Creates a new properties iterator with the given prefix.
*
* @param properties
* the underlying properties collection.
* @param prefix
* a prefix for generating property names (null permitted).
*/
public PropertiesIterator(final Properties properties, final String prefix) {
if (properties == null) {
throw new NullPointerException();
}
this.properties = properties;
this.prefix = prefix;
this.count = 0;
}
/**
* Returns true if there is a property in the underlying collection with a
* name that matches the name returned by the getNextKey() method.
*
* @return true if there is another property with a name in the correct form.
*/
public boolean hasNext() {
return properties.containsKey(getNextKey());
}
/**
* Generates a property name in the form <prefix>
* <count>.
* <P>
* The <count> begins at 0,
* and is automatically incremented with each call to the next() method.
*
* @return the next key in the sequence
*
*/
private String getNextKey() {
if (prefix == null) {
return String.valueOf(count);
}
return prefix + String.valueOf(count);
}
/**
* Returns the property with a name the same as the name generated by the
* getNextKey() method, or null if there is no such property (that is, then
* end of the sequence has been reached).
*
* @return the property or null.
*/
public Object next() {
final String value = properties.getProperty(getNextKey());
count++;
return value;
}
/**
* Always throws UnsupportedOperationException as remove is not implemented
* for this iterator.
*
* @throws UnsupportedOperationException
* as remove is not supported.
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
XML configuration management
/*BEGIN_COPYRIGHT_BLOCK
*
* Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software is Open Source Initiative approved Open Source Software.
* Open Source Initative Approved is a trademark of the Open Source Initiative.
*
* This file is part of DrJava. Download the current version of this project
* from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
*
* END_COPYRIGHT_BLOCK*/
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.*;
/**
* XML configuration management.
* <p/>
* This class uses DOM paths of a specific form to refer to nodes in the XML document.
* Consider this XML structure:
* <foo a="foo.a">
* <bar>abc</bar>
* <fum fee="xyz">def</fum>
* </foo>
* The path "foo/bar" refers to the value "abc".
* The path "foo/fum" refers to the value "def".
* If this form is used, there may be only #text or #comment nodes in the node. All #text nodes will be
* concatenated and then stripped of whitespace at the beginning and the end.
* The path "foo/fum.fee" refers to the value "xyz".
* The path "foo.a" refers to the value "foo.a".
*
* When using getMultiple, any node or attribute name can be substituted with "*" to get all elements:
* The path "foo/*" returns both the value "abc" and "def".
* @author Mathias Ricken
*/
public class XMLConfig {
/** Newline string.
*/
public static final String NL = System.getProperty("line.separator");
/** XML document.
*/
private Document _document;
/** XMLConfig to delegate to, or null.
*/
private XMLConfig _parent = null;
/** Node where this XMLConfig starts if delegation is used, or null.
*/
private Node _startNode = null;
/** Creates an empty configuration.
*/
public XMLConfig() {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
_document = builder.newDocument(); // Create from whole cloth
// NOTE: not 1.4 compatible -- _document.setXmlStandalone(true);
}
catch(ParserConfigurationException e) {
e.printStackTrace();
}
}
/** Creates a configuration from an input stream.
* @param is input stream
*/
public XMLConfig(InputStream is) {
init(new InputSource(is));
}
/** Creates a configuration from a reader.
* @param r reader
*/
public XMLConfig(Reader r) {
init(new InputSource(r));
}
/** Creates a configuration that is a part of another configuration, starting at the specified node.
* @param parent the configuration that contains this part
* @param node the node in the parent configuration where this part starts
*/
public XMLConfig(XMLConfig parent, Node node) {
if ((parent==null) || (node==null)) { throw new XMLConfigException("Error in ctor: parent or node is null"); }
_parent = parent;
_startNode = node;
_document = null;
}
/** Initialize this XML configuration.
* @param is the XML input source
*/
private void init(InputSource is) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
_document = builder.parse(is);
// NOTE: not 1.4 compatible -- _document.setXmlStandalone(true);
}
catch(Exception e) {
throw new XMLConfigException("Error in ctor", e);
}
_document.normalize();
}
/** Creates a configuration from a file.
* @param f file
*/
public XMLConfig(File f) {
try {
init(new InputSource(new FileInputStream(f)));
}
catch(FileNotFoundException e) {
throw new XMLConfigException("Error in ctor", e);
}
}
/** Creates a configuration from a file name.
* @param filename file name
*/
public XMLConfig(String filename) {
try {
init(new InputSource(new FileInputStream(filename)));
}
catch(FileNotFoundException e) {
throw new XMLConfigException("Error in ctor", e);
}
}
public boolean isDelegated() { return (_parent!=null); }
/** Saves configuration to an output stream
* @param os output stream
*/
public void save(OutputStream os) {
if (isDelegated()) { _parent.save(os); return; }
// Prepare the DOM document for writing
Source source = new DOMSource(_document);
/*
// Prepare the output file
Result result = new StreamResult(os);
*/
// Write the DOM document to the file
try {
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", Integer.valueOf(2));
Transformer t = tf.newTransformer();
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.transform(source, new StreamResult(new OutputStreamWriter(os, "utf-8")));
/*
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
xformer.transform(source, result);
*/
}
catch(TransformerException e) {
throw new XMLConfigException("Error in save", e);
}
catch(UnsupportedEncodingException e) {
throw new XMLConfigException("Error in save", e);
}
}
/** Saves configuration to a file.
* @param f file
*/
public void save(File f) {
if (isDelegated()) { _parent.save(f); return; }
FileOutputStream fos = null;
try {
fos = new FileOutputStream(f);
save(fos);
}
catch(FileNotFoundException e) {
throw new XMLConfigException("Error in save", e);
}
finally {
try {
if (fos!=null) fos.close();
}
catch(IOException ioe) { /* ignore exception when closing */ }
}
}
/** Saves configuration to a file specified by a file name.
* @param filename file name
*/
public void save(String filename) {
save(new File(filename));
}
// ----- String ------
/** Returns the value as specified by the DOM path.
* @param path DOM path
* @return value.
*/
public String get(String path) {
List<String> r = getMultiple(path);
if (r.size()!=1) throw new XMLConfigException("Number of results != 1");
return r.get(0);
}
/** Returns the value as specified by the DOM path.
* @param path DOM path
* @param root node where the search should start
* @return value.
*/
public String get(String path, Node root) {
List<String> r = getMultiple(path, root);
if (r.size()!=1) throw new XMLConfigException("Number of results != 1");
return r.get(0);
}
/** Returns the value as specified by the DOM path, or the default value if the value could not be found.
* @param path DOM path
* @param defaultVal default value in case value is not in DOM
* @return value.
*/
public String get(String path, String defaultVal) {
try {
return get(path);
}
catch(XMLConfigException e) {
return defaultVal;
}
}
/** Returns the value as specified by the DOM path, or the default value if the value could not be found.
* @param path DOM path
* @param root node where the search should start
* @param defaultVal default value in case value is not in DOM
* @return value.
*/
public String get(String path, Node root, String defaultVal) {
try {
return get(path, root);
}
catch(XMLConfigException e) {
return defaultVal;
}
}
// ----- Integer ------
/** Returns the value as specified by the DOM path.
* @param path DOM path
* @return value.
* @throws IllegalArgumentException
*/
public int getInt(String path) {
List<String> r = getMultiple(path);
if (r.size()!=1) throw new XMLConfigException("Number of results != 1");
try {
return Integer.valueOf(r.get(0));
}
catch(NumberFormatException nfe) { throw new IllegalArgumentException("Not an integer value.", nfe); }
}
/** Returns the value as specified by the DOM path.
* @param path DOM path
* @param root node where the search should start
* @return value.
* @throws IllegalArgumentException
*/
public int getInt(String path, Node root) {
List<String> r = getMultiple(path, root);
if (r.size()!=1) throw new XMLConfigException("Number of results != 1");
try {
return Integer.valueOf(r.get(0));
}
catch(NumberFormatException nfe) { throw new IllegalArgumentException("Not an integer value.", nfe); }
}
/** Returns the value as specified by the DOM path, or the default value if the value could not be found.
* @param path DOM path
* @param defaultVal default value in case value is not in DOM
* @return value.
* @throws IllegalArgumentException
*/
public int getInt(String path, int defaultVal) {
try {
return getInt(path);
}
catch(XMLConfigException e) {
return defaultVal;
}
}
/** Returns the value as specified by the DOM path, or the default value if the value could not be found.
* @param path DOM path
* @param root node where the search should start
* @param defaultVal default value in case value is not in DOM
* @return value.
* @throws IllegalArgumentException
*/
public int getInt(String path, Node root, int defaultVal) {
try {
return getInt(path, root);
}
catch(XMLConfigException e) {
return defaultVal;
}
}
// ----- Boolean ------
/** Returns the value as specified by the DOM path.
* @param path DOM path
* @return value.
* @throws IllegalArgumentException
*/
public boolean getBool(String path) {
List<String> r = getMultiple(path);
if (r.size()!=1) throw new XMLConfigException("Number of results != 1");
String s = r.get(0).toLowerCase().trim();
if ((s.equals("true")) ||
(s.equals("yes")) ||
(s.equals("on"))) return true;
if ((s.equals("false")) ||
(s.equals("no")) ||
(s.equals("off"))) return false;
throw new IllegalArgumentException("Not a Boolean vlaue.");
}
/** Returns the value as specified by the DOM path.
* @param path DOM path
* @param root node where the search should start
* @return value.
* @throws IllegalArgumentException
*/
public boolean getBool(String path, Node root) {
List<String> r = getMultiple(path, root);
if (r.size()!=1) throw new XMLConfigException("Number of results != 1");
String s = r.get(0).toLowerCase().trim();
if ((s.equals("true")) ||
(s.equals("yes")) ||
(s.equals("on"))) return true;
if ((s.equals("false")) ||
(s.equals("no")) ||
(s.equals("off"))) return false;
throw new IllegalArgumentException("Not a Boolean vlaue.");
}
/** Returns the value as specified by the DOM path, or the default value if the value could not be found.
* @param path DOM path
* @param defaultVal default value in case value is not in DOM
* @return value.
* @throws IllegalArgumentException
*/
public boolean getBool(String path, boolean defaultVal) {
try {
return getBool(path);
}
catch(XMLConfigException e) {
return defaultVal;
}
}
/** Returns the value as specified by the DOM path, or the default value if the value could not be found.
* @param path DOM path
* @param root node where the search should start
* @param defaultVal default value in case value is not in DOM
* @return value.
* @throws IllegalArgumentException
*/
public boolean getBool(String path, Node root, boolean defaultVal) {
try {
return getBool(path, root);
}
catch(XMLConfigException e) {
return defaultVal;
}
}
// ----- Other -----
/** Returns the value as specified by the DOM path.
* @param path DOM path
* @return list of values.
*/
public List<String> getMultiple(String path) {
if (isDelegated()) { return getMultiple(path, _startNode); }
return getMultiple(path, _document);
}
/** Returns the value as specified by the DOM path.
* @param path DOM path
* @param root node where the search should start
* @return list of values.
*/
public List<String> getMultiple(String path, Node root) {
List<Node> accum = getNodes(path, root);
List<String> strings = new LinkedList<String>();
for(Node n: accum) {
if (n instanceof Attr) {
strings.add(n.getNodeValue());
}
else {
Node child;
String acc = "";
child = n.getFirstChild();
while(child!=null) {
if (child.getNodeName().equals("#text")) {
acc += " " + child.getNodeValue();
}
else if (child.getNodeName().equals("#comment")) {
// ignore
}
else {
throw new XMLConfigException("Node "+n.getNodeName()+" contained node "+child.getNodeName()+", but should only contain #text and #comment.");
}
child = child.getNextSibling();
}
strings.add(acc.trim());
}
}
return strings;
}
/** Returns the nodes as specified by the DOM path.
* @param path DOM path
* @return list of nodes.
*/
public List<Node> getNodes(String path) {
if (isDelegated()) { return getNodes(path, _startNode); }
return getNodes(path, _document);
}
/** Returns the nodes as specified by the DOM path.
* @param path DOM path
* @param root node where the search should start
* @return list of nodes.
*/
public List<Node> getNodes(String path, Node root) {
List<Node> accum = new LinkedList<Node>();
getMultipleHelper(path, root, accum, false);
return accum;
}
/** Returns the value as specified by the DOM path.
* @param path DOM path
* @param n node where the search begins
* @param accum accumulator
* @param dotRead whether a dot has been read
*/
private void getMultipleHelper(String path, Node n, List<Node> accum, boolean dotRead) {
int dotPos = path.indexOf(".");
boolean initialDot = (dotPos==0);
if ((path.length()>0) && (dotPos == -1) && (!path.endsWith("/"))) {
path = path + "/";
}
int slashPos = path.indexOf("/");
if(dotPos != -1 && path.indexOf(".", dotPos+1) != -1)
throw new XMLConfigException("An attribute cannot have subparts (foo.bar.fum and foo.bar/fum not allowed)");
if(dotPos != -1 && path.indexOf("/", dotPos+1) != -1)
throw new XMLConfigException("An attribute cannot have subparts (foo.bar.fum and foo.bar/fum not allowed)");
if (((slashPos > -1) || (dotPos > -1)) && !dotRead || initialDot) {
String nodeName;
if ((slashPos > -1) && ((dotPos == -1) || (slashPos < dotPos))) {
nodeName = path.substring(0, slashPos);
path = path.substring(slashPos+1);
}
else {
if (slashPos > -1) {
throw new XMLConfigException("An attribute cannot have subparts (foo.bar.fum and foo.bar/fum not allowed)");
}
if (!initialDot) {
nodeName = path.substring(0, dotPos);
path = path.substring(dotPos+1);
dotRead = true;
}
else {
path = path.substring(1);
getMultipleAddAttributesHelper(path, n, accum);
return;
}
}
Node child = n.getFirstChild();
if (nodeName.equals("*")) {
while(child!=null) {
if (!child.getNodeName().equals("#text") && !child.getNodeName().equals("#comment")) {
if (dotRead) {
getMultipleAddAttributesHelper(path, child, accum);
}
else {
getMultipleHelper(path, child, accum, false);
}
}
child = child.getNextSibling();
}
return;
}
else {
while(child!=null) {
if (child.getNodeName().equals(nodeName)) {
// found
if (dotRead) {
getMultipleAddAttributesHelper(path, child, accum);
}
else {
getMultipleHelper(path, child, accum, false);
}
}
child = child.getNextSibling();
}
return;
}
}
else {
accum.add(n);
}
}
private void getMultipleAddAttributesHelper(String path, Node n, List<Node> accum) {
if ((path.indexOf(".") > -1) || (path.indexOf("/") > -1)) {
throw new XMLConfigException("An attribute cannot have subparts (foo.bar.fum and foo.bar/fum not allowed)");
}
NamedNodeMap attrMap = n.getAttributes();
if (path.equals("*")) {
for(int i=0; i<attrMap.getLength(); ++i) {
Node attr = attrMap.item(i);
accum.add(attr);
}
}
else {
Node attr = attrMap.getNamedItem(path);
if (attr!=null) {
accum.add(attr);
}
}
}
/** Set the value of the node or attribute specified by the DOM path.
* @param path DOM path
* @param value node or attribute value
* @return the node that was created, or the parent node of the attribute if it was an attribute
*/
public Node set(String path, String value) {
if (isDelegated()) { return set(path, value, _startNode, true); }
return set(path, value, _document, true);
}
/** Set the value of the node or attribute specified by the DOM path.
* @param path DOM path
* @param value node or attribute value
* @param overwrite whether to overwrite (true) or add (false)
* @return the node that was created, or the parent node of the attribute if it was an attribute
*/
public Node set(String path, String value, boolean overwrite) {
if (isDelegated()) { return set(path, value, _startNode, overwrite); }
return set(path, value, _document, overwrite);
}
/** Set the value of the node or attribute specified by the DOM path.
* @param path DOM path
* @param value node or attribute value
* @param n node where the search should start
* @param overwrite whether to overwrite (true) or add (false) -- only applies for last node!
* @return the node that was created, or the parent node of the attribute if it was an attribute
*/
public Node set(String path, String value, Node n, boolean overwrite) {
if (isDelegated()) { return _parent.set(path, value, n, overwrite); }
int dotPos = path.lastIndexOf(".");
Node node;
if (dotPos==0) {
node = n;
}
else {
node = createNode(path, n, overwrite);
}
if (dotPos>=0) {
Element e = (Element)node;
e.setAttribute(path.substring(dotPos+1),value);
}
else {
node.appendChild(_document.createTextNode(value));
}
return node;
}
/** Create the node specified by the DOM path.
* @param path DOM path
* @return the node that was created, or the parent node of the attribute if it was an attribute
*/
public Node createNode(String path) {
if (isDelegated()) { return createNode(path, _startNode, true); }
return createNode(path, _document, true);
}
/** Create the node specified by the DOM path.
* @param path DOM path
* @param n node where the search should start, or null for the root
* @return the node that was created, or the parent node of the attribute if it was an attribute
*/
public Node createNode(String path, Node n) {
return createNode(path, n, true);
}
/** Create the node specified by the DOM path.
* @param path DOM path
* @param n node where the search should start, or null for the root
* @param overwrite whether to overwrite (true) or add (false) -- only applies for last node!
* @return the node that was created, or the parent node of the attribute if it was an attribute
*/
public Node createNode(String path, Node n, boolean overwrite) {
if (isDelegated()) { return _parent.createNode(path, n, overwrite); }
if (n==null) { n = _document; }
while(path.indexOf("/") > -1) {
Node child = null;
String nodeName = path.substring(0, path.indexOf("/"));
path = path.substring(path.indexOf("/")+1);
child = n.getFirstChild();
while(child!=null) {
if (child.getNodeName().equals(nodeName)) {
// found
n = child;
break;
}
child = child.getNextSibling();
}
if (child==null) {
// not found
child = _document.createElement(nodeName);
n.appendChild(child);
n = child;
}
}
String nodeName;
if (path.indexOf(".") > -1) {
nodeName = path.substring(0, path.indexOf("."));
}
else {
if (path.length()==0) {
throw new XMLConfigException("Cannot set node with empty name");
}
nodeName = path;
}
Node child = null;
if (nodeName.length()>0) {
if (overwrite) {
child = n.getFirstChild();
while(child!=null) {
if (child.getNodeName().equals(nodeName)) {
// found
n = child;
break;
}
child = child.getNextSibling();
}
if (child==null) {
child = _document.createElement(nodeName);
n.appendChild(child);
n = child;
}
}
else {
child = _document.createElement(nodeName);
n.appendChild(child);
n = child;
}
}
if (path.indexOf(".") > -1) {
if (!(n instanceof Element)) {
throw new XMLConfigException("Node "+n.getNodeName()+" should be an element so it can contain attributes");
}
return n;
}
else {
if (overwrite) {
child = n.getFirstChild();
// remove all children
while(child!=null) {
Node temp = child.getNextSibling();
n.removeChild(child);
child = temp;
}
return n;
}
else {
return child;
}
}
}
/** Returns a string representation of the object.
* @return a string representation of the object.
*/
public String toString() {
ByteArrayOutputStream os = new ByteArrayOutputStream();
save(os);
return os.toString();
}
/** Return the path of a node as it is used in XMLConfig.
* @param n node
* @return path
*/
public static String getNodePath(Node n) {
if (n==null) { return ""; }
String path = "";
while(n.getParentNode()!=null) {
path = n.getNodeName()+"/"+path;
n = n.getParentNode();
}
return path.substring(0,path.length()-1);
}
/** Exception in XMLConfig methods.
*/
public static class XMLConfigException extends RuntimeException {
public XMLConfigException() {
super();
}
public XMLConfigException(String message) {
super(message);
}
public XMLConfigException(String message, Throwable cause) {
super(message, cause);
}
public XMLConfigException(Throwable cause) {
super(cause);
}
}
}
XML Properties
// XMLProperties.java
// $Id: XMLProperties.java,v 1.5 2000/08/16 21:37:58 ylafon Exp $
// (c) COPYRIGHT MIT, INRIA and Keio, 1999.
// Please first read the full copyright statement in file COPYRIGHT.html
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Properties;
import org.xml.sax.AttributeList;
import org.xml.sax.DocumentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.Parser;
import org.xml.sax.SAXException;
/**
* The <code>Properties</code> class represents a persistent set of
* properties. The <code>Properties</code> can be saved to a stream or loaded
* from a stream. Each key and its corresponding value in the property list is a
* string.
* <p>
* A property list can contain another property list as its "defaults"; this
* second property list is searched if the property key is not found in the
* original property list. Because Properties inherits from Hashtable, the put
* and putAll methods can be applied to a Properties object. Their use is
* strongly discouraged as they allow the caller to insert entries whose keys or
* values are not Strings. The setProperty method should be used instead. If the
* store or save method is called on a "compromised" Properties object that
* contains a non-String key or value, the call will fail.
* <p>
* This is a special implementation for XML :
*
* <pre>
* <properties>
* <key name="My_key1">My_Value1</key>
* <key name="My_key2">My_Value2</key>
* </properties>
* </pre>
*
* @version $Revision: 1.5 $
* @author Philippe Le Hégaret (plh@w3.org)
* @author Benoît Mahé (bmahe@w3.org)
*/
public class XMLProperties extends Properties {
public static final String PARSER_P = "com.jclark.xml.sax.Driver";
public boolean debug = false;
class XMLParser implements DocumentHandler {
final int IN_NOTHING = 0;
final int IN_DOCUMENT = 1;
final int IN_KEY = 2;
int state = IN_NOTHING;
String key;
StringBuffer value;
Parser parser;
XMLParser(InputStream in) throws IOException, SAXException {
state = IN_NOTHING;
value = new StringBuffer();
try {
parser = getParser();
parser.setDocumentHandler(this);
} catch (Exception e) {
e.printStackTrace();
throw new SAXException("can"t create parser ");
}
parser.parse(new InputSource(in));
}
public void startElement(String name, AttributeList atts) throws SAXException {
if (state == IN_NOTHING) {
if (name.equals("properties")) {
state = IN_DOCUMENT;
} else {
throw new SAXException("attempt to find root properties");
}
} else if (state == IN_DOCUMENT) {
if (name.equals("key")) {
state = IN_KEY;
key = atts.getValue("name");
if (key == null) {
throw new SAXException("no name for key " + atts);
}
} else {
throw new SAXException("attempt to find keys");
}
} else {
throw new SAXException("invalid element " + name);
}
}
public void endElement(String name) throws SAXException {
if (state == IN_KEY) {
setProperty(key, value.toString());
if (debug) {
System.out.print("<key name=\"" + key + "\">");
System.out.println(value.toString() + "</key>\n");
}
state = IN_DOCUMENT;
name = null;
value = new StringBuffer();
} else if (state == IN_DOCUMENT) {
state = IN_NOTHING;
}
}
public void characters(char ch[], int start, int length) throws SAXException {
if (state == IN_KEY) {
compute(ch, start, length);
}
}
public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
// nothing to do
}
public void startDocument() throws SAXException {
// nothing to do
}
public void endDocument() throws SAXException {
// nothing to do
}
public void processingInstruction(String target, String data) throws SAXException {
// nothing to do
}
public void setDocumentLocator(Locator locator) {
// nothing to do
}
private void compute(char[] ch, int start, int length) {
int st = start;
int len = length - 1;
while (st < length
&& ((ch[st] == "\n") || (ch[st] == "\t") || (ch[st] == " ") || (ch[st] == "\r"))) {
st++;
}
while (len > 0
&& ((ch[len] == "\n") || (ch[len] == "\t") || (ch[len] == " ") || (ch[len] == "\r"))) {
len--;
}
while (st <= len) {
value.append(ch[st]);
st++;
}
}
} // XMLParser
private Class parser_class = null;
/**
* Reads a property list from an input stream.
*
* @param in
* the input stream.
* @exception IOException
* if an error occurred when reading from the input stream.
* @since JDK1.0
*/
public synchronized void load(InputStream in) throws IOException {
XMLParser p = null;
try {
p = new XMLParser(in);
} catch (SAXException e) {
throw new IOException(e.getMessage());
}
}
/**
* Reads a property list from an input stream. This method try to load
* properties with super.load() if the XMLParser failed. Use this method to
* translate an Property set to an XML Property set.
*
* @param file
* the properties file.
* @exception IOException
* if an error occurred when reading from the input stream.
* @since JDK1.0
*/
public synchronized void load(File file) throws IOException {
InputStream in = new BufferedInputStream(new FileInputStream(file));
XMLParser p = null;
try {
p = new XMLParser(in);
} catch (SAXException e) {
try {
in = new BufferedInputStream(new FileInputStream(file));
super.load(in);
in.close();
} catch (IOException ex) {
throw new IOException(e.getMessage());
}
}
}
/**
* Calls the <code>store(OutputStream out, String header)</code> method and
* suppresses IOExceptions that were thrown.
*
* @deprecated This method does not throw an IOException if an I/O error
* occurs while saving the property list. As of JDK 1.2, the
* preferred way to save a properties list is via the
* <code>store(OutputStream out,
* String header)</code> method.
*
* @param out
* an output stream.
* @param header
* a description of the property list.
* @exception ClassCastException
* if this <code>Properties</code> object contains any keys or
* values that are not <code>Strings</code>.
*/
public synchronized void save(OutputStream out, String header) {
try {
store(out, header);
} catch (IOException ex) {
ex.printStackTrace();
}
}
/**
* Writes this property list (key and element pairs) in this
* <code>Properties</code> table to the output stream in a format suitable
* for loading into a <code>Properties</code> table using the
* <code>load</code> method.
* <p>
* After the entries have been written, the output stream is flushed. The
* output stream remains open after this method returns.
*
* @param out
* an output stream.
* @param header
* a description of the property list.
* @exception ClassCastException
* if this <code>Properties</code> object contains any keys or
* values that are not <code>Strings</code>.
*/
public synchronized void store(OutputStream out, String header) throws IOException {
PrintWriter wout = new PrintWriter(out);
wout.println("<?xml version="1.0"?>");
if (header != null) {
wout.println("<!--" + header + "-->");
}
wout.print("<properties>");
for (Enumeration e = keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
String val = (String) get(key);
wout.print("\n <key name=\"" + key + "\">");
wout.print(encode(val));
wout.print("</key>");
}
wout.print("\n</properties>");
wout.flush();
}
protected StringBuffer encode(String string) {
int len = string.length();
StringBuffer buffer = new StringBuffer(len);
char c;
for (int i = 0; i < len; i++) {
switch (c = string.charAt(i)) {
case "&":
buffer.append("&");
break;
case "<":
buffer.append("<");
break;
case ">":
buffer.append(">");
break;
default:
buffer.append(c);
}
}
return buffer;
}
private Class getParserClass() throws ClassNotFoundException {
if (parser_class == null)
parser_class = Class.forName(PARSER_P);
return parser_class;
}
private Parser getParser() {
try {
return (Parser) getParserClass().newInstance();
} catch (Exception ex) {
throw new RuntimeException("Unable to intantiate : " + PARSER_P);
}
}
/**
* Creates an empty property list with no default values.
*/
public XMLProperties() {
super();
}
/**
* Creates an empty property list with the specified defaults.
*
* @param defaults
* the defaults.
*/
public XMLProperties(Properties defaults) {
super(defaults);
}
/**
* Creates an empty property list with the specified defaults.
*
* @param parser
* the XML Parser classname (default is PARSER_P)
* @param defaults
* the defaults.
*/
public XMLProperties(String parser, Properties defaults) {
super(defaults);
try {
parser_class = Class.forName(parser);
} catch (ClassNotFoundException ex) {
System.err.println("Unable to instanciate parser class: " + parser);
System.err.println("Using default parser.");
}
}
public void setDebug(boolean debug) {
this.debug = debug;
}
}