The brasato webapplication framework has two major implementation concepts:
it implements the Model-View-Controller design pattern. From Wikipedia:
“Model-view-controller (MVC) is an architectural pattern used in software engineering. In complex computer applications that present a large amount of data to the user, a developer often wishes to separate data (model) and user interface (view) concerns, so that changes to the user interface will not affect data handling, and that the data can be reorganized without changing the user interface. The model-view-controller solves this problem by decoupling data access and business logic from data presentation and user interaction, by introducing an intermediate component: the controller.”
it implements the composite design pattern for a component based architecutre
Components in brasato are very much like components in Java SWING, in fact, the whole GUI layer in brasato has been inspired by the SWING architecture. In such a component based architecture, the controller and the view elements are decomposed into a hierarchical structure of components and composite objects.
If you are not familiar with MVC and the composite design pattern, please bring yourself up-to-date before you continue reading.
Components are visual elements displayed somewhere on the screen. They are generated by a controller that is responsible for this specific part of the view and who reacts to events generated by those components.
Components are reusable and generic GUI elements. Sometimes, components are also called widgets. In brasato, we have GUI components like tables, forms, menu tree, a link and many others. Note that all this components are completely business independet. The purpose of a component is to provide a certain functionality to display or manipulate data. What kind of data this is or in what greater context the component is used is irrelevant.
Components are basic elements of the brasato framework, it is most likely that you will never have to create a component yourself, it is a stable set of elements provided by the framework that is used by developers to create a rich user interface.
While the purpose of a component is to display a GUI element, the component itself does not know or tell the framework where exactly on the screen itself should be displayed. This is where the containers come in place. A container has the functionality to contain several components and to position them within the containers area. The position of the container itself is again unknown since the container is a component as well.
There are three important containers in brasato:
: the first
container in the chain that represents the users browser
window.Window
: a placeholder
container. This is used when you don't know yet what your view
will be, but you know that will be something you have to display
laterPanel
: a
HTML based container. Pure HTML is used to position components
contained by this container, thus it is very flexiblVelocityContainer
We can summarize, that a brasato webapplication GUI is a hierarchical structure or containers and components. In the brasato debug mode this hierarchical structure can be observed well. Each container has a thin dotted line that symbolizes the border of the container area.
While the MVC pattern separates the view part from the workflow part of the code, it does not necessary make code component based. In simpler web applications it is very common to have one fat controller that dispatches all the requests and does more or less everything. This is normally the case when you use the servlet development model: for each workflow a dedicated servlet.
What is special about the brasato framework is that it takes care of the whole dispatching process and offers a way to break down a whole business process workflow in manageable controller and view parts. In brasato, developers don't write servlets, they write controllers.
So what is a controller? A controller has the following features:
Implementation of workflow logic: controllers react to events that occure due to user a interaction. e.g. a user clicks on a link, the responsible controller decides what the meaning of this action is and what business logic is triggered by this event. A sidenote: the controller should not implement the business logic itself, this should be sone in a so called manager class. The controller is only responsible in controlling the users GUI workflow.
Creation of a view. Each controller
must have a view, a component that represents the viewable thing
that this controller is about. This is done by executing the
method
in the controllers constructor. In most cases the controllers view
part is eithersetInitialComponent()
a
: in this
case the controler can swap its entire view. Remember, the
panel is only a placeholder for a component that is generated
later!Panel
a
:
in this case the controller can use many components and
position them together with text elements using plain HTML and
CSS codeVelocityContainer
Implementation of the composite pattern. There we have it again: a controller can have many child controllers. We come to this in the next chapter.
Managing of the data model: The first element in the MVC is the datamodel. It is initialized by the controller and handed over to the components that use the datamodel to display the data. Important to understand is the fact that whenever something happens, e.g. a user clicks the remove link in a table entry, the remove operation is not performed by the table component. Remember, the component has no business meaning, it is only a GUI element! The table component fires an event to the controller that created this table component, the controler does execute some business logic and removes the table entry from the table data model. When the table component displays itself, it just takes the updated data model and renders the data from the model.
Controller can be reusable: The higher
up in the controller hierarchy, the less reusable is a controller.
E.g. the MainHomeController
can really just
generate the home area as in the OLAT web application. There is
little hope that this is reusable anywhere else. On the other hand
the GroupController
is used almost
anywhere. It is a business context free controller that is very
reusable.
Sometimes it is difficult to distinguish between components and
controllers: why is something implemented as a controller and why some
other things as a component? You will see that there are some
components like the table component that have a wrapper controller.
Whenever you use a table in the brasato framework you actually use the
TableController
and not the
Table
component. The reason is that the table
component got too many features and to complex to handle all the
configuration options that we wanted like pageing, excel download,
table configuration and more. The controller has much more
possibilities to deal with all this functionality. E.g. the table
configuration feature needs a little data model to know which columns
are enabled by this user. The controller can read this information
from the database and implement a workflow to change the settings.
This can't be done in a component. Remember, a component is only a
view element, it does not implement a workflow!
So, sometimes the border between controllers and components is
thin. Business context free controllers with a high reusability factor
like the GroupController
,
UserSearchController
or
TableController
behave very much like
components.
It is important to understand how all those components and containers are created at runtime to get a full picture about the final layout. The following picture shows the most relevant controllers and components. To reduce complexity unimportant elements have been removed.
In this diagramm we focus only on layout relevant parts of the
framework and ignore the brasato main seNrvlet and dispatching issues.
It is enough to know that at some point the
createChiefController
method on the
BaseChiefControllerCreator
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 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 handels 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 controler: 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.
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 with is
devided in to a section for:
web app header (#header): you could place a link or logo
there. The area is controlled by a Sping configured
HeaderController
the Site
navigation (#nav):
navigation for static sites and dynamic tabs, controlled entirely
by the BaseFullWebappController
a static top navigation element (#topnav): for static links
like the logout button, the search field, an imprint. This is
controlled by the Sping configured
TopNavController
the main area (#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 (#footer). use to display some footer information
like logged in users or a link to the project homepage. This is
controlled by a Sping 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 #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.
When implementing the MVC approach, another fundamental paradign is executed: the separation of the dispatching, event handling and rendering.
When a user request enters the brasato framework it gets
automaticall dispatched by the DispatherAction
.
The framework computes then which component is responsible for dealing
with the request and calls the
dispatchRequest()
method on this
component.
There are two types of requests a component can dispatch:
an 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.
an component provided action: some
functionality the component offers to the controller that created
the component. E.g. in the Table
component,
when actually clicks on a link in one of the rows this is not a
table interal 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 handel it and the dispatching phase is finished.
But when the action was a functionality the
component offers to its Listeners
in the
component specification it is a whole differnt 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
.
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 it enough to know that the components will
signal controlles that a specific event happend.
In the 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 done, 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.
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 translforms 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.
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 component in the HTML DOM tree and replaces it with the newly rendered component view it got from the server.
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 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 programmed does some custom dispatching.
Components are rendered programmatically in Java code. The
render()
method is executed. To understand
how a component is mapped to HTML one must read the Java sourcecode.
To modify the rendering, the class must be patched and recompiled.
Component Renderer
are in the same package as
the components in org.olat.core.gui.components.*
.
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.
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 brasat web application layout, it might very
necessary to modify some of the velocity templates.
See the Velocity User Guide for more information about the possibilites in the velocity engine.