Clone wiki

AspectFaces / 1.Intent-and-motivation

1.Intent-and-motivation

What is it we try to solve?

In order to understand the AspectFaces intention, we should consider the common component-based user interface (UI) development. As an example let use Java EE suggestion on the presentation the domain specific language (DSL) called JavaServer Faces (JSF). This language builds the UI page from components such as panels, table, buttons, widgets etc. We cannot omit the detail that this language has weak type-safety. With the JSF component, we aim to visualize/present data as forms or tables. For simplicity lets, consider forms. When we aim to design a form with JSF that represents a given data (entity from Java Persistence API, or a POJO, DTO, etc), we look at the data fields and its constraints (JPA/Validation annotations) and pick an appropriate JSF widget for each field (such as h:inputText, h:selectMenu). Then, because there is technical incompatibility among the Object-oriented entity for data and the JSF we also need to propagate information about field restrictions, such as length, whether it is required, follows a pattern, etc. Next, we do bind data fields to selected JSF widgets. Furthermore, we may need to apply additional concerns to the JSF Form, such as layout, conditional rendering for given user rights, etc. All these tangles together in the code for the JSF Form. Confucius said that one picture is better than 1000 words so let's look at what we just described at Fig.1.

image2013-10-17 14-47-2.png image2013-10-17 14-46-26.png
Figure 1. Designing a JSF Form with conventional approach (*src RACS'13) Figure 2. Cross-cutting concerns for the JSF form (*src RACS'13)

We can see that in order to design a simple form we need to consider multiple concerns and collapse them to a single JSF code fragment. Next, consider a sample code fragments below. Each fragment shows a plain form extension, with client-side validation, conditional rendering, layout, and perhaps we can imagine even more.

Manually developed Plain JSF Form

Email:
<h:inputText id="email" value="#{i.email}"/>
Name:
<h:inputText id="name" value="#{i.name}"/>
Country:
<h:selectMenu id="country" value="#{i.country}"/>

Manually developed JSF Form with Client-side validation

Email:
<h:inputText id="email" value="#{i.email}"
         validate="#{bean.validate('email')}"/>
Name:
<h:inputText 
         required="true"
         id="name" value="#{i.name}"/>
Country:
<h:selectMenu id="country" 
        required="true"
           value="#{i.country}"/>

Manually developed JSF Form with conditional rendering

Email:
<h:inputText id="email" value="#{i.email}"
         render="#{bean.render('email')}"
       validate="#{bean.validate('email')}"/>
Name:
<h:inputText 
       required="true"          
             id="name" value="#{i.name}"/>
Country:
<h:selectMenu id="country" 
        required="true"
           value="#{i.country}"/>

Manually developed JSF Form with basic layout

<table class="classLayout"> 
<tr>
 <td>Email:</td>
 <td><h:inputText id="email" value="#{i.email}"
              render="#{bean.render('email')}"
            validate="#{bean.validate('email')}"/></td>
</tr><tr>
 <td>Name:</td>
 <td><h:inputText 
            required="true"       
                  id="name" value="#{i.name}"/></td>
</tr><tr>
 <td>Country:</td>
 <td><h:selectMenu id="country" 
        required="true"
           value="#{i.country}"/></td>
</tr>
</table>

Next, let's consider the issues here. The resulting code fragment tangles concerns together. We restate information from the data entity. It is hard to read and thus hard to maintain, managing changes to data and its presentation is a tedious and error-prone work since no type-safety exists. Each concern can be seen as an individual but we cannot manage their individual reuse. For example what if we want to change the layout or to support 3 layouts based on screen size? Or we want to selectively change validation among users, or even the presentation we may need to use combo box rather than select menu etc. How do we do that? Most likely we end up with code replication.

We can summarize the main issues here as information restatement and cross-cutting concerns. Information restatement is obvious from Fig.1 and cross-cutting concerns as well, but better from Fig. 2. We can see a phenomenon that all the considered concern be logically separated as individual at Fig 2. a, but when we want to compose them then the JSF language is limited to only use one dimension for the implementation space and thus they collapse to what we see at Fig 2. b. This is not only problem of JSF or DSL languages but also problem of Object-oriented languages.

How AspectFaces solve it?

