|
|
|
Spontaneous Networking |
Jini Community News |
Discuss |
Print |
Email |
First Page |
Previous |
Next
|
|
Sponsored Link •
|
|
Advertisement
|
Configuration The Configuration class serves as a medium of conversation between a
Jini service developer and the person deploying, or using, that software. The
developer delegates certain aspects of the service to the deployer. The deployer then
decides what values those objects should assume to achieve the goals of a particular
deployment situation. The Configuration implementation provides the
deployer with a set of tools to construct those objects.
That division of responsibilities is a good fit for an object-oriented (OO) language such as Java. The developer can use the Java type system to model the contract needed from each object, while the deployer gets to use the polymorphism of the Java programming language to construct instances that both implement the contract and meets the needs of a given deployment.
Configuration objects are created at runtime by an instance of the
net.jini.config.Configuration interface from configuration
entries. A developer defines the requirements each configuration entry must
meet. A Configuration instance is then responsible for evaluating
configuration entries to yield the objects that are �plugged into� the runtime Jini
system. The deployer chooses what Configuration implementation to use,
and defines the configuration entries. The config model, therefore, gives the
deployer control over what object each configuration entry will yield.
The default implementation of Configuration is
ConfigurationFile. That class allows for the construction of arbitrary
Java objects based on a text file interpreted at runtime and defined in a Java-based
language. The following section explains that Java-based configuration language, and
provides examples of its use.
The following code snippet illustrates configuration-specific additions to a Jini service's code:
package org.jini.user.jmcclain.myservice;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationProvider;
import net.jini.config.ConfigurationException;
import net.jini.config.NoSuchEntryException;
....
class MyServiceImpl {
private MyServiceImpl(String[] argv) throws ConfigurationException {
....
Configuration config =
ConfigurationProvider.getInstance(argv,
getClass().getClassLoader());
....
A client would require similar code. Utilities that rely on a configuration object generally consume those configuration objects in their constructors.
The ConfigurationProvider class provides static methods that can be
used to create a configuration. By delegating to ConfigurationProvider,
we allow the deployer to use whatever configuration implementation he desires. By
default ConfigurationFile will be used, but using Java's resource
mechanism, deployers can arrange for another implementation to be used.
The argv String array is passed into
ConfigurationProvider. How that array is parsed will vary between
Configuration implementations. ConfigurationFile treats
the first element as a URL to look for a ConfigurationFile source file.
Any additional elements in the array override the contents of the source file. This
example assumes that all of the program's command-line arguments are used to obtain
the configuration. ConfigurationFile's override feature allows for
simple values to be provided on the command line without having to edit the
configuration source.
Conceptually, a Configuration instance is composed of configuration
entries. When a program needs an object to be provided by the deployer, that program
asks Configuration to evaluate one of those entries to obtain an object.
Evaluating a configuration entry twice may or may not yield the same object. A
service's developer must document what configuration entries her service uses, when
those entries are evaluated, the requirements of those entry objects, and how those
objects are used.
Configuration entries are identified by two strings: one denoting the component and one the name. The config model expects that every configuration entry used by a given software module (e.g. a client, service, or utility) shares the same component string, but has a distinct, hopefully descriptive, name string. In effect, the component string forms a name space and prevents collisions if two modules happen to use the same name. In Sun's contributed implementation of the JSK, the package name serves as the component string for clients and services, and the class name as the component string for utilities.
Once we have a Configuration, we can retrieve entries from it.
Suppose MyService has a daemon thread that cleans up internal data
structures, and we want to give the deployer control over that thread's priority. The
following code snippet illustrates how a deployer might determine that daemon
thread's priority:
....
int reapingPriority = ((Integer)config.getEntry(
"org.jini.user.jmcclain.myservice", // component
"reaperPriority", // name
int.class, // type
new Integer(Thread.NORM_PRIORITY)) // default value
).intValue();
if ((reapingPriority < Thread.MIN_PRIORITY) ||
(reapingPriority > Thread.MAX_PRIORITY))
{
throw new ConfigurationException("entry for component " +
"org.jini.user.jmcclain.myservice, name reaperPriority " +
"must be between " + Thread.MIN_PRIORITY + " and " +
Thread.MAX_PRIORITY + ", has a value of " +
reapingPriority);
}
reaperThread = new ReaperThread();
reaperThread.setPriority(reapingPriority);
reaperThread.setDaemon(true);
reaperThread.start();
....
The above example illustrates some important configuration principles:
MyService does not need to provide
a value for every configuration entry. Since default values reduce the burden on the
deployer, a default should be provided whenever possible. When getting the value of a
configuration entry, the caller can also specify the type of object expected of that
entry. int, not an Integer. However,
because getEntry() returns an Object, the return value is
wrapped in Integer, as is the default value.int), we don't need to
check for null. ConfigurationException. We would also want to log such a problem, but
the logging code has been removed for clarity.
A ConfigurationFile source file might look as follows:
org.jini.user.jmcclain.myservice {
reaperPriority = 6;
}
If this file were named myservice.config, the command line might look like this:
java -Djava.rmi.server.codebase=http://recycle/myservice-dl.jar \
-jar myservice.jar \
myservice.config
In this case, the reaping thread would have a priority of 6. Because we provided
a default when fetching reaperPriority, we could use an empty file:
java -Djava.rmi.server.codebase=http://recycle/myservice-dl.jar \
-jar myservice.jar \
empty.config
or no file:
java -Djava.rmi.server.codebase=http://recycle/myservice-dl.jar \
-jar myservice.jar
and still have a running service. In both cases, the reaping thread would have a
priority of Thread.NORM_PRIORITY. We could also use a command-line
override to obtain the effect of using myservice.config without
specifying a file on the command line:
java -Djava.rmi.server.codebase=http://recycle/myservice-dl.jar \
-jar myservice.jar \
- org.jini.user.jmcclain.myservice.reaperPriority=6
Passing '-' as the first command-line argument to MyService
indicates that there is no ConfigurationFile source file. Replacing '-'
with empty.config would have a similar effect.
Finally we could use myservice.config but use an override to give
the reaping thread some value besides 6:
java -Djava.rmi.server.codebase=http://recycle/myservice-dl.jar \
-jar myservice.jar \
myservice.config org.jini.user.jmcclain.myservice.reaperPriority=4
In this case the reaping thread would have a priority of 4.
|
Sponsored Links
|