Access to add and change pages is restricted. See: https://cwiki.apache.org/confluence/display/OFBIZ/Wiki+access

Overview

This document explains how OFBiz handles screen real estate. It will provide an overview of the OFBiz widget system. Understanding the custom widget system is a prerequisite if you want to change the look and feel of screens in OFBiz. Not only the internal facing screens but also the eCommerce application (the Online store) uses the home-grown OFBiz widget system to render screens. As you probably don't want to run an online store with the default layout that OFBiz comes with, you will need to understand how the OFBiz widget system is designed in order to customize the look and feel of your shop.

There are a couple more scenarios where understanding the OFBiz widget system might be helpful, for example if:

  • You intend to implement a different user interface technology for OFBiz, for example JSF, maybe in combination with AJAX.
  • You want to adapt parts of the OFBiz UI for smaller screens, for example mobile phones. 

OFBiz uses a custom widget system, partially based on the FreeMarker templating engine (http://freemarker.sourceforge.net/). But when trying to understand how to customize both the look and feel as well as the content of screens in OFBiz, FreeMarker essentially comes last. You will need to get your mind around a couple more things before templating comes to play.

The 'what' and the 'how'

There are two aspects to a screen:

  • What data does it show.
  • How does it present that data.

A screen is usually displayed as the result of a request. In a webapp this is going to be an HTTP request, for example:

http://www.yourserver.com/partymgr/control/main

Most OFBiz URLs follow that pattern. The first part after the server name selects the webapp which is supposed to process this request. In this case, the request is for the partymgr webapp. The next part, control, determines that this request should be processed by the Controller Servlet. (See the mapping in web.xml in each webapp.) The Controller Servlet uses the controller.xml file in the webapp's WEB-INF folder to decide what content to serve in response to this request.

Hint: If you wanted to integrate any functionality into OFBiz which you don't want to base on the Controller Servlet, you can use any URL namespace except control and map it to your custom servlet.

Rendering Screens

How the Controller Servlet handles a request

The Controller Servlet is configured using the controller.xml file in the WEB-INF folder. That file has three kinds of XML elements which are important now:

  1. handler
  2. request-map
  3. view-map

While this is the order in which they typically appear in the controller.xml file, let's start with the request-map.

Element: request-map 

  • Attributes: uri
  • Children: security, event, response

The uri attribute is used to match a request-map to the actual request. Keep in mind that the webapp name and control have already been matched by the servlet container to dispatch processing here. Therefore in our example, the remainder of the URL to match here is just "main".

The request map for the URI main looks like this:

<request-map uri="main">
    <security https="true" auth="true"/>
    <response name="success" type="view" value="main"/>
</request-map>

The security element specifies that https is required (https="true") and that this portion of the application requires proper user authentication and authorization (auth="true"). Parts of the application which do not require either one are the online store, for example.

The security element might intercept the processing of the request. If auth="true" and there is no valid OFBiz user attached to the current servlet session, processing will branch into rendering a login screen to obtain a valid OFBiz user, then return and check if the currently authenticated user has sufficient authorization for this request. (??? Is this really handled here), after that, processing will continue. If the user logged in before and there is a valid OFBiz user available in the session, processing will just continue. Should the request come in as plain HTTP and https="true" is set, the controller servlet will redirect the client browser to the corresponding HTTPS URL.

In our example (partymgr/control/main) there is no event triggered by this request, so no processing happens in this case, as we do not have an event element. In case there is no processing, an outcome of success is the default.

The outcome of any processing (which is a string) determines which response to the request is rendered and sent back. In our example, there is only one response to choose from, which is:

<response name="success" type="view" value="main"/>

The type of response is a view (type="view") with name name of "main" (value="main"). Don't get confused by the view name being identical to the URI part that the request-map matched. This is just by chance in this case. The view could be named anything, as long as there will be a view-map element with that name.

Note: A view is not the only possible response to a request. We will discuss other potential responses later in this document. Right now, we're up to understanding how an HTML screen is rendered in a webapp in response to an HTTP(S) request.

Element: view-map

  •  Attributes: name, type, page

Let's look at the view-map entry for the view with the name main:

<view-map name="main" type="screen" page="component://party/widget/partymgr/PartyScreens.xml#findparty"/>

The type of the view is screen (type="screen") and the screen definition is read from the URI "component://party/widget/partymgr/PartyScreens.xml#findparty". The component: protocol is a OFBiz internal mechanism which retrieves just the screen definition for the findparty screen from the file PartyScreens.xml. That file may contain more than one screen definition. So this mechanism primarily serves the purpose of not having to have too many small XML files, which would be the case if a single XML file could contain only one screen definition. You can think of such an XML file as a library of screen definitions. We will examine that file and its format later.

Element: handler

  • Attributes: name, type, class

The information from the view-map element is resolved against the handlers defined by the elements of type handler, usually in the first section of the controller.xml document. As we are rendering a view, we're only interested in handlers of type "view", so we do a lookup for a handler with type="view" and name="screen":

<handler name="screen" type="view" class="org.ofbiz.widget.screen.ScreenWidgetViewHandler"/>

The result of the lookup is a Java class - org.ofbiz.widget.screen.ScreenWidgetViewHandler in this case - which extends the AbstractViewHandler class, which implements the ViewHandler interface.

The control servlet will now pass on the processing to the specified view handler by calling the render method using the a, b and c as parameters. It's entirely up to the implementation of the view handler to generate the response and write it to the servlet response channel.

Hint: If you wanted to implement a view handler which is not based on the OFBiz widgets toolkit but using whatever other view technology, as long as it's a servlet based technology, you would have to implement your own ViewHandler class and make it known to the controller servlet by adding a handler element to the controller.xml file. Then you could create one or more view-map elements with the type="yournewhandler" and have any response in a request-map dispatch processing to that view.

Anatomy of a screen definition

In our example, the page parameter passed to the render method is a URI: component://party/widget/partymgr/PartyScreens.xml#findparty. This URI is split by the ScreeenWidgetViewHandler into two pieces. Anything left of the hash ('#') sign is used to locate an XML file, in this case the file PartyScreens.xml, which should be found in the party/widget/partymgr directory. As mentioned before, a single XML file may contain several screen definitions. Therefore the right-hand portion of the URI is used as a key to find the screen definition with the id findparty within that file.

The PartyScreens.xml file looks like this:

Element: screen

Children: section 

Each screen can consist of a number of sections. In our example, we have only one section.

Element: section

Children: actions, widgets

Element: actions

Here you define the possible actions you need to do. For that you can use different type of actions

  • Labels actions
    • property-map: to define labels (in a map) from a xml labels file
    • property-to-field: to define a field value from a properties file
  • Entity actions, this is simple action directly on entities, they are
    • entity-and
    • entity-condition
    • entity-one
    • get-related-one
    • get-related
  • Set actions, mostly 2 "sub-types"
    • set : simple assignation
    • use of Groovy snippet for a bit more involved assignation (filtered, modified, etc.). Advantage: no need to create/open a new file, immediately visible/readable.
      • syntax : <set field="fieldName" value="${groovy: 1+1}"/> (you may need to set a type using the type attribute of the set element)
  • Script
    • script: to call a Groovy script from a file, not short enough to be snippet.  Inside your Groovy script you prepare and set your data in a context variable.
  • Service
    • service: to call a service

Element: widgets

In our example, the whole section of the screen contains just one widget, which is a decorator-screen.

A decorator literally takes the net content of the screen and decorates it with everything else which you will see on the screen later. For example, the net content of the findparty screen is just the search form, consisting of some field labels, fields, and a submit button. When the page is rendered in the browser, it needs to have headers, footers, the menu bar, etc. All these elements are added by the decorator.

The location attribute of the decorator-screen element points to the definition of the decorator. In most cases, you will find the decorator as part of the framework, not inside a vertical application, unless there is a need to have an application specific decorator. Variables such as ${parameters.mainDecoratorLocation} can be used to point to the decorator definition, which does not always make it easy to find the corresponding definition.

A typical place to look for the definition of the mainDecoratorLocation parameter would be the WEB-INF/web.xml file of the respective webapp, where this parameter can be defined as a context parameter of the web application. In our example (the partymgr app) you will find the following data there:

<context-param>
  <param-name>mainDecoratorLocation</param-name>
    <param-value>component://party/widget/partymgr/CommonScreens.xml</param-value>
    <description>The location of the main-decorator screen to use for this webapp; referred to as a context variable in screen def XML files.</description>
</context-param>

We can get away with some guesswork about the implementation details of the decorator here, though, to make sure we maintain the bird's eye perspective. You can examine the detailed definition of the decorator later. It's just another widget.

Imagine the decorator-screen widget as a kind of screen template with one or more areas to be filled with actual content. In our example, we can see that the screen definition has content for just one decorator-section with the name body. You can think of at analogue to the body section of an HTML page, i.e. this is the main content of the screen.

Again, we can find three child elements here:

  • conditions
  • widgets
  • fail-widgets

Think of this as a simple switch: If the conditions are met, the widgets will be rendered, otherwise the fail-widgets will be rendered.

In our example, the condition is used to evaluate if the user belonging to the respective session is allowed to view this screen or not. In case the user's session does not have appropriate rights, a simple error message is displayed, using the label widget.

In case the user has the right to view the findparty form, the actual form content is rendered, controlled by the following XML fragment:

<widgets>
  <platform-specific>
    <html>
      <html-template location="component://party/webapp/partymgr/party/findparty.ftl"/>
    </html>
  </platform-specific>
</widgets>

The platform-specific widget again is a kind of switch-case-statement. The OFBiz widget toolkit isn't limited to rendering HTML user interfaces. It can could theoretically render the user interface in any different technology you can imaging, like Swing, XUML, Flash, speech, ... In case the UI is being rendered in HTML (which is the case most of the time in OFBiz) all widgets which are children of the html element will be rendered.

In this simple example, there is just one widget as a child element of html, which is html-template. That widget uses Freemarker to fill in actual content into a FreeMaker HTML template. The template is pointed to by the component attribute of the html-element widget. The component protocol means that the location of the template is relative to the application.

Strictly speaking, this is where we leave the OFBiz widget toolkit and you would have to turn to a FreeMaker tutorial to understand the template being used there. Please refer to the FreeMarker Manual.

You may also use the form widget (using <include-form...) instead of a Freemarker template here.  A form widget is a definition in xml of a list or single form.  The form widget is discussed here.

There are few more include possibilities, at all:

What to display: Data Binding in Forms

Depending on the tool you will use for final rendering, you will use one of the techniques below to bind data to your fields:

Form actions

If you include one or more form widgets, the better way to prepare your data is to use the action sub element to specify actions specific to the form. This helps if you want to reuse your form elsewhere, or have the actions legible when defining your form. There, you will also find a row-action element to prepare forms of the list type (or multi type, which is variation of the list type).  You may also call a service using the service element.  There are plenty of examples of form actions available OOTB, which can be found with the following one line script:

find -name "*Forms.xml" -printf '\n\n%p\n\n' -exec sed -n -e '/<actions>/,/<\/actions>/p' {} \;

Groovy script form action

If you use Freemarker the better way to prepare your form data is to call one or more Groovy scripts. You call them in the action part of the screen. Inside you prepare and set your data in a context variable. There are several examples of Groovy form actions available OOTB, which can be found with the following one line script:

find -name "*Forms.xml" -printf '\n\n%p\n\n' -exec xmllint --xpath "//form//actions//script" {} \;
tutorial

To continue on screen and form widget, see OFBiz Tutorial - A Beginners Development Guide

  • No labels

1 Comment

  1. Very nice tutorial to start with OFBiz! thanks, everything's clear now!