First of all, it's important to at least vaguely understand what is going on behind the scenes in the ComponentGateway servlet. In a nutshell, the ComponentGateway:
Ok, so let's take a look at the actual servlet. Here's the basic flow:
XMLObject page = xmlcFactory.create(HelloWorld1HTML.class);
Node node = page.getDocument().getElementById("HelloWorld");
this grabs a reference to the <html> element that is identified by the "HelloWorld" id in the XMLC template :
<html id="HelloWorld">
TemplateView tv = new DefaultTemplateView(node);
TemplateModel tm = new HelloWorldModel();
BTemplate templateComp = new BTemplate(tm);
templateComp.setView(tv);
In this case we are implementing the model just like we would in
Swing, by using an inner class. We'll look at the specifics a littler
further on. For now, just remember that the model's responsibility is to
provide data for the component. By binding a component to a view, we are saying that the component is
going to assume responsibility for rendering everything that exists
below the particular node that backs the view.
root.add(templateComp);
return page;
That's it! The ComponentGateway will invoke render() on the root component, which in turn will cause our template component to render. Once that finishes, the ComponentGateway will render the DOM structure that we provided. The resulting page is returned to the client browser.
Alright, now let's look at what it takes to implement the model. BTemplate uses the TemplateModel interface. Note that unlike Swing components (and unlike the rest of the Barracuda components too!), the template component can take any number of models. When a model is added to the component, it queries the model to determine its name. This is important so that when the component processes directives in a template, it can tell which model it should query to actually retrieve the data.
We should also note that the Model does not have to be implemented using an inner class; we just do it that way because it's convenient and that's how you usually do it in Swing.
The TemplateModel interface defines a number of methods, but by extending from AbstractTemplateModel we only need to implement two:
public String getName()
public Object getItem(String key)
For the getName() method, we return the String "HelloWorld". Now, when the component encounters a directive in the template, it can map the directive to the model name HelloWorld and ask it for data.
When we implement the getItem() method, we simply look at the requested key and return the appropriate data. The BTemplate is smart enough to handle several kinds of data coming back from the model: Nodes, BComponents, and Strings. There may be occasions however where you'd like to return a complex block of HTML or another BComponent, but in most cases, it will be simplest just to return Strings (as we do here).
Now is a good chance to look at the actual HTML template, since when dealing with a BTemplate, the template is responsible for telling the component what data is needed where. So how do we identify which parts of the template need to by dynamically populated?
Well, in HTML we can use directives embedded in element's class attribute field. A directive is any String that follows a well defined format:
Dir::<command>.<model>.<key>.<data>
So let's look at the template, what directives do we see? In the case of the HelloWorld template, there are several:
<title class="Dir::Get_Data.HelloWorld.Title">[Title]</title>
<h2 class="Dir::Get_Data.HelloWorld.Title">[Title]</h2>
<p class="Dir::Get_Data.HelloWorld.Descr">[Descr]</p>
<p class="Dir::Get_Data.HelloWorld.Hello">[Hello]</p>
From this we can see that all the directives use the same command: "Get_Data". This tells the template component that it needs to try and get data for the key in question and bind it to the particular node containing the directive. So, as each directive is encountered the component looks up the model specified (in this case "HelloWorld") and then queries the model for the key. The model returns the data and the component places it in the template.
Note that if we want to rearrange the page, all we have to do is update the template and then recompile using XMLC; it doesn't matter how much we change the page -- we don't have to modify the component or our model unless the designer wants to actually include new keys which are not currently supported.
Pretty neat, huh?
There are a couple of other things worth noting. First, there are three or four other directives that will be addressed in subsequent tutorials. Second, if you don't like the idea of putting directives into your HTML, not to worry: they can be stored separately (either in a file or programmatically). Third, if you don't like the idea of directives at all, have no fear: you can accomplish the same thing using other components (although none of them are quite as easy to use as BTemplate!).