AspectFaces lets you design individual concerns separately, and then weaves all of them together. Thus you are not only thinking in the separate space at Fig 2. a but also designing concerns separately. And now we look at how do we weave it all together, while not restating information. When you look back to the Fig 1., it is clear that the data entity directs most of our decisions regards presentation. Thus we expect that a reference to the data, through a data instance is provided. In JSF when you want to make data instance accessible you either outject the instance to the JSF context or you connect it to a Java Bean. Then in the JSF language, you use EL to access the instance. For example, consider the code below. This instance will be the source of information for us and what we do is, we take a reference to it through a custom component as shown in the code on the right side.

Accessing Data instance from a controller in JSF

#{controller.personInstance}

AspectFaces component with reference to an instance

<af:ui instance="#{controller.personInstance}"/>

We can visualize this step by Fig. 3, which shows an AF component three basic phases: Inspection, Transformation, and Runtime code integration.

image2013-10-17 16-14-13.png Fig. 3. AspectFaces High-level Phases

Inspection

AspectFaces component has access to application and JSF context and also has a reference to the data instance. The instance becomes a subject of structure/code-inspection. We gather all information available that are part of the class representing the data (Entity, POJO, DTO, basic class), thus we know all the fields that are part of the object and also its constraints (such as JPA, Validation, Security annotations, or your custom annotations). In this step, we built a meta-model, a structure representing the data. Next, as we consider that the runtime context, such as user settings, roles, etc. may influence the validity of the fields in the metamodel, and as we show later also the selection of JSF widgets. The inspection phase is shown in Fig. 4.

image2013-10-17 16-19-13.png Fig. 4. AspectFaces Inspection phase

Transformation

Transformation phase is the main part of the entire process and uses an aspect approach to enable reuse of all the concerns while providing configurable and generic transformation rules reusable among projects. This maybe sounds like motivation but wait to see the details. The entire phase is shown in Fig. 5. from which we can see that there are 3 sub-phases.

image2013-10-17 16-23-48.png Fig. 5. AspectFaces transformation phase

Presentation rules

Presentation rule is a statement saying how to map a data field to the UI, other-words which widget to use to present a data field in the UI. In order to design transformation rules applicable to projects can make them static, but rather configurable by users. Thus the heart of AspectFaces is a configuration of presentation rules. A rule is relative to a data type such as string or integer and then we want to base our widget selection on many factors. Thus each rule has a query that can be evaluated to true or false. This query, queries the field meta-information and AspectFaces context, thus both the structure/constraint information and runtime information (from context) can be considered. This query uses EL known from JSF or JUEL, which allows you to use logical and arithmetical operation and access context elements, objects and object properties. A field annotation is accessible basically by its name. Let's look at an example below. You can see that mapping rules are grouped by type. Each type has a default template to use. We describe this DLS template later. Consider the String type, which shows more advanced examples. You can see that if a field has name username then another template is used (or you can use class/field combination as well), next you can see a conditional selection for a template, the expression attribute defines the query which can consider any think field related from the meta-model or from the context. The user has access to add any object to the context, thus you can integrate conditions for GeoLocation, Screen-size, etc.

Sample mapping rules

<configuration>
    <mapping>
        <type>Integer</type>
        <type>int</type>
        <type>BigDecimal</type>
        <type>Long</type>
        <type>long</type>
        <default tag="inputNumberTemplate.xhtml" />
    </mapping>

    <mapping>
        <type>Date</type>
        <default tag="inputDateTemplate.xhtml" />
    </mapping>
    <mapping>
        <type>String</type>
        <default 
            tag="inputTextTemplate.xhtml" 
            maxLength="255" 
            size="30" 
            required="false" />
        <var name="username" tag="usernameTemplate.xhtml" />
        <condition 
            expression='${not empty type and type == "readOnly"}' 
            tag="outputTextTemplate.xhtml" />
        <condition 
            expression="${not empty email and email == true}" 
            tag="emailTemplate.xhtml" />
        <condition 
            expression="${not empty password and password == true}" 
            tag="passwordTemplate.xhtml" />
        <condition 
            expression="${not empty maxLength and maxLength > 255}" 
            tag="textAreaTemplate.xhtml" />
    </mapping>

</configuration>

Template composition

