Table of Contents
Introduction
Property Provider
Startup Constants
New-Style Property Management
Startup Servlet
Old-Style Property Management
The concept of property management has been a useful programming feature
even before the advent of the Java programming language.
It allows an application to be configured at runtime without having to
recompile and redeploy code.
The X Window environment has the concept of resources, which is used to
control window placement, size, fonts, etc.
Programs that run on the various Microsoft Windows operating systems
used to use .ini
files and now use the registry to contain
runtime configuration.
The Java platform also provides this facility and calls it Properties.
It includes the Properties
class, a subclass of Hashtable
,
which maintains a simple mapping of string keys to string values, and defines
methods that allow the mappings to be stored and retrieved from a
simply formatted text file.
What is missing from an architectural standpoint is the management of these files -
their location, how to find them, loading them, caching their values, and ultimately,
allowing access to the values from application code.
As with many of the Arch4J components, the management of properties has been
centralized by using the notion of a service provider for all property-related activities.
Over time, this concept has been expanded to provide additional useful functionality
for the application developer.
These improvements include the use of an XML file to define properties,
and a simpler mechanism to bootstrap the discovery and startup of the property
manangement facility.
The PropertyProvider
is the main service provider for simple property services.
The services are accessed via the static
getProvider()
method.
Originally, this provider was designed as a mechanism to aggregate the plethora
of Java Properties files into a single cohesive service, whereby property keys
could be looked up via a domain, which acted as a grouping mechanism.
This model is referred to as old-style property management.
The new-style mechanism uses a single XML file to contain the properties,
retains the concept of domain as a grouping mechanism within the XML file,
and adds the ability to define a type for each property value, such as boolean or int.
In addition to the XML property file, the new-style mechanism adds an easy startup
concept by way of a startup constants class.
This eases the burden of bootstrapping enough system properties just to let
the various Arch4J providers themselves startup.
The other providers should use this class for all of their property lookup,
either by looking up a property via a particular domain, or by using the
default domain, or by accessing constant values through the new constants class.
For historical purposes, properties retrieved via the old-style mechanism
uses code that looks like the following:
String value = PropertyProvider.getProvider().getPropertyManager().
getProperty("someDomain", "someProperty.key");
The domain is taken as the root of the property file name.
The suffix .properties
is appended to the domain
name to create a file name that is parsed to try to find the property.
Property files are searched for in the directory specified by the system
property arch4j.property.directory
. This property can be
set on the Java VM command line with the -D option, as in:
java -Darch4j.property.directory=C:/properties -classpath ...
If the system property is not set, property files will be searched for
in the current directory (where the VM was started).
If the property file is not found in that directory,
the property manager will try to find the file by searching for the file as
a resource on the classpath.
This is useful for web applications that cannot set the system
property arch4j.property.directory
.
For the new-style, constants class-based mechanism, this class is initialized
by searching for the system property arch4j.constants.class
.
If that property is set, then the new-style is used. Otherwise, the old-style is used.
If the constants class property is defined, the value should be a class name,
a subclass of StartupConstants.
The provider will create an instance of that constants class, available on the
provider via the method
getConstants().
The constants class is used to point the property provider at the application home
directory, and to an XML property file.
Once loaded, properties can be retrieved in exactly the same manner as above, via
one of the getProperty()
methods.
Since the XML-based property scheme adds type capability, there is an additional
method available on this class which can be used to get at all the new functionality.
It is named
getNewPropertyManager().
Not only can you access string property values, but other types as well. For example:
int timeout = PropertyProvider.getProvider().getNewPropertyManager().
getInt("someDomain", "someTimeoutProperty.key");
The conversion of non-string types is performed when the XML property file is parsed.
Any errors are reported at that time, so valid types are guaranteed at application runtime.
The format of the XML property file allows more than one value to be stored for each key,
so you can get an array of values for a single key without having separate key names for each element.
int[] validValues = PropertyProvider.getProvider().getNewPropertyManager().
getIntArray("someDomain", "validValues");
Even though the concept of domains is maintained with the new-style scheme,
you do not need to use it. A default domain is maintained and used if not specified.
The following example shows this; simply leave the domain name off.
double rate = PropertyProvider.getProvider().getNewPropertyManager().
getDouble("conversionRate");
If your application runs inside of a web container, use the StartupServlet
to configure the bootstrapping of the property provider instead of using system properties.
See the documentation on that class for more information, as well as the documentation on
StartupConstants for rich client applications (Swing apps or Console apps).
For information on the format and tags used in the XML properties file, see
New-Style Property Management.
Back to the top
The StartupConstants
class defines methods that are used to initialize an application
and to configure its runtime environment. This eases the burden of having
to configure all of the runtime parameters as Java VM -D arguments.
Only two are needed; one to point to a concrete subclass of this class
and one to point to an application home directory.
With those two properties set (either via a -D argument or via a servlet),
the rest of the runtime configuration can be determined,
either directly as additional methods on the subclass
or indirectly through the property file values.
XML SAX properties are included and defaulted here to help insure that
the XML properties can be parsed without having to set up additional Java VM arguments.
XML parsing via the JAXP API is included when using version 1.4 or greater of the Java VM.
If an older VM is used, make sure you include a JAXP-compliant SAX parser factory class
in your classpath and modify your subclass to point to it.
Two system properties are used by the PropertyProvider
when it is initialized by way of a subclass of this class.
The first property is named arch4j.constants.class
.
Its value is a class name, which is a subclass of this class.
It is used to get the other startup properties.
The second property comes by way of the method
getApplicationHomeProperty().
This string is the parameter name to use to find the application's home directory.
The name chosen is up to the application developer.
For example, let us suppose that an application named counter is being deployed.
The application will contain a subclass of StartupConstants
named
com.mycompany.counter.CounterStartupConstants
.
In addition to the application code,
there is an external location for properties to be modified and data files to be stored.
This application home directory will be located in C:/var/appData/counter
.
The developer arbitrarily chooses the application home property name to be counter.app.home
,
which is what the overridden method getApplicationHomeProperty()
will return.
Here are the Java VM -D arguments that will initialize the application correctly.
-Darch4j.constants.class=com.mycompany.counter.CounterStartupConstants
-Dcounter.app.home=C:/var/appData/counter
If you really, really do not want to use an application home directory,
do not set the application home system property (the -Dcounter.app.home
in the example above).
Also, force the default application home method
getDefaultApplicationHome()
to return a null
.
Just make sure to store the XML property file somewhere in your classpath.
It will be found and parsed.
Back to the top
The XMLPropertyManager
class manages the reading, writing, and parsing of an XML-based property file.
It also provides backward compatibility to the Old-Style Property Management
scheme by supporting the old API.
When no property domains are used,
the simplest format for the XML-based property file looks like this:
<?xml version="1.0" encoding="UTF-8" ?>
<xml-properties>
<property key="someKey" value="Some Value" type="string" />
<property key="some.boolean.key" value="true" type="boolean" />
<property key="long.key.multiple" value="12023453454" type="long" />
<property key="long.key.multiple" value="-987654321012" type="long" />
</xml-properties>
In this case, a default domain is used. This file is functionally equivalent to:
<?xml version="1.0" encoding="UTF-8" ?>
<xml-properties>
<domain name="$DEFAULT$">
<property key="someKey" value="Some Value" type="string" />
<property key="some.boolean.key" value="true" type="boolean" />
<property key="long.key.multiple" value="12023453454" type="long" />
<property key="long.key.multiple" value="-987654321012" type="long" />
</domain>
</xml-properties>
Note the canonical default domain name.
Properties can be defined with the following list of data types:
boolean
char
double
float
int
long
string
In order to remain backward compatible,
split your properties up into domains,
specifically, the ones that other components within Arch4J use.
For example, here are a few of the known domains:
<?xml version="1.0" encoding="UTF-8" ?>
<xml-properties>
<domain name="dataaccess">
<property key="defaultConnection" value="myMainDatabase" type="string" />
<property key="myMainDatabase.driver" value="com.mysql.jdbc.Driver" type="string" />
<property key="myMainDatabase.url" value="jdbc:mysql:///testdata" type="string" />
<property key="myMainDatabase.username" value="root" type="string" />
<property key="myMainDatabase.password" value="" type="string" />
<property key="myMainDatabase.maxConnections" value="10" type="string" />
<property key="myMainDatabase.useArch4JPool" value="false" type="string" />
</domain>
<domain name="logging">
<property key="framework.class" value="org.arch4j.logging.log4j.Log4JLoggingFramework" type="string" />
<property key="framework.log4j" value="log4j.properties" type="string" />
</domain>
</xml-properties>
One drawback to maintaining backward compatibility is that properties in
the older domains must be defined with the type of string,
since that is all that is available via the Java Properties API.
While it may not be well-formed XML, the parser will allow properties to be both inside
and outside the domain tag.
Those properties defined outside of the domain tag will be considered to be in
the default domain.
If a new property is created by using one of the getXXX() methods in this class that
takes a default value, then the property data will be written back out to disk.
Default properties will be put into the canonical default domain tag.
For new properties that are part of an application and not part of an existing
Arch4J domain, application developers can either define their own set
of domains or use the default domain.
The new format allows developers to create arrays of values for a single property key.
When using a Java properties file, the keys have to be unique, as in
primary.colors.1=red
primary.colors.2=yellow
primary.colors.3=blue
and then some contrived method needs to be developed to group by the .1, .2, .3 numbers.
The same property can be defined in XML as
<property key="primary.colors" value="red" type="string" />
<property key="primary.colors" value="yellow" type="string" />
<property key="primary.colors" value="blue" type="string" />
and retrieved via the method getStringArray("primary.colors")
.
Back to the top
The StartupServlet
class is used to initialize property management for applications that run inside a web container.
Since it is non-trivial to add Java VM -D arguments to the web container startup,
this servlet class can be used at servlet initialization time to configure the system properties
needed to bootstrap the PropertyProvider,
specifically for XML property management,
which is the new-style way of handling application configuration via Arch4J.
Using this servlet requires that a valid servlet section in the web.xml deployment file
be set up to initialize this servlet. Along with the servlet name, two servlet initialization
parameters must be made available to the servlet. These two parameters directly correspond to
the two system properties that are used by the PropertyProvider
when it is initialized.
The first parameter is named arch4j.constants.class
.
Its value is a class name, which is a subclass of StartupConstants.
This class is used to get the other startup properties.
The second parameter comes by way of the method
getApplicationHomeProperty().
This string is the parameter name to use to find the application's home directory.
The name chosen is up to the application developer, and it is the developer's responsibility to make
sure that the name matches in both the web.xml deployment file and the constants subclass.
For example, let us suppose that a web application named counter is being deployed.
The application will contain a subclass of StartupConstants
named
com.mycompany.counter.CounterStartupConstants
.
In addition to the web container archive,
there is an external location for properties to be modified and data files to be stored.
This application home directory will be located in C:/var/appData/counter
.
The developer arbitrarily chooses the application home property name to be counter.app.home
,
which is what the overridden method getApplicationHomeProperty()
will return.
To ensure that this happens when the web container starts the application,
we will load this servlet on startup as the first loaded servlet.
Here is the servlet section that will initialize the application correctly.
<servlet>
<servlet-name>PropertyStartupServlet</servlet-name>
<servlet-class>org.arch4j.property.StartupServlet</servlet-class>
<init-param>
<param-name>arch4j.constants.class</param-name>
<param-value>com.mycompany.counter.CounterStartupConstants</param-value>
</init-param>
<init-param>
<param-name>counter.app.home</param-name>
<param-value>C:/var/appData/counter</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
If you really, really do not want to use an application home directory,
do not include the application home init parameter in your servlet specification
(counter.app.home
in the example above).
Also, force the default application home method getDefaultApplicationHome()
in your StartupConstants
subclass to return a null
.
Just make sure to store the XML property file somewhere in your classpath.
It will be found and parsed.
Back to the top
The PropertyManager
interface defines the methods that a simple property file
manager needs to implement. Properties are thought of as belonging to a
domain. The domain is the name of the properties file without the
.properties
extension.
PropertyManagerImpl
is the implementation of the old-style scheme.
It takes the name of a property domain and tries to find an associated
property file in the designated property file directory by appending
.properties to the domain.
For example, the property manager
will search for the properties in the "user" domain in user.properties.
If the special property key CACHE
is found and the value is
Y, then the collection of properties will be cached and used on
future lookups. The cache can be cleared by calling
clearCache().
Back to the top