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:

@Control -- marker annotation valid on fields; the annotated field's type is a control type (directly, as a control interface/extension, or indirectly as the generated ControlBean that implements a control interface/extension).

@ControlReference -- single value annotation valid on classes or methods; the annotation's value specifies the a control type that the control client uses. @ControlReferences are required whenever a client uses a control type in a purely programmatic way (ie, there is no @Control annotated field of that control type in the client).

{{{TBD: elaborate on how this might work for clients that are Java-centric, but aren't "plain Java code", e.g. JSPs, BPELJ, etc.}}}

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:

Example client manifest (e.g. named

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 @ControlInterface annotation. The expectation is that overriding the default binding is an unusual occurrence. The conventional approach to overriding an annotation value would be via deployment descriptors, 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:

Example controls binding file (


The external configuration file should be in the classpath as If you are building a Web application that uses Controls, then you would put a file in WEB-INF/classes to take advantage of external binding. If you are building a jar with Controls in it that requires external binding, then would be in the root of the jar.

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 "assembler" attribute on the @ControlImplementation annotation. The class referenced by "assembler" must implement the ControlAssembler interface.

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, 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).

TBD: Add message logging functionality to ControlAssemblyContext
     so implementations can emit diagnostics to assembly tools.
TBD: Expose more abstract operations like "addEjbRef()" on
     ControlAssemblyContext.EJBModule, rather than just raw "getEjbJarXml()".

The assembly process:

  1. constructs an instance of the appropriate ControlAssemblyContext

  2. 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.
  3. applies the controls binding file (if present) to override impl bindings.
  4. introspects the set of impls for instances that specify a ControlAssembler

  5. instantiates an instance of each ControlAssembler and executes it, passing in the ControlAssemblyContext

Assembly must be done when:

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

Controls/AssemblyAndBinding (last edited 2009-09-20 23:24:38 by localhost)