The result of presentation rule is a template selection. Template with a DSL code fragment that described the widget. The developer of the target UI language will be familiar with these templates. Because they use the target language and construct with additional markup that allows extending the basic presentation structure. Let's look at inputTextTemplate below. It is very similar to the target language, but note the special markup denoted by a dollar sign. This is again EL that has access to the field-level meta-model and to the context. Thus when we expose a variable foo with text value "bar" we can get the content in the template by specifying $foo$, we can do more than that, we can do tricks like this $empty foo ? 'Ooops forgot' : foo.substring(0,1)$. There are many options to set a context, one of them is through the component handler or through the component such as <af:ui instance="#{controller.personInstance}" foo="bar"/>

Sample template

<h:outputLabel
            id="#{prefix}$fieldName$Label"
            for="#{prefix}$fieldName$"
            value="#{text['$className$.$fieldName$']}:" />

<h:inputText
            disabled="#{empty edit$FieldName$ ? not edit : not edit$FieldName$}"
            value="#{$className$.$fieldName$}"
            required="#{empty required$FieldName$ ? '$required$' : required$FieldName$}"
            size="$size$"
            title="#{text['title.$className$.$fieldName$']}"
            maxlength="$maxLength$"
            rendered="#{empty render$FieldName$ ? 'true' : render$FieldName$}"
            id="#{prefix}$fieldName$" />

This example shows an example generic and reusable template and lets see a basic interpretation for the following context.

Person.java sample class

@Entity
@Table(name = "Person")
public class Person extends EntityObject implements java.io.Serializable {
    //..
    @Column(name = "firstName", nullable = false, length = 100)
    @NotNull
    @Length(max = 100)
    @UiOrder(1)
    public String getFirstName() {
        return this.firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    //..
}

We receive a functioning UI code.

Sample interpretation output considering the Person.class field and text template

<h:outputLabel
            id="#{prefix}firstNameLabel"
            for="#{prefix}firstName"
            value="#{text['person.firstName']}:" />

<h:inputText
            disabled="#{empty editFirstName ? not edit : not editFirstName}"
            value="#{person.firstName}"
            required="#{empty requiredFirstName ? 'true' : requiredFirstName}"
            size="30"
            title="#{text['title.person.firstName']}"
            maxlength="100"
            rendered="#{empty renderFirstName ? 'true' : renderFirstName}"
            id="#{prefix}firstName" />

Layout integration

In layout integration we are inspired with XSLT, which cannot be used with component-based UIs unless there is language support for it, but we go beyond that and provide the possibility to use AF constructs. All that is necessary is to indicate which layout to use.

Passing a layout to the AF component

<af:ui 
    instance="#{controller.personInstance}"
    layout="personDoubleLayout"/>

the layout templates look like this:

Custom Layout (2 col elements and bottom in the middle notes)

<table>
    <af:iteration-part maxOccurs="100">
        <tr>
            <td>$af:next$</td>
            <td>$af:next$</td>
        </tr>
    </af:iteration-part>
    <tr>
        <td colspan="2">$af:notes$</td>
    </tr>
</table>

Note the option to address specific and non-specific fields (af:next vs. af:notes) or to restrict the amount of iterable fields (maxOccurs).

Runtime code integration

So far the af:ui component replaced what we would do manually, receiving the JSF code. But we want to generate the UI on demand in runtime. The last part takes the generated code and builds from it the component tree known to the language interpreter. Which in reality means that <af:ui instance="#{controller.personInstance}" layout="personDoubleLayout"/> gives your user the UI that he understands.

image2013-10-17 17-20-31.png Fig. 6. AspectFaces sample resulting UI (confused user from the US - field state)

image2013-10-17 17-20-57.png Fig. 7. AspectFaces sample resulting UI (elderly user from the US - field state)

image2013-10-17 17-21-19.png Fig. 8. AspectFaces sample resulting UI (kid user out of the US - no field state)

Summary

AspectFaces let you integrate your separately defined concerns to the presentation, there are 4 levels on which your concern may apply: 1 meta-model, 2 presentation selection, 3 presentation extension, 4 layouts. This approach considerably reduces coding efforts, maintenance and does not impact performance. We measured impact in the large enterprise system, and we saved up to 30% of the UI code efforts with AF and the UI load performance got impacted by 6 milliseconds for 250 samples.

Updated