WARNING: This tutorial is being written! Do not hesitate to report any errors or suggestions.
Quick access: The JavaBeans model Binding to the Javabeans Components Using annotations The data binding and the use of the Repeater
To correctly understand the data binding model of the NWS framework, it is important to remember that in Java, we do not code a class anyhow. Normally, you are expected to comply with the JavaBeans model: it is actually a simple coding convention allowing any tool (here the NWS framework) to find at the execution (at the runtime) all the properties and the events managers carried by a proceeding. The discovery of these elements is possible by using the Java reflection engine which has been extended to support JavaBeans: it is called introspection. In other words, the introspection engine (the java.beans package) is an extension of the Reflection engine (the java.lang.reflect package) to find all the get/set/is prefixed methods to determine the properties and all the methods observing the addXxxListener pattern to determine the recording methods of headphones (Listener == management model of Java event).
For the data binding, we are only interested by the JavaBeans properties. As a reminder, a property is different than an attribute. The attribute corresponds to a variable part of the object and it stores a value: it is also called a member data (of the proceedings). Unlike a property corresponds to a pair of methods: they generally used to access in reading and in writing to an attribute (although in some subtle cases, it is not a requirement).
The NWS Web components can be linked to the data available through the properties of your JavaBeans objects. Moreover, the class of the NWS page can also exhibit properties which you can link your WEB components.
The easiest way to understand the data link model is to study a concrete example. This example is accessible from the application of the NWS demonstrating framework (activate this link to download it). Specifically, this page is samples/DataBinding.wp. Two classes are increasingly used: corelib.services.web.samples.virtualcaddy.webpages.samples.DataBinding and corelib.services.web.samples.virtualcaddy.business.Article. You can find here, the code of this last class.
01 package corelib.services.web.samples.virtualcaddy.business; 02 03 public class Article { 04 05 private int idArticle; 06 private String brand; 07 private String designation; 08 private double unitaryPrice; 09 10 11 public Article( int idArticle, String brand, String designation, double unitaryPrice ) { 12 this.setIdArticle( idArticle ); 13 this.setBrand( brand ); 14 this.setDesignation( designation ); 15 this.setUnitaryPrice( unitaryPrice ); 16 } 17 18 19 public int getIdArticle() { 20 return idArticle; 21 } 22 23 public void setIdArticle( int idArticle ) { 24 if ( idArticle < 0 ) throw new RuntimeException( "Identifier must be positive" ); 25 this.idArticle = idArticle; 26 } 27 28 public String getBrand() { 29 return brand; 30 } 31 32 public void setBrand( String brand ) { 33 this.brand = brand.toUpperCase(); 34 } 35 36 public String getDesignation() { 37 return designation; 38 } 39 40 public void setDesignation( String designation ) { 41 this.designation = designation.toLowerCase(); 42 } 43 44 public double getUnitaryPrice() { 45 return unitaryPrice; 46 } 47 48 public void setUnitaryPrice( double unitaryPrice ) { 49 if ( unitaryPrice < 0 ) throw new RuntimeException( "Unitary price must be positive" ); 50 this.unitaryPrice = unitaryPrice; 51 } 52 53 public String toString() { 54 return this.idArticle + ": " + this.designation + " of brand " + 55 this.brand + " - " + this.unitaryPrice + " €"; 56 } 57 }
Note that this class exposes four properties: getIdArticle/setIdArticle, getBrand/setBrand, getDesignation/setDesignation and getUnitaryPrice/setUnitaryPrice. Here is the code of the Web page class.
01 package corelib.services.web.samples.virtualcaddy.webpages.samples; 02 03 import corelib.services.web.samples.virtualcaddy.business.Article; 04 import corelib.services.web.server.WebPage; 05 import corelib.services.web.server.events.WebPageEvent; 06 07 @SuppressWarnings( "unused" ) 08 public class DataBinding extends WebPage{ 09 10 private static int displayCounter = 0; 11 private Article theArticle = 12 new Article( 0, "The brand", "many informations", 10 ); 13 14 15 @Override public void page_load( WebPageEvent webPageEvent ) { 16 DataBinding.displayCounter ++; 17 } 18 19 20 public int getDisplayCounter() { 21 return DataBinding.displayCounter; 22 } 23 24 public Article getArticle() { 25 return this.theArticle; 26 } 27 28 }
You can notice, under the form of an attribute, the instance of the Article Class. We will return later on the other members of this class. However, it lacks to us a file for our explanations: the Web page itself. Here is the code.
01 <?xml version="1.0" encoding="ISO-8859-1" ?> 02 <web:Html xmlns:web="corelib.services.web.components" 03 xmlns:demo="corelib.services.web.samples.virtualcaddy.webcomponents" 04 codeBehind="corelib.services.web.samples.virtualcaddy.webpages.samples.DataBinding"> 05 <head> 06 <title>Data Binding Sample</title> 07 <link rel="stylesheet" type="text/css" href="../CssStyles.css" /> 08 </head> 09 <body> 10 <h1>Data Binding Sample</h1> <br /> 11 12 <h2>Article description</h2> 13 14 <b>Identifier</b>: <web:OutputText text="#{theArticle.idArticle}" /> <br/> 15 <b>Designation</b>: <web:OutputText text="#{theArticle.designation}" /> <br/> 16 <b>Brand</b>: <web:OutputText text="#{theArticle.brand}" /> <br/> 17 <b>Identifier</b>: <web:OutputText text="#{this.article.unitaryPrice}" /> <br/> 18 <br/> 19 <b>Display count</b>: <web:OutputText text="#{this.displayCounter}" /> 20 </body> 21 </web:Html>
Well, take all this calmly. At the line 04 of the file DataBinding.wp, the Web page is linked to his page class (DataBinding.java). Then, from line 14, the webpage links Web components of type <web:OutputText> to data provided by the Web page class. An expression of data links is introduced by the syntax #{ and is finished by }. The content of this expression is constructed taking into account the JavaBeans model. But three options are allowed.
First option: the expression of link begins with the name of an attribute of the page class. In this case, the following corresponds to one or more properties. For example, the expression #{theArticle.idArticle} allow you to retrieve the returned value by theArticle.getIdArticle(). If the value of a property is also an object, you can continue to descend into its own properties (without limitation deep). Being able to access directly to the attributes of the page class allows you to simplify the coding of this one.
Second option: the expression of link begins with the name of an entry in the user session or with the name of an entry of application data (application data are shared by all the users of the site). In this case the following of the expression is the name of a property of the object stored in the session or in the application.
Third option: an expression of link to the data begins with this. In this case, the following of the expression must correspond to a property's page class. Consider the line 17 of the page class: there is an expression of link #{this.article.unitaryPrice}. Of this expression we can directly think that the page class provides a method getArticle(): indeed we can confirm this at the line 24 of the page class. As the method getArticle returns an item, we can then go into the properties of the considered class (in this case, getUnitaryPrice()).
WARNING: if the link term is used on a component of form entry (whatever its nature <web:TextBox>, ...) and if these write access methods (the setters) necessary for the expression are here, then the data entered into the form will be stored in the associated beans after submission of the form.
The line 19 on the Web page shows you an example where the calculated value by the expression evolves over time. Indeed, in line 15 of the page class, the page_load method (a manager of events that triggers at every page request) increments the value of a static counter to each call. At the line 20, of this same file, the method getDisplaycounter returns the value of this counter. The expression #{this.displayCounter} allows to recover the value of this counter (the third option presented above).
The NWS framework introduces an attractive option with respect to the data link: You can use annotations to control the persistence of your beans. But before talking about this possibility, let us go back a few moments on the concept of Java annotation.
Java 5 (J2SE 5.0) introduced the concept of annotations. An annotation is a metadata that is attached to your code. The annotation is compiled and stored in the associated .class. When this class will be mounted in memory, it will be possible, through the Java reflection engine (the package java.lang.reflect), to know if an element (attribute, method, etc.) of the considered class, has been annotated. This allows considering some framework which will be able to perform certain tasks automatically. For example, the Hibernate framework operates annotations to achieve a mapping between Java objects and tables in a relational database: for example, this framework automatically generates SQL orders to save your objects in base. It is virtually the same for the NWS framework that can automatically take over the persistence of some of your items in the user session or in data applications.
Two annotations can be used to indicate, to the NWS framework, to store your beans in session and in the data application. These annotations shall be placed before the attributes of the page class that you want to make persist between the different queries.
corelib.services.web.annotations.Application: the annotation @Application can store the attributes in the application data. For information, to retrieve a value from the application data from a NWS page, you have to use the following instruction: this.application.getAttribut( "key" );.
this.application.getAttribut( "key" );
corelib.services.web.annotations.Session: the annotation @Session lets you store the attribute considered in the user session calling for the webpage.
To better understand the concept, we have to study the NWS page of items used display in the demo application, its page class. Both sections of code that follow match to the implementation of the said page.
01 <?xml version="1.0" encoding="ISO-8859-1" ?> 02 <web:Html xmlns:web="corelib.services.web.components" 03 xmlns:caddy="corelib.services.web.samples.virtualcaddy.webcomponents" 04 codeBehind="corelib.services.web.samples.virtualcaddy.webpages.SelectArticle"> 05 <head> 06 <title>Select your article</title> 07 <link rel="stylesheet" type="text/css" href="CssStyles.css" /> 08 </head> 09 <body> 10 <h1>Select your article</h1> <br /> 11 12 <div align="center"> 13 14 <table border="0" width="40%"> 15 <tr> 16 <td width="40%">Identifier:</td> 17 <td width="60%"> 18 <web:OutputText id="lblIdentifier" cssClass="LabelBox" 19 text="#{catalogBrowser.currentArticle.idArticle}" /> 20 </td> 21 </tr> 22 <tr> 23 <td width="40%">Brand:</td> 24 <td width="60%"> 25 <web:OutputText cssClass="LabelBox" 26 text="#{catalogBrowser.currentArticle.brand}" /> 27 </td> 28 </tr> 29 <tr> 30 <td width="40%">Designation:</td> 31 <td width="60%"> 32 <web:OutputText cssClass="LabelBox" 33 text="#{catalogBrowser.currentArticle.designation}" /> 34 </td> 35 </tr> 36 <tr> 37 <td width="40%">Unitary Price:</td> 38 <td width="60%"> 39 <web:OutputText cssClass="LabelBox" 40 text="#{catalogBrowser.currentArticle.unitaryPrice}" /> 41 </td> 42 </tr> 43 </table> 44 45 <web:Form method="POST"> 46 <web:Button id="btnPrevious" value="Previous" /> 47       48 <web:Button id="btnAdd" value="Add" /> 49       50 <web:Button id="btnNext" value="Next" /> 51 </web:Form> 52 </div> 53 54 <caddy:CaddyFooter /> 55 </body> 56</web:Html>
01 package corelib.services.web.samples.virtualcaddy.webpages; 02 03 04 import corelib.services.web.annotations.Session; 05 import corelib.services.web.components.Button; 06 import corelib.services.web.components.events.ActionEvent; 07 import corelib.services.web.components.events.ActionListener; 08 import corelib.services.web.samples.virtualcaddy.backingbeans.CatalogBrowser; 09 import corelib.services.web.server.WebPage; 10 import corelib.services.web.server.events.WebPageEvent; 11 12 13 public class SelectArticle extends WebPage { 14 15 @Session private CatalogBrowser catalogBrowser; 16 17 private Button btnPrevious = null; 18 private Button btnAdd = null; 19 private Button btnNext = null; 20 21 public void page_load( WebPageEvent event ) { 22 this.btnPrevious.addActionListener( new ActionListener() { 23 public void actionPerformed( ActionEvent event ) { 24 btnPrevious_actionPerformed( event ); 25 } 26 }); 27 this.btnAdd.addActionListener( new ActionListener() { 28 public void actionPerformed( ActionEvent event ) { 29 btnAdd_actionPerformed( event ); 30 } 31 }); 32 this.btnNext.addActionListener( new ActionListener() { 33 public void actionPerformed( ActionEvent event ) { 34 btnNext_actionPerformed( event ); 35 } 36 }); 37 38 } 39 40 41 public void btnPrevious_actionPerformed( ActionEvent event ) { 42 this.catalogBrowser.moveToPreviousArticle(); } 43 44 45 public void btnNext_actionPerformed( ActionEvent event ) { 46 this.catalogBrowser.moveToNextArticle(); 47 } 48 49 public void btnAdd_actionPerformed( ActionEvent event ) { 50 51 } 52 53 }
In line 15 of the file SelectArticle.java you will notice the presence of the attribute catalogBrowser. You can also note that this attribute is not initialized: he has a value null. However, this attribute is prefixed by the annotation @Session. At each HTTP request, the NWS framework will seek to initialize this attribute with a request stored in the user's session. The key name in the session, will be by default the attribute one ("catalogBrowser"). If no data exist in session for the considered entry, a new instance will be created: it is imperative that the considered class has a constructor accepting no parameter. If this attribute is not of type of a data already present in session (for the key considered), an exception will be produced at runtime.
The CatalogBrowser class allows you to browse in a catalog of items, while retaining the position of the item being presented. The position is unique to each customer, it is logical to store this request in a user session. This class offers the method getCurrentArticle() which returns the article being viewed.
This allows us to write the Web page SelectArticle.wp in order to use the binding to the data. The expression #{catalogBrowser.currentArticle.designation} allows you to access to the designation of the article being viewed.
#{catalogBrowser.currentArticle.designation}
Also if we look at the implementation of the NWS framework demonstration, the method CatalogBrowser.getAllArticles() returns an articles table (Article []). It is possible to link a web component of type <web:Repeater> to a set of beans. Here is the code of the page samples/DataBinding2.wp and this one of the associated page class
01 package corelib.services.web.samples.virtualcaddy.webpages.samples; 02 03 import corelib.services.web.annotations.Session; 04 import corelib.services.web.samples.virtualcaddy.backingbeans.CatalogBrowser; 05 import corelib.services.web.server.WebPage; 06 07 @SuppressWarnings( "unused" ) 08 public class DataBinding2 extends WebPage { 09 10 @Session private CatalogBrowser catalogBrowser; 11 12 }
01 <?xml version="1.0" encoding="ISO-8859-1" ?> 02 <web:Html xmlns:web="corelib.services.web.components" 03 xmlns:demo="corelib.services.web.samples.virtualcaddy.webcomponents" 04 codeBehind="corelib.services.web.samples.virtualcaddy.webpages.samples.DataBinding2"> 05 <head> 06 <title>Data Binding Sample</title> 07 <link rel="stylesheet" type="text/css" href="../CssStyles.css" /> 08 </head> 09 <body> 10 <h1 align="center">Data Binding Sample</h1> <br /> 11 12 <div align="center"> 13 <table border="1" width="60%"> 14 <tr> 15 <th width="25%">Identifier</th> 16 <th width="25%">Brand</th> 17 <th width="25%">Designation</th> 18 <th width="25%">Unitary price</th> 19 </tr> 20 <web:Repeater values="#{catalogBrowser.allArticles}" elementAlias="article"> 21 <tr> 22 <td><web:OutputText text="#{article.idArticle}" /></td> 23 <td><web:OutputText text="#{article.brand}" /></td> 24 <td><web:OutputText text="#{article.designation}" /></td> 25 <td><web:OutputText text="#{article.unitaryPrice}" /></td> 26 </tr> 27 </web:Repeater> 28 <caption align="bottom">Article listing</caption> 29 </table> 30 </div> 31 </body> 32 </web:Html>
As you can see, the Web component of type <web:Repeater> is linked to data. But as the linked data is of a table type (it also works with collections of type java.util.list), the Web component will duplicate its content for each item of the collection. To facilitate the definition of the linked expressions, an alias is created for each iterate (here article).
Dominique LIARD - © 2007 SARL Infini Software - All rights reserved Other brands and product names in these documents are the property of their respective owners.