1.2. Component lifecycle and rendering

How components are created: layout and control decomposition

It is important to understand how all those components and containers are created at runtime to get a deeper understanding about the final layout. The following picture shows the most relevant controllers and components. To reduce complexity unimportant elements have been removed.

Decomposition of the framework controllers and components that span up the layout

In this diagramm we focus only on layout relevant parts of the framework and ignore the brasato main servlet and dispatching process. It is enough to know that at some point the BaseChiefControllerCreator.createChiefController method is called for a certain user request to create a new user window. First, a new BaseChiefController is created. This is the top of the controller hierarchy. The BaseChiefController creates an instance of the Window component and adds the HTML elements html, head and body in a VelocityContainer to that window. Therefore, the BaseChiefController is mainly responsible to provide framework related HTML fragments such as the debug tools, the AJAX back channel and covers the whole issues of JavaScript and CSS inclusion.

Then, a SimpleBaseController is created that has a simple VelocityContainer view to add the GUI messages, modal dialog and a GUI stack feature. The SimpleBaseController wrapps the application specific base controller that handles the applications basic behaviour. In most cases this will be the BaseFullWebappController.

You might wonder how the framework knows which controller it should use as the application specific base controller: the BaseChiefController and the SimpleBaseController are both parts of the framework, but the BaseFullWebappController can be replaced with whatever super controller you like. We talked above about the BaseChiefControllerCreator that factored all this controllers - for this purpose the BaseChiefControllerCreator has a Spring injected ContentCreator that has the ability to create the base controller for the current web app. In this example the AutoCreator with the configuration className=BaseFullWebappController is used to create a BaseFullWebappController at run time.

Base controller factory: configured via Spring

