Date: 2004-08-10T18:51:26
Editor: KenTam <[EMAIL PROTECTED]>
Wiki: Apache Beehive Wiki
Page: Controls/AssemblyAndBinding
URL: http://wiki.apache.org/beehive/Controls/AssemblyAndBinding
no comment
New Page:
= Controls Assembly and Binding =
== The Problems ==
The binding problem: the controls programming model has a crisp separation of
interface and implementation. In order to expose the power of this separation,
a configuration mechanism needs to exist to bind specific control
implementations to the usages of a control bean/interface, and a default
binding needs to be defined.
The assembly problem: control implementations may need to do build-time work on
or impacted by the its control client(s), such as side-effecting its client's
deployment descriptors, or generating additional files that are
implementation-specific. Mechanisms need to exist for the control author to
express this work, and for the build process to execute it; the phase where
this work is done is called assembly.
Since assembly is dependent on being bound to a particular control
implementation, and both occur between the time controls/control clients are
compiled and executed, the two problems are closely related.
== Declaring Controls Usage ==
A critical aspect of solving binding and assembly is identification of the set
of control types used by a set of control clients. Developers need to know
what control types their application uses so they can choose custom
implementation bindings. The assembly process needs to know what set of
control types an application uses in order to execute only the relevant
assembly work.
Control clients MUST declaratively identify all control types they use. This
is accomplished via 2 annotations, which are handled by the control client
annotation processor:
[EMAIL PROTECTED] -- marker annotation valid on fields; the annotated field's
type is a control type (directly, as the PI, or indirectly as the generated CB
that maps to a PI).
[EMAIL PROTECTED] -- single value annotation valid on classes or methods; the
annotation's value specifies the a control type that the control client uses.
[EMAIL PROTECTED] are required whenever a client uses a control type in a
purely programmatic way (ie, there is no [EMAIL PROTECTED] annotated field of
that control type in the client).
{{{TBD: elaborate on how this might work for non-Java clients}}}
Both annotations have runtime retention policy; thus in principle, the assembly
process may accept a set of control clients made of up of a mixture of source
and binary classes, and use reflection to determine the set of control types
those clients use.
== The Controls Client Manifest ==
To more transparently surface the set of used control types, and make the
assembly process more efficient, the control client annotation processor
generates a "controls client manifest" (shortened to "client manifest" when the
context is clear) documenting the set of used control types. This manifest is
a java.util.Properties file that specifies:
* classname of the control client
* classnames of each control type used by that control client (the set
identified by [EMAIL PROTECTED] and [EMAIL PROTECTED] usages) and the
corresponding default implementation binding
Example client manifest (e.g. named {{{FooImpl.controls.properties}}})
{{{
client.name=org.acme.controls.FooImpl
org.acme.controls.CustomerDbBean=org.apache.beehive.controls.scl.DatabaseControlImpl
org.acme.controls.DailyTimerBean=org.apache.beehive.controls.scl.TimerControlImpl
}}}
The manifest is a generated artifact and is not user-editable. If a manifest
is present, the control client processor will read it and only write it out if
the set of controls used has changed; the assembly process may therefore use
the timestamp on the manifest to determine whether work needs to be done on a
given client.
{{{TBD: reconsider filename convention?}}}
== Implementation Binding ==
The default implementation binding for a control type is defined by the
defaultBinding attribute on the [EMAIL PROTECTED] annotation. The expectation
is that overriding the default binding is an unusual occurrence. The
conventional approach to overriding an annotation value would be via a
deployment plan, however, since the binding affects assembly, it needs to take
place prior to application deployment (we consider assembly to be properly part
of the build).
{{{
REVIEW: this almost suggests that assembly is part of deployment, but on deeper
thought that seems clearly wrong. I am not completely satisfied with this yet.
I think we need to really define crisply whether binding is a developer or
admin feature.
}}}
External configuration of bindings is supported via a "controls binding file",
an optional, user-authored, application scoped properties file that contains:
* bindings between ControlBean/interface types and control implementation
types. Each binding applies to all usages of the CB/interface type within that
app.
Example controls binding file (e.g. {{{MyApp.controls.properties}}})
{{{
org.acme.controls.FooBean=org.acme.controls.FooSimulationImpl
com.bea.controls.DailyTimerBean=org.acme.controls.CustomTimerImpl
}}}
{{{
REVIEW: Do we need finer granularity over binding configuration? This approach
can be extended to client-scoped config files.
}}}
== The Assembly Process ==
A control implementation declares its desire to participate in the assembly
process via the optional "assemblyClass" attribute on the [EMAIL PROTECTED]
annotation. The class referenced by "assemblyClass" must implement the
ControlAssembler interface [see attached]
Assembly takes place after the control clients have been handled by the control
client processor, and relies on the client manifest (or its moral equivalent
which can be obtained via reflection). All controls referenced by the client
be must completely compiled prior to assembly; in particular, the assembler
classes associated with the control implementations must be compiled (note for
nested controls usage -- "compiled" does not include running assembly! It does
include bean gen).
The assembly process operates on a set of "assembly targets". An assembly
target is any J2EE module that contains 1+ control clients, and represents the
smallest amount of assembly work that can be done. For example, an EJB-based
JWS is an assembly target, and a webapp with several JPFs that use controls is
an assembly target.
For a J2EE module type to support control clients, there must be provided an
implementation of the {{{ControlAssemblyContext}}} interface (see attached),
which exposes the characteristics of the module to the assembly process (ie,
providing access to file system locations so files can be added to the module,
providing access to read/modify descriptors, etc).
{{{
REVIEW: Consider exposing specific operations like "addEjbLink"
}}}
The assembly process:
1. constructs an instance of the appropriate {{{ControlAssemblyContext}}}
1. builds the set of control types and corresponding control impls that are
referenced by the control clients in the assembly target, using the client
manifests.
1. applies the controls binding file (if present) to override impl bindings.
1. introspects the set of impls for instances that specify a
{{{ControlAssembler}}}
1. instantiates an instance of each {{{ControlAssembler}}} and executes it,
passing in the {{{ControlAssemblyContext}}}
Assembly must be done when:
1) a client manifest changes
2) the controls binding file changes
It is the responsibility of each {{{ControlAssembler}}}, when run, to determine
whether the work it needs to do has already been done in a previous execution
(for example, injection of deployment descriptor values).
{{{
TBD: no provision to just "clean" the work done by an assembler. I think the
answer here is you just need to a clean build, anything more seems like a
nightmare.
}}}
{{{
TBD: the controls binding file needs to apply at runtime too. Is there another
file? Think about allowing runtime changing of controls binding.. Interaction
with deployment.. Stale builds..
}}}
----
Back to [:../:Controls]