public class PropertyPack
extends java.lang.Object
A packNames may be qualified with a prefix dotted list like
com.physpics.apps.indexgofer.IndexGofer.properties
The prefix is converted to a directory when the data are in a classpath or jar. The prefix may be omitted, leaving the .properties file at the toplevel of the jar.
Properties may be saved, but only into the first cluster on the list passed to the PropertyPack constructor. If it is a DirCluster, then the change will be added to packname.properties. If a FileCluster, then the change will be added to its named file. Thus the change can be stored in a file not named packname.
Variant names are formed by appending suffixes before
the file extension as described in
ResourceBundle.getBundle
For example, if packName is IndexGofer and the locale is Locale("ja"),
then properties are sought in IndexGofer_ja.properties
and IndexGofer.properties
.
A new PropertyPack is created for each packName. However, arbitrarily named files may be included among the possible locations by including a FileCluster in the ArrayList passed to the PropertyPack constructor.
Three file extensions are tried, in this order: .properties, .xml, and .class.
The format for .properties files is described in
Properties.load(java.io.Reader)
.xml files look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties
PUBLIC "-//java.sun.com//properties//EN"
"http://java.sun.com/dtd/properties.dtd">
<properties version="1.0">
<comment this is the comment, only one is allowed />
<entry key="this.is.a.key"> value for this.is.a.key </entry>
<entry key="another.key"> another value</entry>
</properties>
A .class file must be a subclass of ResourceBundle
.
If the search is in a directory, the dotted name is used as a file name. Thus if the directory is /home/fred then the search is for a file whose name is /home/fred/com.physpics.Indexer_ja_â_XX.properties (or .xml or .class) If the search location is a jar file, the dotted name is converted by replacing dots with slashes: com/physpics/Indexer_ja_â_XX.xxx Consequently, the file must be stored in the .jar in the directory given by the qualified name.
Limitation on ResourceBundle names: The application name, say App, is usually the name of a java source file, App.java which produces App.class; so properties for the application cannot be in App.java as a subclass of ResourceBundle. There is no problem with properties in App.properties.
If the packName is com.physpics.useful.App, then the file App.properties must reside in the jar under directory com/physpics/useful/. Alternatively, the packName could be simply App, in which case App.properties must be in the top level directory of the jar.*
KEY CONCEPTS
CLUSTER - a place to look for properties files. Typically a directory, but can be an URL. Individual sources like files can also be on the list of clusters.
PROP_NODE - A specific set of properties. Typically a file. Each Cluster may contain multiple PropNodes.
WANTED_LIST - A list of all filenames that can be generated as variants of the locale.
Modifier and Type | Class and Description |
---|---|
static class |
PropertyPack.AdhocFilter
An AdhocFilter checks for a filename with various extensions.
|
static class |
PropertyPack.BundlePropNode
A PropNode that manages a ResourceBundle object
|
static class |
PropertyPack.Cluster
A Cluster is an element for the list of directories and jars
to examine for PropNode elements.
|
static class |
PropertyPack.ClusterMember
Identify a particular file within a cluster.
|
static class |
PropertyPack.DirCluster |
static class |
PropertyPack.FileCluster
Member of clusters list that denotes a single file.
|
static class |
PropertyPack.JarCluster
A JarCluster accesses files inside a jar
(where they are called "resources).
|
static class |
PropertyPack.JarFileCluster
Member of clusters list that denotes a single file within a jar.
|
protected static class |
PropertyPack.LocaleInfo
retain info for each of the valid locales
|
static class |
PropertyPack.NameTool
Class to wrap ResourceBundle.Control for methods
toBundleName and
getCandidateLocales.
|
static class |
PropertyPack.PropertyPropNode
A PropNode that manages a .properties file
|
static class |
PropertyPack.PropNode
Elements for the list of files/bundles to check.
|
static class |
PropertyPack.SystemCluster
As a member of a clusters list, this object manages System.properties.
|
static class |
PropertyPack.SystemPropNode
A PropNode that accesses System properties
|
static class |
PropertyPack.URLCluster
A URL cluster is for URLs other than file:..., usually http:.
|
static class |
PropertyPack.WantedList
A WantedList lists a filename with each of several possible extensions.
|
Modifier and Type | Field and Description |
---|---|
protected java.util.ArrayList<PropertyPack.Cluster> |
clusters
The list of directories and jars to be searched for packName
and its locale-specific variants.
|
protected java.util.ArrayList<PropertyPack.PropNode> |
propNodes
The instances of packName that have been discovered.
|
protected OneShotTimer |
saveProps
Ensure saving properties to file.
|
protected java.util.Locale |
theLocale
The Locale for fetching language specific versions of IndexGofer.properties.
|
Constructor and Description |
---|
PropertyPack(java.lang.Class<?> app,
File workdir)
Create a PropertyPack for the properties of an application.
|
PropertyPack(PropertyPack source,
java.lang.String otherName)
Creates a PropertyPack for a different packName.
|
PropertyPack(java.lang.String namePrefix,
java.util.ArrayList<PropertyPack.Cluster> clus)
Constructs a PropertyPack that searches an arbitrary set of directories
and jar files.
|
PropertyPack(java.lang.String namePrefix,
java.lang.Class<?> app,
File workdir)
Create a PropertyPack for the properties of an application, where
the packName of the properties files is namePrefix.
|
Modifier and Type | Method and Description |
---|---|
void |
dumpInfo()
Send info on clusters and propNodes to stdout.
|
static void |
dumpStrings(java.lang.String what,
java.lang.String[] ss) |
void |
flushSave() |
java.util.ArrayList<java.lang.String> |
getArray(java.lang.String key)
Find a property and parse it as a list.
|
boolean |
getBoolean(java.lang.String key)
Gets a boolean with default value of false.
|
boolean |
getBoolean(java.lang.String key,
boolean defVal)
Fetches the named property and tests it for truthiness.
|
int |
getInt(java.lang.String key)
Get an integer property.
|
int |
getInt(java.lang.String key,
int defVal)
Get an integer property.
|
PropertyPack.PropNode |
getMostRecentSource() |
PropertyPack.PropNode |
getNode(java.lang.String key) |
java.lang.String |
getPackName() |
java.lang.String |
getProperty(java.lang.String key)
Find a named property's value.
|
java.lang.String |
getProperty(java.lang.String key,
java.lang.String defawlt) |
PropertyPack |
getSibling(java.lang.String packName)
Create a PropertyPack with the same clusters as this one,
but with a different packName.
|
java.lang.String |
getString(java.lang.String key)
Synonym for getProperty
|
java.lang.String |
getString(java.lang.String key,
java.lang.String defVal)
Synonym for getProperty
|
java.util.Locale |
getTheLocale() |
boolean |
isMutable() |
static void |
main(java.lang.String[] args) |
static java.util.Locale |
name2Locale(java.lang.String localeName)
Convert a locale name to a Locale object.
|
InputStream |
openFile(java.lang.String fpath)
Searches for a named path in the list of directories
and opens an InputStream on it.
|
static java.util.ArrayList<java.lang.String> |
parseAsArray(java.lang.String s)
Parse a string as a comma-separated list and return a list of the elements.
|
protected void |
populateSets()
Make sure we have scanned all clusters for packName.properties.
|
static PropertyPack.PropNode |
propNodeFactory(PropertyPack.ClusterMember clum,
PropertyPack.LocaleInfo loc)
Create a PropNode of the variety needed for f.
|
int |
qSize() |
void |
setLocale(java.util.Locale loc)
Set the Locale to be used to find associated resource version of IndexGofer.properties.
|
void |
setLocale(java.lang.String name)
Set the Locale to be used to find associated resource versions of IndexGofer.properties.
|
java.lang.String |
setProperty(java.lang.String key,
java.lang.String value)
Store a value for a key.
|
static java.util.ArrayList<PropertyPack.Cluster> |
standardDirs(java.lang.String packName,
java.lang.Class<?> member,
File workdir)
Produce the default list of search locations:
workdir/ a parameter
userdir/ System.getProperty("user.dir")
jardir/ The directory containing app.jar
JAVADATA/ System.getProperty("java.home")
Java.properties in user.home
Site.properties in a writable java data area
jardir/packName.jar search within the .jar file
where app.jar includes =member=
In addition, locale-dependent variants of packName are sought
in each location as described in
{#link java.util.ResourceBundle#getBundle(String, Locale, ClassLoader)}
In case packName matches application name, a search within a jar file
looks for both packName.class and packNameBundle.class
|
void |
store()
Save the properties to cluster-0.
|
static boolean |
toBoolean(java.lang.String s,
boolean defVal) |
static int |
toInt(java.lang.String s,
int defVal) |
static java.lang.String |
unparseStringArray(java.util.ArrayList<java.lang.String> a)
Convert an array of strings into a single String bounded with [ and ]
and delimited with ",".
|
static java.lang.String |
unparseStringArray(java.lang.String[] a) |
boolean |
verifySaveNode() |
protected java.util.Locale theLocale
protected java.util.ArrayList<PropertyPack.Cluster> clusters
If the first cluster is a writeable DirCluster or FileCluster; it is called cluster-0, and is the value of defaultSaveNode. No locale variants are processed from this cluster; the non-localized file will be the destination for setProperty.
protected java.util.ArrayList<PropertyPack.PropNode> propNodes
ResourceBundle.Control.getCandidateLocales
protected OneShotTimer saveProps
public PropertyPack(java.lang.Class<?> app, File workdir)
app
- The class for the application.workdir
- The working directory for this execution.public PropertyPack(java.lang.String namePrefix, java.lang.Class<?> app, File workdir)
namePrefix
- the packName for properties files to be sought.
Each cluster is searched for files of this name with any of the extenisions
.properties, .xml, and .Java.app
- main class for the applicationworkdir
- working directory for this executionpublic PropertyPack(java.lang.String namePrefix, java.util.ArrayList<PropertyPack.Cluster> clus)
namePrefix
- the packName for properties files. Files with this
name and extension .properties, .xml, or .Java are sought in each
member of argument clus.clus
- A list of Clusters in which to look for files with
names beginning with packName. If clus is null, the resulting
PropertyPack responds null to every getProperty() request.
To define a special purpose cluster list, start with an empty ArrayList or the result of StandardDirs. Then create Cluster objects and add them to the list. Here are the cluster types and the best way to add instances
public PropertyPack(PropertyPack source, java.lang.String otherName)
source
- A source whose clusters to use for new PropertyPackotherName
- The name-prefix for all properties files
and ResourceBundles in the new PropertyPack.public void setLocale(java.lang.String name)
name
- The IETF BCP 47 name for the Locale. It is processed through name2Localepublic void setLocale(java.util.Locale loc)
loc
- the Locale to be used for finding resource bundlespublic java.util.Locale getTheLocale()
public static java.util.Locale name2Locale(java.lang.String localeName)
localeName
- the String name of the Locale. In official BCP 47,
code segments are hyphen separated; however, Jave uses underline.
For US english, the string would be "en_US".
For Locale.getDefault, the name may be "default", null, or empty.public java.lang.String getPackName()
public PropertyPack.PropNode getMostRecentSource()
public boolean isMutable()
protected void populateSets()
public boolean verifySaveNode()
public void flushSave()
public static java.util.ArrayList<PropertyPack.Cluster> standardDirs(java.lang.String packName, java.lang.Class<?> member, File workdir)
packName
- name shared by all properties files.member
- One of the class files in the desired jar.workdir
- The project's working directory.PropertyPack(java.lang.String, java.lang.Class, java.io.File)
public PropertyPack getSibling(java.lang.String packName)
packName
- The packName for the new PropertyPack (no extension)public static PropertyPack.PropNode propNodeFactory(PropertyPack.ClusterMember clum, PropertyPack.LocaleInfo loc)
clum
- A ClusterMember denoting the location for this PropNode.
// TODO to get rid of ClusterMember,
// clum must be two arguments: Cluster andloc
- the Locale that engendered this nodepublic static java.util.ArrayList<java.lang.String> parseAsArray(java.lang.String s)
Sigh: backslashes are processed in parsing the properties files; so to get a single backspace as input to parseAsArray, TWO backspaces are required in the .properties file.
The list must be delimited with an initial [ and a trailing ], but preceding or trailing whitespace is trimmed away first.Example: [elementOne, element2\ , \, ,] where the elements are "ElementOne", "element2 ", ",", and "".
If the trimmed argument does not begin with [ and end with ], the result is a one-element list with the trimmed content as its element. Thus an empty argument string returns a list with one empty-string element.
The empty list is represented by "[]", with or without whitespace between the brackets.
s
- The string to be parsed.public static java.lang.String unparseStringArray(java.util.ArrayList<java.lang.String> a)
a
- The array of Strings (as an ArrayList)public static java.lang.String unparseStringArray(java.lang.String[] a)
public java.lang.String getProperty(java.lang.String key)
key
- name of the propertypublic java.lang.String getProperty(java.lang.String key, java.lang.String defawlt)
public PropertyPack.PropNode getNode(java.lang.String key)
public static int toInt(java.lang.String s, int defVal)
public int getInt(java.lang.String key)
key
- The property to seekpublic int getInt(java.lang.String key, int defVal)
key
- The property to seekdefVal
- The default value if no property is found.public static boolean toBoolean(java.lang.String s, boolean defVal)
public boolean getBoolean(java.lang.String key)
key
- The property string to fetch.public boolean getBoolean(java.lang.String key, boolean defVal)
key
- what key to look underdefVal
- The default value.public java.lang.String getString(java.lang.String key)
key
- The property keypublic java.lang.String getString(java.lang.String key, java.lang.String defVal)
key
- The property keydefVal
- The default valuepublic java.util.ArrayList<java.lang.String> getArray(java.lang.String key)
key
- The property name. To be a list, the property value
should be within [ and ]; otherwise the list will have one element,
the trimmed property value.parseAsArray(java.lang.String)
public InputStream openFile(java.lang.String fpath)
fpath
- a slashed path name expected to descend from one of the clusters
Since it is relative to the cluster, fpath does not have an initial slash.public java.lang.String setProperty(java.lang.String key, java.lang.String value)
Only one file is eligible to save settings. It is in cluster-0, which must be writeable. The file is packName.properties (when cluster-0 is a DirCluster) or the named file (for a FileCluster). No locale variants are considered; they are ignored in cluster-0.
This method arranges that a call to store() will occur after a minute or so. (Thus, for multiple successive setProperty calls, only one store() will be done.)
Setting a value null is implemented by removing the property. This may uncover values stored in higher numbered clusters. If so, a warning message is issued.
key
- Property name.value
- New value for the property.public void store()
public int qSize()
public void dumpInfo()
public static void dumpStrings(java.lang.String what, java.lang.String[] ss)
public static void main(java.lang.String[] args) throws IOException
IOException