Configuration
HK2 has an optional feature which allows configuration values specified in some format
such as (but not limited to) XML or Properties files to be injected into HK2 services.
The parts
The architecture of the HK2 configuration system consists of three parts. These three parts are
then combined to make the user experience simple and intuitive. The three basic parts of the
HK2 configuration system are:
- Persistence (some external configuration format such as XML or properties)
- Registry (a single JVM in-memory representation of Java Beans or bean-like maps)
- HK2 service integration (injecting values into HK2 services)
Each of these parts play a role in bringing configuration information into HK2 services. The basic
idea is that the persistence layer translates whatever external format the configuration has into
JavaBeans and updates the registry. The registry then notifies the HK2 service integration piece
which either adds HK2 services or updates existing HK2 services with new values from the existing
JavaBeans.
Since it is the second part of the HK2 configuration system that serves as the basic abstraction
layer it shall be described first.
The HK2 Configuration Registry
The HK2 Configuration Registry is an in-memory registry of JavaBeans (or bean-like maps). Instances
are organized by a type, and then further by instance names. It is usually the case that all instances
of the same type have the same java type, and the same set of parameters. Instance names can either
be a field from the bean or can be calculated some other way. The combination of type name and
instance name will always uniquely identify a particular instance.
The main API for working with the Registry is the Hub. The Hub is an HK2 service that
can be added to a ServiceLocator with the enableConfigurationHub method of the
ManagerUtilities class.
The current BeanDatabase can be gotten from the Hub. A
WriteableBeanDatabase which allows changes to the BeanDatabase
is available from the Hub. BeanDatabaseUpdateListener implementations
can be registered with the Hub to keep track of the current state of the configuration registry.
Those creating a module that is providing configuration from some backing store into the registry will
most often be working with the BeanDatabase and WriteableBeanDatabase
API. The HK2 service integration part of the HK2 configuration feature sets itself up as a
BeanDatabaseUpdateListener in order to provision HK2 services with configuration
data. However there may be other uses for a BeanDatabaseUpdateListener.
HK2 Service Integration
The HK2 service integration layer takes JavaBean instances from the Hub and creates an HK2 service per instance
of the type. It does this by setting itself up as a BeanDatabaseUpdateListener
on the Hub. HK2 mark themselves as being configured by a specific type by putting themselves into
the ConfiguredBy scope. This is the definition of the ConfiguredBy scope
annotation:
@Scope
@Retention(RUNTIME)
@Target(TYPE)
public @interface ConfiguredBy {
/** The type to be associated with this service */
public String value();
/** * Specifies the creation policy for configured services */
public CreationPolicy creationPolicy() default CreationPolicy.ON_DEMAND;
public enum CreationPolicy {
/**
* Instances of services with this policy will
* be created when some user code creates explicit
* demand for the service. This is similar to most
* other hk2 services
*/
ON_DEMAND,
/**
* Instances of services with this policy will
* be created as soon as their backing instances
* become available
*/
EAGER
}
}
HK2 services in the ConfiguredBy scope are normal HK2 services in that they can have normal
injection points and have all the other features of an HK2 service. They are also able to inject configuration
data into fields, constructors or methods that are annotated with Configured. There will be one
instance of the HK2 service created for each instance of the type in the BeanDatabase. Each
instance of the HK2 service will have a name equal to the name of the instance in the BeanDatabase
upon which it is based.
Any field or parameter annotated with Configured will be injected with a value from the JavaBean instance
in the BeanDatabase upon which this instance of the HK2 service is based. This is the definition of
the Configured annotation:
@Retention(RUNTIME)
@Target( { FIELD, PARAMETER })
@InjectionPointIndicator
public @interface Configured {
public final static String BEAN_KEY = "$bean";
/**
* The name of the field in the java bean or
* bean-like map to use for injecting into
* this field or parameter
*/
public String value() default "";
/**
* Describes how dynamic a configured field or parameter must be.
* All parameters of a constructor must be STATIC.
* All parameters of a method must have the same dynamicity value
*
* @return The dynamicicty of this field or parameter
*/
public Dynamicity dynamicity() default Dynamicity.STATIC;
/**
* Describes how dynamic a configured field or parameter should be
*/
public enum Dynamicity {
/** This value should not automatically change over the life of the service instance */
STATIC,
/** This value can change at any time during the life of the service instance */
FULLY_DYNAMIC
}
}
When placed on a java Field the name of the parameter can come from the name of the field. However, when placed
on a parameter of a constructor or a method the Configured value field must be filled in with
the name of the parameter from the JavaBean to use. If the parameter name is "$bean" then the parameter
or field will take the whole bean as its value.
Fields and methods that have parameters marked with Configured can opt in to having those values
changed dynamically when the corresponding parameter in the JavaBean is modified.
An HK2 service can also mark methods to run before and after dynamic changes are taking place, and it can also
implement the java.beans.PropertyChangeListener interface. To mark a method to run prior to dynamic changes
being made use the PreDynamicChange annotation on a method:
@Retention(RUNTIME)
@Target(METHOD)
public @interface PreDynamicChange {
}
To mark a method to run after dynamic changes are complete use the PostDynamicChange annotation
on a method:
@Retention(RUNTIME)
@Target(METHOD)
public @interface PostDynamicChange {
}
The methods marked with PreDynamicChange or PostDynamicChange can take
zero parameters or a single parameter that is a List<PropertyChangeListener>. If the List version is used
the List will contain the full set of dynamic changes that took place in a single BeanDatabase
operation. Furthermore, the PreDynamicChange can optionally return a boolean value. If
it does return a boolean value and that boolean value is false, then any fields marked as being dynamic will NOT
get updated.
The HK2 service integration part of the HK2 configuration system can be enabled using the enableConfigurationSystem
method of the [ConfigurationUtilities][configurationutilities] class.
Configuration Persistence
The persistence layer isn’t a layer so much as a set of plugins that take configuration data from some form (usually
persistent) and tranlate it into JavaBeans or bean-like maps. Those JavaBeans or bean-like maps are then
placed into the Hub. There can be multiple providers providing the input, or some providers can be used
in some scenarios while others are used in other scenarios. For example, a central server could read the configuration
from an XML file while remote clients could have a network plugin that receive the configuration from the central
server.
At the time of writing HK2 provides a provider that reads property files. There may be other providers that
are added as well (i.e., one that reads XML data).
The HK2 Properties Configuration provider
This space is under construction