Building Components

Components of the model are constructed using the builder pattern1. Different types of components require the use of different builders. The interfaces for these builders were listed in the previous section. However, a concrete implementation of a builder is required to do any real work. Builder objects can be created using the ComponentBuilderFactory class defined in the curam.util.client.model package. The factory class provides a number of factory methods to create builders. Only the use of the following factory methods are supported in the Cúram application:

createComponentBuilder
Creates and returns an object implementing the ComponentBuilder interface. Use this to build generic components that do not require a binding and that do not contain other components.
createFieldBuilder
Creates and returns an object implementing the FieldBuilder interface. Use this to build fields that are bound to data sources.
createContainerBuilder
Creates and returns an object implementing the ContainerBuilder interface. Use this to build components that may contain other components of any kind.

The component builders present a simple, flat API for creating components. They eliminate the need to understand the internal structure of components. In particular, the properties of the objects that hold additional information about a component, such as bindings, parameters and links can be defined directly through the builder interface; there is no need to create instances of these objects or understand how they are stored.

To use a builder, instantiate it using the appropriate factory method and then call the appropriate setter methods to set the properties of the component being built. When complete, call getComponent to get the instance of the newly built component object. When getComponent is called and has returned the new component, the builder object resets all of the properties and may be reused to build another component. Until getComponent is called, many of the simple properties can be set again to overwrite their existing values. However, this may not work for properties that represent items in collections, such as the parameters of the component.

Once built, components are immutable, much like java.lang.String objects, or the Path objects described in Accessing Data with Paths. The only way to change a property of a component is to build a new component with the modified value for that property. Component builders can be used to create entirely new components, but are commonly used to create new components that are modified copies of other components to overcome this immutability. The starting point in this process is the component that will act as the prototype for the new component. Create the builder object and then pass the prototype component to the builder's copy method. This will set all of the properties of the component component to be built from the properties of the prototype component. Use the setter method of the builder to overwrite (including with a null value) the properties of the new component that differ from the prototype component. Finally, call the getComponent method on the builder to get the new component that is the modified copy of the original, prototype component. A typical use of this copy-and-modify process is when making multiple copies of a Field object, changing the domain and extending the paths, before delegating the copy of the field for rendering by another renderer plug-in class.

When copying a prototype Container object using the builder's copy method, all of the child components of the container are copied by reference. A reference is sufficient, as the child components are immutable. Because references are used, any child that is itself a container will become a child of the new container complete with its own child components. When it is necessary to change the children of a Container that must be copied using a builder, the copyShallow method should be called on the ContainerBuilder instead of the copy method. The copyShallow method does not copy any references to the child components. Copy these one-by-one by iterating over the child components of the prototype container and then calling the add method on the ContainerBuilder. The child components can be copied and modified, or even selectively omitted, during this process if required.

1 See the Wikipedia article on the builder pattern for a brief description of the pattern. The renderer plug-in, in creating components, acts as the "Director" in that description of the pattern.