Multi-phase builder generation behavior

In this topic ...

Builders Calling Builders

Deferring a Builder Call

Related Topics ...

Overview: Creating Builders

Creating Builder Definitions

Creating Builders from Models

Implementing a Coordinator

For some Builders, such as Rules in a Rule Set, the order of the Builder Calls can be as important. For other Builders, such as an HTML Builder that puts a Text Input box on a named element in a certain page, the order is irrelevant. In another case, where the Builder puts a link on "All Pages in the Model," it is vital that the Builder is able to run after all the Pages have been created.

The developer of the Builder has the option of making order important or not. Factory Builder architecture supports multi-phase generation. Any Builder that wants to defer its work, for whatever reason, can invoke a defer operation, specifying the name of the phase in which it would like to be re-invoked.

The Factory supports three main generation phases. These phases are:

  • Creation - The first phase when all the Builder Calls in the Model are invoked. In general, any Builder that calls other Builders should do so in this phase. All Builders that construct new elements should do so in this phase.

  • Post-Creation - In this phase Builders that modify elements that were constructed in the Creation phase are run . The second-phase Builder Calls do not risk generating an error because the element they are supposed to operate on has not yet been created. Note that the list of Builder Calls being invoked is not the list of Builder Calls from the Model. It is only the list of Builder Calls for which the associated Builder specifically asked for the Builder Call to be deferred to this phase. This can include some Builder Calls that were in the original list, but it might also include Builder Calls that were invoked by other Builders.

  • Validation - The final phase that the Factory invokes is the "Validation" phase. This is where a Builder can check the validity of the finished product, perhaps providing some error or warning messages to be displayed in the Designer

In addition to the three phases invoked by the Factory, a Builder can defer itself to any other named phase. However, phases with names other than the official three above will not be invoked automatically. Instead, the outside entity that called into the Factory requesting a Generation will have the opportunity to trigger these additional phases. This offers a tremendous amount of flexibility to embed optional functionality in a Builder that can be invoked at Generation time by the agent in charge.

The following code can be used to control and determine phase:

/** Generation phases */

    /** Initial generation phase when objects are created */

    public static final String PHASE_CONSTRUCTION = "Construction";

    /** Generation phase for modifying objects that were created in Construction phase */

    public static final String PHASE_POSTCONSTRUCTION = "PostConstruction";

    /** Generation phase for doing more subtle modification on objects that were created in the first two phases */

    public static final String PHASE_MODIFICATION = "Modification";

    /** Generation phase for doing validation after all creating/modifying objects has completed in the first two phases */

    public static final String PHASE_VALIDATION = "Validation";

    /** Generation phase for processing the abstract elements. i.e. Action Lists into methods

     * Note that this is called AFTER the Domain-specific AppProcesser */

    public static final String PHASE_PROCESS = "Process";

    /** Generation phase for externalizing the generated pieces. i.e. Classes, JSP files, etc.

     * Note that this is called AFTER the Domain-specific AppExternalizer. */

    public static final String PHASE_EXTERNALIZE = "Externalize";

 

Builders Calling Builders

When one Builder wants to call another Builder, the process is to create a new Builder Call object (the API provides assistance with this) and then to invoke it. Since the new Builder Call is fundamentally no different from a Builder Call on the primary Builder Call List, the secondary Builder operates normally, as if it were a primary Builder.

If one Builder calls another, the (highly) recommended method is to make the call during the Creation Phase. If the secondary Builder expects to run in another phase, then it will defer itself using the same mechanism that it would defer itself if it were a primary Builder Call. However, it is conceivable that one Builder would have to run in the Post-Creation phase and it would not know which other Builders it plans to call until then. In this case, it is acceptable for the secondary Builder to be called, and it will be called exactly as it would be in the Creation Phase. If it defers itself to the Post-Creation Phase, then it will be called again, immediately, but with a set up that it will recognize as the Post-Creation Phase. Note that one Builder should never call another in the Validation Phase.

 

Handling Errors from Called Builders

When a Builder another Builder, there is a possibility that the other Builder will generate warning or error messages. Such messages are automatically carried up to the original Builder Call in the Builder Call List. This occurs even if the chain of Builders calling other Builders is multiple levels deep.

 

Deferring a Builder Call to Another Phase:

This is typical sample code that would appear in the doBuilderCall method of a Builder class that wants to defer itself to another phase:

   GenContext genContext;

   WebApp webApp;

   BuilderCall builderCall;

 

   String name;

   String basisVariable;

   public void doBuilderCall(GenContext genContext, WebApp webApp, BuilderCall builderCall,

BuilderInputs builderInputs)

   {

        if (genContext.getGenerationPhase().equals(GenContext.PHASE_CONSTRUCTION))

        {

this.genContext = genContext;

this.webApp = webApp;

this.builderCall = builderCall;

 

// code to get all the builder inputs

name = builderInputs.getString(Constants.Name, null);

basisVariable = builderInputs.getString(Constants.BasisVariable, null);

 

// Defer to PostConstruction phase if it is still desired.

boolean defer = constructionPhase();

if (defer)

genContext.deferBuilderCall(GenContext.PHASE_POSTCONSTRUCTION, builderCall);

        }

        else

        {

        postConstructionPhase();

        }

    }

    

    public boolean constructionPhase()

    {

    boolean deferToPostConstruction = true;

    

// Construction phase work here.

    

    return deferToPostConstruction;

    }

    

    public void postConstructionPhase()

    {

// PostConstruction phase work here.

    }