Reference » The subform lifecycle

The subform lifecycle

Last modified by Andreas Hahn on 2011/06/09 10:22

Subform creation

In a default shept setup a subForm gets created when the user clicks on the chain linkgo.png icon. You put chain commands into the view with the chainRow-tag in the shept.jar META-INF/tags/shept-opt resource location:

 <shept-opt:chainRow chainName="addresses" code="addresses" />

The chainName attribute reflects either a name you have specified for the chain or if there is none the name of the target segment. When the command is excecuted the default handler ChainingComponent will then call the chains configured CommandFactory to create a new subForm instance. Shepts provides the default implementations (RefreshableListCommandFactory and AssociationCommandFactory) that support datagrids that typically create a FilteredListHolder as the backing object.


Now clicking the chain link in one row starts a couple of actions

  1. Look up for a chain configuration of the current segment that fits the specified "addresses".
    2. Read the chain definition form the configuration and obtain the commandFactory which will serve the next segment.

Segment building continues with CommandFactory#getCommand()

CommandFactories that build datagrids

  1. create a formBackingObject for the next segment which is by default a FilteredListHolder
    2. Populate the listholders newModelTemplate with a newly created instance of a model object as defined by the commandFactories configuration.
    3. Initialize the created newModelTemplate with #initialize(String string) - an optional text like 'enter data here'
    4. Initialize the created newModelTemplate with #initialize(SourceObject object) - the source object from the row you have just clicked.
    5. Populate all empty data entry rows of the new segment with a copy of newModelTemplate

Note that the target entity needs to support this by implementing an #initialize(SourceClass object) method. If the target entity is an Address and the source is Person then Address should implement #initialize(Person person). This is not enforced however and if omitted it simply means that new target entity objects won't get initialized from the source. After initialization the filter gets excecuted and the list is populated with the results. The rules for populating the result list will follow the specified FetchType on your association.

Read more about initialization here


Relationships are handled by the AssociationCommandFactory. Usually your entity objects will contain plenty of associations. Either you have defined them manually as @OneToMany relationships or when you have started from an existing database your initial import tools (e.g. HibernateTools) will have generated them from existing foreign key references. An AssociationCommandFactory cares about those @OneToMany relationships from your model. It wraps the entity relation between source and target into a ReloadableAssociation that is a filter (FilterDefinition) implementation.  The purpose of this wrapped FilterDefinition is to provide a resource for 1) creating new model instances (the C from CRUD) and 2) refresh the underlying association (e.g. read it again from the datasource).

Refreshable lists

The RefreshableListCommandFactory first creates a filter by instantiating the filterClass property. Typical filter objects are implementations of HibernateCriteriaDefinition or ExampleDefinition. The filter will then be initialized from the configuration. The filter should implement an #initialize(SourceClass object) method that takes as its only argument an object of the source entity - then it will be also initialized by that method. In our example an AddressFilter should at least support an #initialize(Person person) method. After initialization is done the filter will be exceuted and the list is populated with the results. How many lines are actually fetched from the database depends on the configuration of the underlying ScrollingListProvider. By default it is at least twice the size of the visible Viewport (the number of lines shown in one data grid view).

Custom commandFactories

Custom commandFactories are implemented by implementing CommandFactory#buildCommand()


Subform destruction

Subforms can get destroyed in different ways. An obvious one by is by clicking on 'close' as shown in the screenshot. Usually a subform gets also destroyed when the contents in one of the  preceeding subforms changes. The rationale behind this is to disallow content mismatches between the different forms on a web page. 


Created by Andreas Hahn on 2011/01/10 16:36

© 2011 - Andreas Hahn