When developing for the metadata aggregator framework — either within the Shibboleth project or externally to extend it — the classes you create will implement one or more of the Java interfaces defined by the framework, for example Stage
or ItemMetadata
. As long as you implement those interfaces faithfully, your new class will work with the framework. It's certainly possible to implement a new class "from scratch" by just saying class X implements Stage<T>
but it can be a lot of work and this is almost never done within the framework itself. Instead, heavy use is made of a hierarchy of abstract classes each providing some useful functionality: you can extend one of these classes to greatly reduce the amount of code you need to write yourself.
Many objects in the metadata aggregator are components as defined by the Shibboleth component model, which is to say they all implement the Component interface via one or more behavioural interfaces:
An InitializableComponent must be initialize()
ed before it can be used.
A DestructableComponent can be destroy()
ed after use to reclaim resources.
An IdentifiedComponent has an id
property accessed through a getId()
method.
An IdentifiableComponent is an IdentifiedComponent
with a setId()
method.
These interfaces are almost always implemented together (for example, Stage requires InitializableComponent
, DestructableComponent
and IdentifiedComponent
) and shib-support
supplies a number of abstract base classes to implement the associated functionality in a standard way. Two of these are of particular interest when working with the metadata aggregator.
AbstractInitializableComponent implements InitializableComponent
and DestructableComponent
.
Subclasses must not override the implementations of initialize()
and destroy()
(this will be enforced by making these methods final in a later release).
Instead, the base class implements empty protected doInitialize()
and doDestroy()
methods which subclasses may override.
Implementations of doInitialize()
must call super.doInitialize()
before other actions. Implementations of doDestroy()
must call super.doDestroy()
after other actions. This allows all classes in the class hierarchy to properly set up and tear down state.
When initialize()
or destroy()
are called for the first time on an instance, the instance's doInitialize()
or doDestroy()
methods are called. initialize()
and destroy()
are synchronized, so all doInitialize()
and doDestroy()
methods are executed under the instance's monitor as an atomic operation.
AbstractIdentifiableInitializableComponent extends AbstractInitializableComponent
, adding implementations of IdentifiedComponent
and IdentifiableComponent
:
Adds a settable id
property (getId()
and setId()
methods).
The id property must be set before the component is initialized, or a ComponentInitializationException will be thrown.
The id property cannot be set after the component is initialized; attempts will cause a UnmodifiableComponentException to be thrown.
AbstractInitializableComponent
and AbstractIdentifiableInitializableComponent
provide the basis for almost all metadata aggregator components, depending on whether the component needs to have an id
property. Both are @ThreadSafe
so that thread-safe components can be built from them. They are not, however, normally used directly. Instead, the main abstract classes in the aggregator class hierarchy are derived from two intermediate classes (BaseInitializableComponent
and BaseIdentifiableInitializableComponent
) which add some helper methods to every component:
ifDestroyedThrowDestroyedComponentException()
ifNotInitializedThrowUninitializedComponentException()
ifInitializedThrowUnmodifiableComponentException()
throwSetterPreconditionExceptions()
combines ifDestroyedThrowDestroyedComponentException()
and ifInitializedThrowUnmodifiableComponentException()
. This helper method can be used to check the preconditions for a setter method.
throwComponentStateExceptions()
combines ifDestroyedThrowDestroyedComponentException()
and ifNotInitializedThrowUninitializedComponentException()
. This helper method can be used to check the preconditions for the main operational method in a class.
BaseInitializableComponent and BaseIdentifiableInitializableComponent are placed in an implementation package and should never be used outside the java-metadata-aggregator
codebase. Instead, external classes should be based on one of the exposed abstract classes, such as AbstractStage
and its subclasses, described below. This is because the functionality of BaseInitializableComponent
and BaseIdentifiableInitializableComponent
may be moved into the java-support
classes in a future release.
The largest class hierarchy in the metadata aggregator is that for stages.