Tuesday, September 28, 2010

Introduction to Context Web Application Framework

I'm the creator of Context Web Application Framework (Context) and after long time of developing it, I'm happy to finally introduce it publicly. It is a result of a long dream that is beginning to come true.

So, what is this about? Context is a component based framework based on Java, XML, XSL and Guice. That may sound exotic at first but in reality that choice has given me a possibility to create a well behaving and flexible framework.

The basic idea is that all pages are made of Java-components that can be mixed at will. There is no difference between pages and components within. Everything is the same.

XML-based representation



The components themselves have a mapping to XML or internally to a DOM-tree. This means that for each component there exists a logical representation of its contents. The representation is not tied purely to class properties. Components may create a more complex DOM-model if needed.

When all the components are combined it creates a complete DOM-tree which is, during rendering, transformed into XHTML via XSL. XSL as templating language is conceptually most suitable for this task. It does contain its quirks and is a bit bloaty at some points, but currently there does not exist better alternative. In the future the templates may be extended to support Context even better.

Stateful pages



In Context pages are stateful. When a page is loaded by internet browser, a corresponding server-side companion, called WebApplication is created and it exists in the server during the entire lifetime of the page.

WebApplication contains the page state, and all the components that are assigned to the page. During the lifetime of the page it is possible to add and remove components if needed.

Every single page has its own WebApplication, they are not shared or pooled in any way. So, you may just open the same page in to multiple browser tabs, and they all have their own state. In the server WebApplication is not saved into session but to different cache. This state is handled transparently by Guice and Context.

The reasoning is that with this approach the page remembers its state on the server and makes it possible to create complex interaction between page components. You can even with little effort make localization so that the language of the entire page can be changed on the fly.

The server side



On the server side components interact by simply calling methods of other Java-components to change their state. When enough changes are made during page update, the new state is reflected back to the browser.

All page components are also independent. This means that the components are able to refresh themselves at will. All that is needed is to call refresh() and that is enough. Of course it means that XSL-template needs to know how the refresh is actually made, but in most cases it is quite trivial.

Interaction from client side and back



When user invokes actions on the page, those actions are transformed into requests to the server. By using Javascript, special remote methods are invoked in the corresponding java-component that is listening to the request. Then the component decides what to do with the request and communicates it to other Java-components if needed.

Then, all the components that decide to refresh themselves, do so, and finally when everything is ready, an update is sent back to the browser and the result of the user action becomes visible.

A small example



Here is a very simple, but working, example. It is a message board system. The system contains of two elements where one is used to add new messages to the board, and the other is used to show the messages. You may find this kind of system from the Demo-section of Context-homepage.

First are the Java classes:

// This is the message-type the the board contains
public class Message {
String title;
String content;
}

// This is the component that shows the messages
public class MessageBoard extends EnhancedElement {

ObjectBuilder messageBuilder = ObjectBuilder
.forClass(Message.class).asText("content");

List<Message> messages;

@EmbeddedAttribute
public int messageCount() {
return messages.size();
}

@CustomBuild
public void buildMessages(DOMBuilder b) {
DOMBuilder messagesb = b.descend("messages");
for (Message message : messages) {
messageBuilder(messagesb.descend("message"), message);
}
}

public void addMessage(Message message) {
if (message != null) {
messages.add(message);
refresh();
}
}
}

// This is component used to add new message
public class MessageEditor extends EnhancedElement {

MessageBoard board;

// This method can be called remotely from browser
@RemoteMethod
public void sendMessage(Message message) {
board.addMessage(message);
}
}


The example shows all the elements and a DTO. The components are extending EnhancedElement that enables elements to use annotation-based configuration and makes the components easy to use. The interaction between components is also simple. Just call a method and the component may choose itself, whether it should update itself or not.

If that snippet would be shown in XML it might look something like this:

<WebApplication>
...
<MessageBoard id="el2" messageCount="10">
<messages>
<message title="My first message">
<content>
Some message with
wrapping lines.
</content>
</message>
<message title="My second message">
<content>
Some message with
wrapping lines.
</content>
</message>
</messages>
</MessageBoard>
...
<MessageEditor id="el3" />
...
</WebApplication>


Of course in reality that XML is kept as DOM-tree and is never printed out itself. The important thing here is that this representation do not say anything what it should look like. It only tells what information is shown.

The final piece is the XSL-template. For this particular example, following XSL might suffice:

<!-- Template for MessageBoard.class -->

<xsl:template match="MessageBoard">
<div id="{@id}">
<xsl:call-template name="MessageBoard.content" />
</div>
</xsl:template>

<xsl:template match="MessageBoard.update">
<replaceInner id="{@id}">
<xsl:call-template name="MessageBoard.content" />
</replaceInner>
</xsl:template>

<xsl:template name="MessageBoard.content">
Messages: <xsl:value-of select="@messageCount" />
<table>
<xsl:for-each select="messages/message">
<tr>
<td>
<xsl:value-of select="@title" />
</td>
<xsl:apply-templates select="content" />
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>

<!-- Template for MessageEditor.class -->

<xsl:template match="MessageEditor">
<form id="{@id}">
<xsl:call-template name="MessageEditor.content" />
</form>
</xsl:template>

<xsl:template match="MessageEditor.update">
<replaceInner id="{@id}">
<xsl:call-template name="MessageEditor.content" />
</replaceInner>
</xsl:template>

<xsl:template name="MessageEditor.content">
Title: <input type="text" name="title" /><br/>
Message: <br/>
<textarea name="content"></textarea><br/>
<input type="button" class="button" 
onclick="contextfw.call('{@id}', 'sendMessage', $('#{@id}').serializeObject());" 
value="Send" />
</xsl:template>


This shows some standard XSL-templates with conventions to support the functionality of Context. For instance the element replaceInner is used by component update to inform how the update should be made. That element simply replaces the contents of the element with a new one.

Separation between layers



Context creates a very sharp distinction between java and frontend layers. On larger projects, development can be separated to two teams. One for the backend to handle the Java-components, and the other to the frontend to make the layout. Basically the teams need to agree on the remote methods to communicate with the server and the XML that is used to transfer the information from Java to XSL.

How to get involved



The current version of Context is 0.5.x and is meant to be evaluated by developers and enthusiasts so that by their feedback Context is able to grow stable 1.0. It is not yet meant for production. There is still a lot to do.

How to get started? Well, navigate yourself to www.contextfw.net and begin from there. The site itself is made with Context, so there is no need to create external demos. By trying the tutorial you are able to create your very first Context-application.

The homepage is still quite small and is missing a lot of information, but it will evolve during time. Also the best way into get contact is to you dedicated discussion group.

I hope you will have a fun time with this framework.

- Marko Lavikainen