The BaseFullWebappController deals with the main navigation and layout of the web app. We think the approach of a main navigation at the top - we call it Site - is universal and can be used for almost every web application out there. The BaseFullWebappController has a VelocityContainer as the main view part which is devided into several sections:

  • layout wrapper (#b_page and #b_page_margins) for pure layouting purposes

  • web app header (#b_header): you could place a link or logo there. The area is controlled by a Spring configured HeaderController

  • the Site navigation (#b_nav): navigation for static sites and dynamic tabs, controlled entirely by the BaseFullWebappController

  • a static top navigation element (#b_topnav): for static links like the logout button, the search field, an imprint. This is controlled by the Spring configured TopNavController

  • the main area (#b_main): The main application area for the currently active site. The controller that is used in this area must implement the MainController interface. In most cases the Main3ColsController is used which features a 1, 2 or 3 column view.

  • the footer (#b_footer): Use it to display some footer information like logged in users or a link to the project homepage. This is controlled by a Spring configured FooterController

Note that the nomenclatura for this elements strictly follows the YAML web layout framework. The BaseFullWebappController layout is based on YAML.

The next level of layout relevant parts are generated by the controller that is responsible for the #b_main area. As I said, usually this is the Main3ColsController delivered by the brasato framework. More about this later. Within the Main3ColsController the three columns can be filled with whatever the application needs.

Dispatching, event and render phase

When implementing the MVC approach, another fundamental paradigm is executed: the separation of the dispatching, event handling and rendering.

When a user request enters the brasato framework it gets automatically dispatched by the DispatcherAction. The framework computes then which component is responsible for dealing with the request and calls the Component.dispatchRequest() method on this component.

There are two types of requests a component can dispatch:

  1. a component internal action: some user action that does only modify a view option of the component. E.g. in the Table component the user could click the table header which then sorts the table ascending or descending in this column. This action does not modify the data model nor does it modify anything in the system at all. It is entirely GUI related and component internal only.

  2. a component provided action: some functionality the component offers to the controller that created the component. E.g. in the Table component, when one actually clicks on a link in one of the rows this is not a table internal GUI issue. This is the selection functionality of the table, one of the main features the Table component offers.

When component internal actions occure, the component will handle it and the dispatching phase is finished.

But when the user action was a functionality that the component offers to its Listeners in the component specification, it is a whole different story. The Listener is the Controller who created the Component and attached itself as Listener. The listener gets informed whenever some of those functions are executed by the user, we call them Event. So, when the user presses this link in the table row, the Table component will fire an Event to the Controller by calling the Controller.event() method.

Now we entered the event handling phase. Actually, this is still part of the dispatching phase since it happens during the execution of the dispatchRequest() method of the Component, but from a logical point of view this is not dispatching anymore. Sending events from a component to a controller, from controllers to parent controllers or even from controllers to global event buses implement the Observer design pattern, another fundamental design concept. But I'm not going into details here, it is enough to know that the components will signal to its listening controlles that a specific event happend.

In the Controller.event() method the Controller catches those events and executes some business logic. For example, the controller could call the UserManager and delete the user associated with the selected row from the database and refresh the data model of the table component. That's it: the controller catches the event from the component and manipulates the datamodel. (In other cases, the controller could fire events to its parent controller to signal that a certain workflow is now finished, and the parent controller could then remove the entire view of the current controller and replace it with another view. But at some point in the hierarchy, a controller will do some business logic and not fire an event anymore since everything has been done that needs to be done.)

Now, when the last event is handeld, the dispatching and event handling phase is finished and the framework continues with the rendering phase. At this point all the business logic has been finished, all database transactions have been submitted, all states are set and we could call it a day for this request. Everythig that follows now is just rendering the data and the new state of the application. After this point, no business logic should be executed anymore and no data manipulation be made.

The render phase is easy: the framework takes the current Window with the whole hierarchy of Components and Containers and traverses it with the Renderer. You can think of the Renderer as a transformer, it transforms the internal object structure into a HTML page. The Renderer has special implementations for each Component and uses those while traversing the component tree recursively. For example, the MenuRenderer will be used to render a MenuTree, the TableRenderer is used to display a Table component. Each of those Renderer produces a string that represents the rendered component as an HTML fragment.

The sum of all those component HTML fragments is the page as an HTML document. Thats it. In the end, the brasato framework delivers this page to the users browser.

Render phase in the AJAX mode

A very powerfull feature of the brasato framework is the automated AJAX mode. When the AJAX mode is enabled, the dispatching and event phase remain the same, but an importand difference happens during rendering phase.

Instead of applying the rendering to the whole Component tree starting from the Window object, the framework checks for each component in the tree if it actually has a dirty view. Dirty means, that the view of the Component changed since the last call. Only those components that are marked as dirty are rendered (including the components child components) and sent to the browser via a background AJAX channel.

In the browser, some JavaScript code detects the corresponding element in the HTML DOM tree and replaces it with the newly rendered component view it got from the server. In fact, this new view is nothing else than a small HTML snipplet.

The effect of the AJAX mode is that the basic layout does not need to be redrawn by the browser, only parts in the DOM tree will change. This results in a more vivid user experience due to lower network traffic and less computer power needed to draw the HTML page in the browser.

From a programmers perspective nothing special has to be done to support this AJAX mode unless a programmer does some custom dispatching or a component wants to implement component-internal AJAX features (e.g. dynamic loading of a menu tree).

General component rendering

Components are rendered programmatically in Java code. The Component.render() method is executed. To understand how a component is mapped to HTML one must read the Java sourcecode for the specific renderer. To modify the rendering, the class must be patched and recompiled. Component Renderers are in the same package as the components in org.olat.core.gui.components.* .

Generally it is not recommended to modify a renderer just to change the layout. After each update of the OLAT application all changes must be carefully reviewed and the patches reapplied. If you can't style a component with the HTML markup that is generated by a renderer, please let me know so that we can modify it for a future release.

VelocityContainer rendering

A special case is the VelocityContainer component. The main feature of this Container is to position contained child components using HTML markup and to add other elements like internationalized text fragments. This is implemented using the Apache Velocity templating engine. When constructing a VelocityContainer instance in a Controller, the path to a velocity template file is one of the main elements of the constructor. The templates are normally stored in a special directory _content on the same level as the controller that constructs the element. During the render phase, the VelocityContainer will use this template to create the HTML fragment.

To create a velocity container instance you can use the BasicController.createVelocityContainer() helper method. As an argument it takes the name of your HTML template. E.g. when giving the name "test", the velocity container will search for a file _content/test.html.

The advantage of this approach is that it is very simple to write Velocity templates and to position other objects like child components, translated strings or objects that represent parts of the data model. A so called VelocityRenderDecorator offers many helpfull methods in the template like translating, URL generation, child component rendering and much more. The render decorator can be accessed using the $r variable in the templates.

Most elements in a brasato web application are implemented in velocity containers, almost every controllers view is constructed using a VelocityContainer. Therefore, most of the HTML code generated in the render phase is defined in the velocity templates. In most cases you can forget about how other components are rendered, most likely you will never need to modify anything there. But for customizing the brasato web application layout, it might be necessary to modify some of the velocity templates.

When you write your own velocity templates, make sure you write valid XHTML 1.0 transitional code. Best is to test your page using an XHTML online validator.

See the Velocity User Guide for more information about the possibilities in the velocity engine.