Wednesday, May 30, 2012

Tapestry - Dependency Injection

Before we understand Dependency Injection in Tapestry, let us see some fundamentals.

Tapestry has the notion of Pages, Components and Services.

While all of them are POJOs, Tapestry assumes that the POJOs in /pages folder are Pages, those in /components are Components and /services are Services.

Pages and Components have their corresponding .tml files. A page can be rendered, but a component cannot be rendered. A component can be used by a page.

Services do not have .tml files. Instead, each Service has an explicit interface and implementation. Services provided functionality that other classes can use. For example, a service can implement a business computation, it can transform, filter, process data, do security checks, write logs, handle email communication, schedule events for data backup, etc. Essentially, anything that is not directly related to rendering a page or handling a page event (user clicking on a page) can be made a service.

Tapestry allows Pages, Components and Dependencies to all be injected into each other, using the following annotations:
@InjectPage
@InjectComponent
@InjectService

Additionally, it has the generic @Inject annotation which "automagically" picks up the correct thing to inject (except when it runs into ambiguity - but let us not worry about that now).

In this post, let us create a Service POJO and inject it.

In /src/main/java/org/confucius, create a folder 'services'

In /src/main/java/org/confucius/services, create a Interface GreetDAO.java, like this:

 package org.confucius.services;  
   
 import java.util.List;  
   
 import org.confucius.Greet;  
   
 public interface GreetDAO {  
      public List<Greet> getInternationalGreetsList();  
 }  
   

In /src/main/java/org/confucius/services, create a class GreetDAOImpl.java, like this:

 package org.confucius.services;  
   
 import java.util.ArrayList;  
 import java.util.List;  
   
 import org.confucius.Greet;  
   
 public class GreetDAOImpl implements GreetDAO {  
   
      public List<Greet> getInternationalGreetsList() {  
           List<Greet> greetList = new ArrayList<Greet>();  
             
           Greet englishGreet = new Greet("English", "Hello World!");  
           greetList.add(englishGreet);  
             
           Greet frenchGreet = new Greet("French", "Bonjour tout le Monde!");  
           greetList.add(frenchGreet);  
             
           Greet italianGreet = new Greet("Italian", "Buongiorno a Tutti!");  
           greetList.add(italianGreet);  
             
           Greet spanishGreet = new Greet("Spanish", "Hola Mundo!");  
           greetList.add(spanishGreet);  
             
           Greet swahiliGreet = new Greet("Swahili", "Jambo!");  
           greetList.add(swahiliGreet);  
             
           return greetList;  
      }  
   
 }  
   


Now we need to tell Tapestry to load GreetDAOImpl as an implementation of service GreetDAO.

For this we need to make a Module.

A Module is a place where services are defined, besides other things. Conveniently, a Module is just another POJO - one with a very specific name by convention: AppModule.java.

In /src/main/java/org/confucius/services, create a class AppModule.java, like this:

 package org.confucius.services;  
   
 import org.apache.tapestry5.ioc.ServiceBinder;  
   
 public class AppModule {  
        
      public static void bind(ServiceBinder binder){  
         binder.bind(GreetDAO.class, GreetDAOImpl.class);  
       }  
   
 }  
   


Note that there are other ways to define modules, but we will not worry about that right now. We will just use the default AppModule.java


Finally, we need to make one more change for this Module to get loaded.

By convention, we should name our Tapestry Filter in web.xml 'app'. So update your web.xml, like this:

 <!DOCTYPE web-app PUBLIC  
  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
  "http://java.sun.com/dtd/web-app_2_3.dtd" >  
   
 <web-app>  
   <context-param>  
     <param-name>tapestry.app-package</param-name>  
     <param-value>org.confucius</param-value>  
   </context-param>  
   
   <filter>  
     <filter-name>app</filter-name>  
     <filter-class>org.apache.tapestry5.TapestryFilter</filter-class>  
   </filter>  
   
   <filter-mapping>  
     <filter-name>app</filter-name>  
     <url-pattern>/*</url-pattern>  
   </filter-mapping>  
     
 </web-app>  
   


We are all set to inject our new Service.


Update your InternationalGreets.java class to use this GreetDAO service, like this:

 package org.confucius.pages;  
   
 import java.util.List;  
   
 import org.apache.tapestry5.annotations.Property;  
 import org.apache.tapestry5.ioc.annotations.Inject;  
 import org.confucius.Greet;  
 import org.confucius.services.GreetDAO;  
   
 public class InternationalGreets {  
   
   @Property  
   private Greet greet;  
   
      @Inject  
      private GreetDAO greetDAO;  
        
      public List<Greet> getInternationalGreetsList(){  
           return greetDAO.getInternationalGreetsList();  
      }  
 }  
   


If you now rebuild and redeploy HelloWorldTapestry, you will see the International Greets in a table, just like you did before.

However, this time Tapestry injected the GreetDAO service to make the greets available.

Tuesday, May 29, 2012

Tapestry - Grid

Tapestry uses the Grid component to display data tables.

Let us see this by displaying the International Greets in a Grid.

In /src/main/java/org/confucius, create a class Greet.java, like this:

 package org.confucius;  
   
 public class Greet {  
      private String language;  
      private String greeting;  
        
      public Greet(String language, String greeting) {  
           this.language = language;  
           this.greeting = greeting;  
      }  
   
      public String getLanguage() {  
           return language;  
      }  
        
      public void setLanguage(String language) {  
           this.language = language;  
      }  
        
      public String getGreeting() {  
           return greeting;  
      }  
        
      public void setGreeting(String greeting) {  
           this.greeting = greeting;  
      }  
 }  
   

Update InternationalGreets.java with a method to return a List of Greets, like this:

 package org.confucius.pages;  
   
 import java.util.ArrayList;  
 import java.util.List;  
   
 import org.apache.tapestry5.annotations.Property;  
 import org.confucius.Greet;  
   
 public class InternationalGreets {  
   
   @Property  
   private Greet greet;  
   
      public List<Greet> getInternationalGreetsList(){  
           List<Greet> greetList = new ArrayList<Greet>();  
             
           Greet englishGreet = new Greet("English", "Hello World!");  
           greetList.add(englishGreet);  
             
           Greet frenchGreet = new Greet("French", "Bonjour tout le Monde!");  
           greetList.add(frenchGreet);  
             
           Greet italianGreet = new Greet("Italian", "Buongiorno a Tutti!");  
           greetList.add(italianGreet);  
             
           Greet spanishGreet = new Greet("Spanish", "Hola Mundo!");  
           greetList.add(spanishGreet);  
             
           Greet swahiliGreet = new Greet("Swahili", "Jambo!");  
           greetList.add(swahiliGreet);  
             
           return greetList;  
      }  
 }  
   

Update InternationaGreets.tml to use the Grid component to display the greets, like this:

 <html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">  
      <body>  
     <t:grid source="internationalGreetsList" row="greet"/>  
      </body>  
 </html>  
   

Since we are using the default Grid, i.e. there are no specific instructions, Grid will show each property of the Greet object in the order in which it appears in Greet.java. Each column will be sortable by default.

If you rebuild and redeploy HelloWorldTapestry, you will see the International Greets in a sortable table.

Tapestry - Navigation

Let us see how to navigate from one page to another in Tapestry.

Let us create two new pages.

In your /src/main/resources/org/confucius/pages, create a file called InternationalGreets.tml, like this:

 <html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">  
      <body>  
         <p>   
       English: Hello World!   
       <br/>   
       French: Bonjour tout le Monde!   
       <br/>   
       Italian: Buongiorno a Tutti!   
       <br/>   
       Spanish: Hola Mundo!   
       <br/>   
       Swahili: Jambo!   
         </p>   
      </body>  
 </html>  
   

In your /src/main/java/org/confucius/pages, create a file called InternationalGreets.java, like this:

 package org.confucius.pages;  
   
 public class InternationalGreets {  
   
 }  
   


In your /src/main/resources/org/confucius/pages, create a file called AmericanGreets.tml, like this:

 <html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">  
      <body>  
         <p>   
          Regular: Hi!   
       <br/>   
       Friendly: Whatsup!   
       <br/>   
       Extra Friendly: Hey, How are you doing!   
         </p>   
      </body>  
 </html>  
   

In your /src/main/java/org/confucius/pages, create a file called AmericanGreets.java, like this:

 package org.confucius.pages;  
   
 public class AmericanGreets {  
   
 }  
   


Update Index.tml to contain two new buttons, like this:

 <html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">  
      <body>  
           <h2>${greeting}</h2>  
             
           <form t:id="greetForm">  
                <input t:id="internationalGreetsButton" t:type="submit" value="Show International Greets"/>  
                <input t:id="americanGreetsButton" t:type="submit" value="Show American Greets"/>  
           </form>  
      </body>  
 </html>  
   


Update Index.java to handle the two new buttons, like this:

 package org.confucius.pages;  
   
 import org.apache.tapestry5.annotations.Component;  
 import org.apache.tapestry5.corelib.components.Form;  
   
 public class Index {  
      private String greeting;  
      private Object formEventReturn;  
        
      @Component(id = "greetForm")  
      private Form form;       
        
      public Index() {  
           this.greeting = "Hello World, Tapestry!";  
      }  
   
      void onSelectedFromAmericanGreetsButton() {   
           formEventReturn = AmericanGreets.class;  
      }  
        
      void onSelectedFromInternationalGreetsButton() {   
           formEventReturn = InternationalGreets.class;  
      }  
   
      Object onSuccessFromGreetForm() {  
           return formEventReturn;  
      }  
        
      public void setGreeting(String greeting) {  
           this.greeting = greeting;  
      }  
   
      public String getGreeting() {  
           return greeting;  
      }  
        
 }  
   


Note that we have introduced three new methods, two which handle the button clicks, and one which handles the form submission.

We return the .class corresponding to the appropriate page - this tells Tapestry which page to navigate to.

If you rebuild and redeploy HelloWorldTapestry, you will see two buttons which navigate you to International and American greets.

Tapestry - Bean-side Components

Tapestry allows you to specify components in the bean, instead of in the template.

Let us create the Sliding Panel component in the bean. To refresh our memory, the bean is the Java class associated with the template.

Update your Layout.java class to include the SlidingPanel component, like this:

 package org.confucius.components;  
   
 import org.apache.tapestry5.annotations.Component;  
 import org.chenillekit.tapestry.core.components.SlidingPanel;  
   
 public class Layout {  
   
      @Component(parameters = {"subject=Chenillekit Greeter"})  
      private SlidingPanel panel1;  
        
 }  
   

Here, we have used annotations to tell Tapestry that 'panel1' is a SlidingPanel component, and its 'subject' property is 'Chenillekit Greeter'.

Now, update Layout.tml to use this Sliding Panel, like this:
 <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">  
   <head>  
     <title>Tapestry</title>  
   </head>  
   <body>  
     <h3>Basic Tutorial Series</h3>  
     
           <div t:id="panel1">  
                  <t:body/>  
           </div>  
   
           <p>Visit Us @ www.projectconfucius.org</p>  
             
   </body>  
 </html>  


If you rebuild and redeploy HelloWorldTapestry, you will see the Sliding Panel just like before. Thus, there is no difference in presentation whether you specify a component in the template or in code.

Typically, you will specify the component in code when you want to configure it dynamically, or if you want to keep your template clean of configurations.

Tapestry - Chenillekit

There are several open source component libraries for Tapestry, like Tynamo, TapX, Chenillekit, etc.

We will use Chenillekit as a demo, and put the greeting inside a Sliding Panel.

Update your pom.xml to contain the Chenillekit dependency, like this:

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
       <modelVersion>4.0.0</modelVersion>  
       <groupId>org.confucius</groupId>  
       <artifactId>HelloWorldTapestry</artifactId>  
       <packaging>war</packaging>  
       <version>0.0.1-SNAPSHOT</version>  
         
       <dependencies>  
           <dependency>  
                <groupId>org.apache.tapestry</groupId>  
                <artifactId>tapestry-core</artifactId>  
                <version>5.3.3</version>  
           </dependency>              
   
           <dependency>  
                <groupId>org.apache.tapestry</groupId>  
                <artifactId>tapestry5-annotations</artifactId>  
                <version>5.3.3</version>  
           </dependency>  
               
           <dependency>  
                <groupId>org.chenillekit</groupId>  
                <artifactId>chenillekit-tapestry</artifactId>  
                <version>1.3.3</version>  
           </dependency>  
         
   </dependencies>  
         
    <build>  
        <finalName>HelloWorldTapestry</finalName>  
    </build>  
         
 </project>  
   

Update Layout.tml to use a Sliding Panel, like this:

 <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">  
   <head>  
     <title>Tapestry</title>  
   </head>  
   <body>  
     <h3>Basic Tutorial Series</h3>  
     
           <t:chenillekit.SlidingPanel t:subject="Chenillekit Greeter">  
             <t:body/>  
           </t:chenillekit.SlidingPanel>      
   
           <p>Visit Us @ www.projectconfucius.org</p>  
             
   </body>  
 </html>  

Now if you rebuild and redeploy HelloWorldTapestry, you will see the greeting inside a Chenillekit Sliding Panel.

Tapestry - Layouts

To create the same look-n-feel across multiple pages, Tapestry provides the concept of Layout. For example, all pages may have the same header and footer,

A Layout looks very similar to any other Page, except that it is placed in the /components folder instead of /pages.

For now, we will not worry about the difference between a component and a page - they are very similar. Both have a foo.tml file and a corresponding foo.java POJO.

Let us build a Layout for our pages.

In /src/main/resources/org/confucius, create a folder 'components'

In  /src/main/resources/org/confucius/components, create a file Layout.tml, like this:

 <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">  
   <head>  
     <title>Tapestry</title>  
   </head>  
   <body>  
     <h3>Basic Tutorial Series</h3>  
     
     <t:body/>  
   
     <p>Visit Us @ www.projectconfucius.org</p>  
             
   </body>  
 </html>  


Note that we have included the Tapestry tag library. The magic here is the t:body tag - this will get automatically replaced by the content of the actual page.

Again, this looks just like any other Tapestry page, but because it is in the /components folder, Tapestry treats it like a 'component'.


In /src/main/java/org/confucius, create a folder 'components'

In  /src/main/java/org/confucius/components, create a class Layout.java, like this:

 package org.confucius.components;  
   
 public class Layout {  
   
 }  
   

This is just an empty POJO, but it is necessary to make it available to Tapestry.

Now, update your Index.tml page to use the Layout, like this:

 <html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">  
      <body>  
           <h2>${greeting}</h2>  
      </body>  
 </html>  
   


The t:type attribute tells Tapestry to use Layout.tml as the layout component.

If you now rebuild and redeploy HelloWorldTapestry, you will see the header and footer rendered in the page.

Note:
If some of your pages needed a different layout, say Layout2 - then you will need to create a Layout2.tml and Layout2.java, and in your pages, you will say t:type="layout2"

Friday, May 25, 2012

Tapestry - Using Beans

Due to Tapestry convention, Index.java is already a Bean, no configuration necessary.

Let us see how to use it in Index.tml.

Update your Index.java to have a property 'greeting', like this:
 package org.confucius.pages;  
 public class Index {  
      private String greeting;  
      public Index() {  
           this.greeting = "Hello World, Tapestry!";  
      }  
      public void setGreeting(String greeting) {  
           this.greeting = greeting;  
      }  
      public String getGreeting() {  
           return greeting;  
      }  
 }  

We can now use this field in Index.tml, like this:
 <html>  
 <body>  
 <h2>${greeting}</h2>  
 </body>  
 </html>  

Due to the one-to-one mapping between pages and Beans, Tapestry will look for the 'greeting' property in Index.java, since it is referred to in Index.tml

Tapestry will automatically call the getGreeting()) method to get the property 'greeting'.

If you rebuild and redeploy HelloWorldTapestry, and point your browser to:
http://localhost:8080/HelloWorldTapestry/

you will see "Hello World, Tapestry!" displayed.

Tapestry Hello World - Setup

Let us setup a Tapestry project using Maven.

In Eclipse, go to File --> New Project --> Maven Project

Use the maven-archetype-webapp

Specify:
Group Id: org.confucius
Artfact Id: HelloWorldTapestry
Package: org.confucius

Once the project is created, we will update the pom.xml to include the Tapestry libraries.

So your pom.xml will now look like this:
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
       <modelVersion>4.0.0</modelVersion>  
       <groupId>org.confucius</groupId>  
       <artifactId>HelloWorldTapestry</artifactId>  
       <packaging>war</packaging>  
       <version>0.0.1-SNAPSHOT</version>  
       <dependencies>  
           <dependency>  
                <groupId>org.apache.tapestry</groupId>  
                <artifactId>tapestry-core</artifactId>  
                <version>5.3.3</version>  
           </dependency>              
           <dependency>  
                <groupId>org.apache.tapestry</groupId>  
                <artifactId>tapestry5-annotations</artifactId>  
                <version>5.3.3</version>  
           </dependency>  
       </dependencies>  
       <build>  
        <finalName>HelloWorldTapestry</finalName>  
       </build>  
 </project>  

Next, we need to update our web.xml to use Tapestry.

Your web.xml will now look like this:
 <!DOCTYPE web-app PUBLIC  
  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
  "http://java.sun.com/dtd/web-app_2_3.dtd" >  
 <web-app>  
   <context-param>  
     <param-name>tapestry.app-package</param-name>  
     <param-value>org.confucius</param-value>  
   </context-param>  
   <filter>  
     <filter-name>Tapestry Filter</filter-name>  
     <filter-class>org.apache.tapestry5.TapestryFilter</filter-class>  
   </filter>  
   <filter-mapping>  
     <filter-name>Tapestry Filter</filter-name>  
     <url-pattern>/*</url-pattern>  
   </filter-mapping>  
 </web-app>  

We direct all URLs to be handled by the Tapestry filter.


The default Welcome page for Tapestry is Index.tml

Under /src/main/resources, create the folder structure:
/src/main/resources/org/confucius/pages

In /src/main/resources/org/confucius/pages, create a file Index.tml, like this:
 <html>  
 <body>  
 <h2>Hello World, Tapestry!</h2>  
 </body>  
 </html>  

Note that an TML file looks just like a HTML file.

Under /src/main, create a Source Folder called 'java'
(R-click on /src/main, select New-->Other, then select Java-->Source Folder)


Under /src/main/java, create the folder structure:
/src/main/java/org/confucius/pages


In /src/main/java/org/confucius/pages, create a class Index.java, like this:
 package org.confucius.pages;  
 public class Index {  
 }  

Note that this is an empty POJO, but it must be available to Tapestry - it is the matching POJO for Index.tml

Our Tapestry project is now setup.

If you build and deploy the project, and browse to
http://localhost:8080/HelloWorldTapestry/

You will see "Hello World, Tapestry!" displayed. 

Tapestry

Tapestry is very similar to JSF.

However, it uses Convention-Over-Configuration to greatly reduce configuration and simplify UI development.

Just like JSF Facelets, Tapestry has its own templating engine. Tapestry template files end in the .tml extension.

The most significant convention is that every page Foo.tml must have a corresponding Foo.java.

Foo.java is a POJO and is automatically a Tapestry Bean, no configuration is necessary.

Secondly, Foo.java can only be accessed from Foo.tml and not from any other template.

Thirdly, any method in Foo.java can return a class (say Bar.class), or a string (say "Bar"). This tells Tapestry that the next page to display is Bar.tml

These simple conventions go a long way in making a Tapestry project very organized.

For example, in JSF, since any page can refer to any Bean, very soon it leads to a criss-cross of references from pages to Beans. If a page is deprecated, it is not clear if any of the Beans need to be deprecated as well. In the absence of convention, pages and Beans become disconnected (eventually, a mess).

Tapestry, because if its one-to-one relation between pages and Beans, makes it very clear how pages can access Beans. If a page is deprecated, the corresponding Bean gets deprecated as well.

This is one example of how Tapestry conventions make things simpler. There are several others.

Another example, since a Bean is associated with exactly one page,  maintaining state is non-ambiguous. In JSF, if a Bean is called from several pages, some of its state may be set by one Page, other by another Page - leading to a chaotic situation.

Finally, building Tapestry components is way easier than building corresponding JSF components.

There are many other optimizations and scalability that Tapestry is able to deliver because of its well thought-out conventions.

Thursday, May 24, 2012

JSF - Dependency Injection

Just like Spring (see this post), JSF provides support for injecting Beans into other Beans.

Let us see how this is done.

We will move the method for creating a List of Greets to a new class, then inject this class into HelloBean.

In your /src/main/java/org/confucius, create a class called GreetDAO.java, like this:

 package org.confucius;  
   
 import java.util.ArrayList;  
 import java.util.List;  
   
 import javax.faces.bean.ManagedBean;  
 import javax.faces.bean.SessionScoped;  
   
 @ManagedBean(name="greetDAO_v1")  
 @SessionScoped  
 public class GreetDAO {  
      public List<Greet> getInternationalGreetsList(){  
           List<Greet> greetList = new ArrayList<Greet>();  
             
           Greet englishGreet = new Greet("English", "Hello World!");  
           greetList.add(englishGreet);  
             
           Greet frenchGreet = new Greet("French", "Bonjour tout le Monde!");  
           greetList.add(frenchGreet);  
             
           Greet italianGreet = new Greet("Italian", "Buongiorno a Tutti!");  
           greetList.add(italianGreet);  
             
           Greet spanishGreet = new Greet("Spanish", "Hola Mundo!");  
           greetList.add(spanishGreet);  
             
           Greet swahiliGreet = new Greet("Swahili", "Jambo!");  
           greetList.add(swahiliGreet);  
             
           return greetList;  
      }  
 }  
   

Note that we have declared this class to be a Bean named "greetDAO_v1"
(Typically, DAO classes connect to a database to get data objects, but here we are create the objects on the fly - for the purpose of demo)

Next, update your HelloBean to make use of this DAO class, like this:

 package org.confucius;  
   
 import java.util.List;  
   
 import javax.faces.bean.ManagedBean;  
 import javax.faces.bean.ManagedProperty;  
 import javax.faces.bean.SessionScoped;  
   
 @ManagedBean(name="helloBean")  
 @SessionScoped  
 public class HelloBean {  
      private String greeting;  
        
      @ManagedProperty(value = "#{greetDAO_v1}")  
      private GreetDAO greetDAO;  
   
      public HelloBean(){  
           this.greeting = "Hello World JSF!";  
      }  
        
      public String getGreeting() {  
           return this.greeting;  
      }  
   
      public void setGreeting(String greeting) {  
           this.greeting = greeting;  
      }  
   
      public GreetDAO getGreetDAO() {  
           return greetDAO;  
      }  
   
      public void setGreetDAO(GreetDAO greetDAO) {  
           this.greetDAO = greetDAO;  
      }  
   
      public String getInternationalGreets() {  
           return "international_greets";  
      }  
   
      public String getAmericanGreets() {  
           return "american_greets";  
      }  
        
      public List<Greet> getInternationalGreetsList(){  
           return greetDAO.getInternationalGreetsList();  
      }  
   
 }  
   

We have injected the GreetDAO bean into this class, and are using its method to return a List of Greet objects.

If you rebuild and redeploy HelloWorldJSF, you will be able to see the data table showing languages and greets.

JSF did what is necessary to provide a GreetDAO class instance to HelloBean.

JSF - Richfaces Datatable

A very common scenario in UI is to show a data table.

Usually a method gets a list of objects from a database, and we need to present them as a table.

Let us use Richfaces to display such a data table.

In your /src/main/java/org/confucius, create a class called Greet.java like this:

 package org.confucius;  
 public class Greet {  
      private String language;  
      private String greeting;  
      public Greet(String language, String greeting) {  
           this.language = language;  
           this.greeting = greeting;  
      }  
      public String getLanguage() {  
           return language;  
      }  
      public void setLanguage(String language) {  
           this.language = language;  
      }  
      public String getGreeting() {  
           return greeting;  
      }  
      public void setGreeting(String greeting) {  
           this.greeting = greeting;  
      }  
 }  

In your HelloBean.java, create a new method which returns a List of Greet objects, like this:

 package org.confucius;  
 import java.util.ArrayList;  
 import java.util.List;  
 import javax.faces.bean.ManagedBean;  
 import javax.faces.bean.SessionScoped;  
 @ManagedBean(name="helloBean")  
 @SessionScoped  
 public class HelloBean {  
      private String greeting;  
      public HelloBean(){  
           this.greeting = "Hello World JSF!";  
      }  
      public String getGreeting() {  
           return this.greeting;  
      }  
      public void setGreeting(String greeting) {  
           this.greeting = greeting;  
      }  
      public String getInternationalGreets() {  
           return "international_greets";  
      }  
      public String getAmericanGreets() {  
           return "american_greets";  
      }  
      public List<Greet> getInternationalGreetsList(){  
           List<Greet> greetList = new ArrayList<Greet>();  
           Greet englishGreet = new Greet("English", "Hello World!");  
           greetList.add(englishGreet);  
           Greet frenchGreet = new Greet("French", "Bonjour tout le Monde!");  
           greetList.add(frenchGreet);  
           Greet italianGreet = new Greet("Italian", "Buongiorno a Tutti!");  
           greetList.add(italianGreet);  
           Greet spanishGreet = new Greet("Spanish", "Hola Mundo!");  
           greetList.add(spanishGreet);  
           Greet swahiliGreet = new Greet("Swahili", "Jambo!");  
           greetList.add(swahiliGreet);  
           return greetList;  
      }  
 }  

Update your international_greets.xhtml to display the Greet objects in a data table, like this:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
 <html xmlns="http://www.w3.org/1999/xhtml"  
      xmlns:h="http://java.sun.com/jsf/html"  
      xmlns:f="http://java.sun.com/jsf/core"  
      xmlns:ui="http://java.sun.com/jsf/facelets"  
      xmlns:rich="http://richfaces.org/rich">  
       <ui:composition template="/templates/template.xhtml">  
           <ui:define name="title">International Greets</ui:define>  
           <ui:define name="content">  
                <h:form>  
               <rich:dataTable value="#{helloBean.internationalGreetsList}" var="greet" id="greettable">  
                      <rich:column>  
                        <f:facet name="header">  
                          <h:outputText value="Language"/>  
                                  </f:facet>  
                     <h:outputText value="#{greet.language}"/>                  
                      </rich:column>  
                      <rich:column>  
                        <f:facet name="header">  
                          <h:outputText value="Greeting"/>  
                                  </f:facet>  
                     <h:outputText value="#{greet.greeting}"/>                  
                      </rich:column>  
               </rich:dataTable>  
                </h:form>  
           </ui:define>  
   </ui:composition>  
 </html>  

The Richfaces DataTable will automatically iterate through the list, and populate the table.

If you rebuild and redeploy HelloWorldJSF, you will see a DataTable displaying all the greets in different languages.

JSF - Navigation

Let us see how to go from one page to another in JSF 2.0.

Note: JSF 1.2 had a different way of doing things

Let us create two new pages.

In your /src/main/webapp, create a file called international_greets.xhtml, like this:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
 <html xmlns="http://www.w3.org/1999/xhtml"  
      xmlns:h="http://java.sun.com/jsf/html"  
      xmlns:f="http://java.sun.com/jsf/core"  
      xmlns:ui="http://java.sun.com/jsf/facelets"  
      xmlns:rich="http://richfaces.org/rich">  
       <ui:composition template="/templates/template.xhtml">  
           <ui:define name="title">International Greets</ui:define>  
           <ui:define name="content">  
                <p>  
                English: Hello World!  
                <br/>  
                French: Bonjour tout le Monde!  
                <br/>  
                Italian: Buongiorno a Tutti!  
                <br/>  
                Spanish: Hola Mundo!  
                <br/>  
                Swahili: Jambo!  
                </p>  
           </ui:define>  
   </ui:composition>  
 </html>  


In your /src/main/webapp, create a file called american_greets.xhtml, like this:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
 <html xmlns="http://www.w3.org/1999/xhtml"  
      xmlns:h="http://java.sun.com/jsf/html"  
      xmlns:f="http://java.sun.com/jsf/core"  
      xmlns:ui="http://java.sun.com/jsf/facelets"  
      xmlns:rich="http://richfaces.org/rich">  
       <ui:composition template="/templates/template.xhtml">  
           <ui:define name="title">American Greets</ui:define>  
           <ui:define name="content">  
                <p>  
                Regular: Hi!  
                <br/>  
                Friendly: Whatsup!  
                <br/>  
                Extra Friendly: Hey, How are you doing!  
                </p>  
           </ui:define>  
   </ui:composition>  
 </html>  


Let us update our HelloBean.java to contain two new methods, which return the above pages by name.
Like this:
 package org.confucius;  
 import javax.faces.bean.ManagedBean;  
 import javax.faces.bean.SessionScoped;  
 @ManagedBean(name="helloBean")  
 @SessionScoped  
 public class HelloBean {  
      private String greeting;  
      public HelloBean(){  
           this.greeting = "Hello World JSF!";  
      }  
      public String getGreeting() {  
           return this.greeting;  
      }  
      public void setGreeting(String greeting) {  
           this.greeting = greeting;  
      }  
      public String getInternationalGreets() {  
           return "international_greets";  
      }  
      public String getAmericanGreets() {  
           return "american_greets";  
      }  
 }  

 Now, let us update out greet.xhtml to contain two buttons, which call the above methods.
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
 <html xmlns="http://www.w3.org/1999/xhtml"  
      xmlns:h="http://java.sun.com/jsf/html"  
      xmlns:f="http://java.sun.com/jsf/core"  
      xmlns:ui="http://java.sun.com/jsf/facelets"  
      xmlns:rich="http://richfaces.org/rich">  
       <ui:composition template="/templates/template.xhtml">  
           <ui:define name="title">JSF</ui:define>  
           <ui:define name="content">  
                <h1>#{helloBean.greeting}</h1>  
                <h:form>  
                     <h:commandButton value="Show International Greets" type="submit" action="#{helloBean.getInternationalGreets}" />  
                     <h:commandButton value="Show American Greets" type="submit" action="#{helloBean.getAmericanGreets}" />  
                </h:form>  
           </ui:define>  
   </ui:composition>  
 </html>  

Note that the Buttons have to be enclosed in a Form, otherwise they won't take effect.
This is a very common source of bugs!

If you rebuild and redeploy HelloWorldJSF, you will see the new buttons, which, when clicked direct you to the new pages.

JSF automatically assumes that the return values of the methods are names of pages, extension (.faces) is not required

Important Note:
Sometimes we use the full method name in the EL, like #{helloBean.getAmericanGreets}, while other times we leave out the 'get' part, like #{helloBean.greeting}. Why?

This is because when specified as an action, EL looks for a method with the exact name. When used outside an action specification, EL assumes it is a property field of the bean, and looks for the 'get' method.

Wednesday, May 23, 2012

JSF - Richfaces

Let us use a Richfaces component - Collapsible Panel to create some "special effects" in our UI.

Update your template.xhtml to envelope the content inside a Collapsible Panel, like this:
 <!DOCTYPE html>  
 <html xmlns="http://www.w3.org/1999/xhtml"  
      xmlns:h="http://java.sun.com/jsf/html"  
      xmlns:f="http://java.sun.com/jsf/core"  
      xmlns:ui="http://java.sun.com/jsf/facelets"  
      xmlns:rich="http://richfaces.org/rich">  
   
      <h:head>  
           <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
           <title><ui:insert name="title">Default Title</ui:insert></title>  
      </h:head>  
   
      <h:body>  
           <h3>Basic Java Series</h3>  
           <rich:collapsiblePanel header="RichFaces Greeter" switchType="client">  
                <ui:insert name="content">Default content</ui:insert>  
           </rich:collapsiblePanel>       
           <p>Visit us at www.projectconfucius.org</p>  
      </h:body>  
 </html>  
   

Notice that we are including the richfaces tag library.

The "switchType" attribute specifies that the collapsibility should be managed in the browser, with no AJAX calls to the server. This makes the client respond faster, and the "View State" of the component is saved on the client side.

Let us also update our web.xml to choose a "skin" for richfaces - this customizes the look-and-feel of Richfaces components.

Your web.xml will not look like this:
 <?xml version="1.0" encoding="UTF-8"?>  
 <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
   
   <context-param>  
     <param-name>org.richfaces.skin</param-name>  
     <param-value>blueSky</param-value>  
   </context-param>    
   
   <servlet>  
     <servlet-name>Faces Servlet</servlet-name>  
     <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>  
     <load-on-startup>1</load-on-startup>  
   </servlet>  
   
   <servlet-mapping>  
     <servlet-name>Faces Servlet</servlet-name>  
     <url-pattern>*.faces</url-pattern>  
   </servlet-mapping>  
   
   <welcome-file-list>  
     <welcome-file>greet.faces</welcome-file>  
   </welcome-file-list>  
   
 </web-app>  
   

If you rebuild and redeploy HelloWorldJSF, you will see  Richfaces Collapsible Panel, with a sky blue header, which collapses if you click on it.

JSF - Facelets

Facelets is a 'templating' technology for JSF - it allows us to:
  • Write XHTML files
  • Use JSF EL expressions to call methods on JSF Beans
  • Divide and Rule - compose pages from smaller XHTML pages
  • Use JSF Rich components 
We already saw the first two, now lets see how to compose pages from smaller XHTML pages.

This feature is very similar to Apache Tiles framework that we saw earlier in this post.

Let us suppose that we will need to create several pages with the same layout, but different content.

In your /src/main/webapp folder, create a folder 'template'

In /src/main/wepapp/template, create a file template.xhtml, like this:
 <!DOCTYPE html>  
 <html xmlns="http://www.w3.org/1999/xhtml"  
      xmlns:h="http://java.sun.com/jsf/html"  
      xmlns:f="http://java.sun.com/jsf/core"  
      xmlns:ui="http://java.sun.com/jsf/facelets">  
   
      <h:head>  
           <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
           <title><ui:insert name="title">Default Title</ui:insert></title>  
      </h:head>  
   
      <h:body>  
           <h3>Basic Java Series</h3>  
           <ui:insert name="content">Default content</ui:insert>  
           <p>Visit us at www.projectconfucius.org</p>  
      </h:body>  
 </html>  
   

Notice that we have included the facelets tag library, under the name space 'ui'.

All our pages can use this template which automatically generates a header ("Basic Java Series") and footer ("Visit us..").

Each page can define its own title and content. We use the ui:insert tag to specify points at which a child XHTML page can insert its own content.

Let us update greet.xhtml to use this template, like this:
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
 <html xmlns="http://www.w3.org/1999/xhtml"  
      xmlns:h="http://java.sun.com/jsf/html"  
      xmlns:f="http://java.sun.com/jsf/core"  
      xmlns:ui="http://java.sun.com/jsf/facelets">  
   
       <ui:composition template="/templates/template.xhtml">  
   
           <ui:define name="title">JSF</ui:define>  
   
           <ui:define name="content">  
                <h1>#{helloBean.greeting}</h1>  
           </ui:define>  
   
   </ui:composition>  
 </html>  

We are using the ui:define tag to insert a title and content into the template.

If you now build and deploy HelloWorldJSF, and point your browser to:
http://localhost:8080/HelloWorldJSF/

you will see "Hello World, JSF!"  printed between the header and footer.
Notice also that the page title is now "JSF".

JSF - Bean Declaration

JSF allows you to declare your class as a Bean, then call its methods from the XHTML.

Under /src/main, create a Source Folder called 'java'
(R-click on /src/main, select New-->Other, then select Java-->Source Folder)

In /src/main/java, create a class HelloBean.java in a package org.confucius
(R-click on /src/main/java, select New-->Other, then select Java-->Class)

The class looks like this:
 package org.confucius;  
   
 import javax.faces.bean.ManagedBean;  
 import javax.faces.bean.SessionScoped;  
   
 @ManagedBean(name="helloBean")  
 @SessionScoped  
 public class HelloBean {  
      private String greeting;  
   
      public HelloBean(){  
           this.greeting = "Hello World JSF!";  
      }  
        
      public String getGreeting() {  
           return this.greeting;  
      }  
   
      public void setGreeting(String greeting) {  
           this.greeting = greeting;  
      }  
 }  
   

Note the annotations that declare this class to be a JSF Bean named "helloBean".

We will describe annotations in detail in an upcoming post. For now, note that annotations are like inline-configurations. Any framework can define its unique set of annotations. For the Java compiler, the annotations are like comments - it more or less ignores them. But it lets the framework know of the annotations and the framework can take whatever action it needs to take. In this case, JSF framework will look at the annotations and create a bean with the name 'helloBean' and make it session-scoped.


This bean is Session-scoped which means that its state will be maintained for the duration of the HTTP session.

We can now access the methods of this Bean from our XHTMLs.

Update greet.xhtml like this:
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
 <html xmlns="http://www.w3.org/1999/xhtml"  
      xmlns:h="http://java.sun.com/jsf/html"  
      xmlns:f="http://java.sun.com/jsf/core">  
   
   <h:body>  
           <h1>#{helloBean.greeting}</h1>  
      </h:body>  
 </html>  

This style of using #{expression} for calling a Bean's method is called JSF EL (Expression Language).
Facelets view handler will do the needful to convert the EL expression to appropriate content. 

If you rebuild and deploy HelloWorldJSF and point your browser to:
http://localhost:8080/HelloWorldJSF/

You will see "Hello World, JSF!" displayed.

JSF Hello World - Setup

Let us setup a JSF project using Maven.

Note that there are several open source projects which make JSF component libraries - like Trinidad, Tobago, Tomahawk, Openfaces, IceFaces.

In this project we will use JBoss Richfaces, which is one of the most popular ones and has a pretty big set of components.

In Eclipse, go to File --> New Project --> Maven Project

Use the maven-archetype-webapp

Specify:
Group Id: org.confucius
Artfact Id: HelloWorldJSF
Package: org.confucius

Once the project is created, we will update the pom.xml to include all the necessary JSF and Richfaces libraries.

So your pom.xml will now look like this:
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
       <modelVersion>4.0.0</modelVersion>  
       <groupId>org.confucius</groupId>  
       <artifactId>HelloWorldJSF</artifactId>  
       <packaging>war</packaging>  
       <version>0.0.1-SNAPSHOT</version>  
          
   <build>  
     <finalName>HelloWorldJSF</finalName>  
   </build>  
   
        <dependencyManagement>  
     <dependencies>  
       <dependency>  
         <groupId>org.richfaces</groupId>  
         <artifactId>richfaces-bom</artifactId>  
         <version>4.2.2.Final</version>  
         <scope>import</scope>  
         <type>pom</type>  
       </dependency>  
     </dependencies>  
   </dependencyManagement>  
   
   <dependencies>  
     <dependency>  
       <groupId>org.richfaces.ui</groupId>  
       <artifactId>richfaces-components-ui</artifactId>  
     </dependency>  
     <dependency>  
       <groupId>org.richfaces.core</groupId>  
       <artifactId>richfaces-core-impl</artifactId>  
     </dependency>  
     <dependency>  
       <groupId>javax.faces</groupId>  
       <artifactId>javax.faces-api</artifactId>  
       <scope>provided</scope>  
     </dependency>  
     <dependency>  
       <groupId>org.glassfish</groupId>  
       <artifactId>javax.faces</artifactId>  
       <scope>compile</scope>  
     </dependency>  
     <dependency>  
       <groupId>javax.servlet</groupId>  
       <artifactId>javax.servlet-api</artifactId>  
       <scope>provided</scope>  
     </dependency>  
     <dependency>  
       <groupId>javax.servlet.jsp</groupId>  
       <artifactId>jsp-api</artifactId>  
       <scope>provided</scope>  
     </dependency>  
     <dependency>  
       <groupId>javax.el</groupId>  
       <artifactId>el-api</artifactId>  
       <scope>provided</scope>  
     </dependency>  
     <dependency>  
       <groupId>javax.servlet.jsp.jstl</groupId>  
       <artifactId>jstl-api</artifactId>  
     </dependency>     
     <dependency>  
       <groupId>net.sf.ehcache</groupId>  
       <artifactId>ehcache</artifactId>  
     </dependency>  
   </dependencies>  
    
 </project> 

Notice that we are using a BOM (Bill of Materials), which is a Maven construct for projects that are version sensitive. BOMs specify the versions of its dependencies.

Explanation:
A specific version of RichFaces requires certain specific version of its dependencies. Mismatch in dependency versions can cause issues. For this reason, Richfaces defines a BOM which defines the versions of its dependencies. Therefore, in our POM, we do not need to specify the dependency versions.

Next, we need to update our web.xml to use JSF.

Your web.xml will now look like this:
 <?xml version="1.0" encoding="UTF-8"?>  
 <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
   
   <servlet>  
     <servlet-name>Faces Servlet</servlet-name>  
     <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>  
     <load-on-startup>1</load-on-startup>  
   </servlet>  
   
   <servlet-mapping>  
     <servlet-name>Faces Servlet</servlet-name>  
     <url-pattern>*.faces</url-pattern>  
   </servlet-mapping>  
   
   <welcome-file-list>  
     <welcome-file>greet.faces</welcome-file>  
   </welcome-file-list>  
   
 </web-app>  
   

We direct all URLs which end in *.faces to be handled by JSF servlet.

Also, note that we have defined greet.faces as our welcome file.

However, we will never create a file called greet.faces - we will create one called greet.xhtml.

Whenever JSF sees a request for a file called foo.faces, it actually picks up foo.xhtml, sends it to the Facelets view handler which renders foo.html, which is sent back to the browser.

In your /src/main/webapp folder, create a file greet.xhtml, like this:
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
 <html xmlns="http://www.w3.org/1999/xhtml"  
      xmlns:h="http://java.sun.com/jsf/html"  
      xmlns:f="http://java.sun.com/jsf/core">  
   
   <h:body>  
           <h1>Hello World!</h1>  
      </h:body>  
 </html>  

Note that an XHTML file looks just like a HTML file.

Note also that we have included two JSF tag libraries - HTML and Core. These tag libraries gives enhanced functionality over regular HTML tags.

Our JSF project is now setup.

If you build and deploy the project, and browse to
http://localhost:8080/HelloWorldJSF/

You will see "Hello World!" displayed.

JSF - Java Server Faces

JSF, a Sun standard View Technology., solves the Rich UI problem in the following ways:

1. JSF separates the "Rich component" developers from UI developers.

The Rich component developers deal with all the javascript and make the components cross-browser compatible. They provide a custom tag library which allows UI developers to use the components.

2. JSF provides a templating technology called Facelets.

Facelets files are .xhtml files which look just like regular HTML files. UI developers can use the custom tags provided by the Rich component developers to put components in their pages.

At run time, Facelets renders the final HTML page which is seen on the browser, replacing the custom tags with appropriate HTML tags and java scripts (as specified by the Rich component developers).

3. JSF provides a Bean container, so that any Java class on the server can be declared to be a JSF bean. And a rich component can call methods on the JSF Bean.

Internally, JSF generates all the necessary AJAX calls to make the communication between browser and server possible.

4. JSF allows page navigation to be declared in an XML file (faces-config.xml)

At run time, JSF will read the navigation file and display the appropriate pages to the user.

5. JSF maintains the state of the Beans and also of the View.

No effort is needed on part of the application developer.

View Technologies & Rich User Interfaces

The original Web UI was envisioned as hypertext, cross referencing, static web pages (sometimes called Web 1.0).

But things quickly progressed beyond that to give highly interactive, dynamically generated web pages with cool animation effects (sometimes called Web 2.0).

The technology which enabled this transition is javascript, which was a simple scripting language originally developed for small dynamic web page modifications, but people pushed it to its limits and beyond.

Such web interfaces are often called "Rich UI" and "Rich Application" because they display all kinds of special effects like collapsible Window Panels, Drag-n-Drop lists, interactive Charts, Dynamic Trees, Color themes, etc.

The components which display such complex dynamic effects are called "Rich components", and sometimes "Widgets".

Developing a Rich UI comes with a new set of challenges:

1. Developing complex javascript is not easy. It requires a lot of experience, it is not easy to debug and can result in unexpected behaviors in different browsers.

2. Rich components typically need to use AJAX to communicate with servers, which makes things more tricky.

3. In addition to application state, there is an additional need to maintain state of the Rich components (sometimes called View state)

4. There is always the browser "back" button which messes the view.

5. Finding an easy, seamless way for rich components to interact smoothly with Java objects on the application server is not trivial.

6. In the absence of ordinary hyperlinks, defining navigation between pages becomes a job in itself.

All these challenges led to the development of new frameworks for developing the front-end. These are often called "View Technologies".


In the coming posts, we will look at 3 of the most prominent view technologies:

 * JSF - Java Server Faces, is a Sun standard, and more widely used.

* Apache Tapestry, is the easiest to use and more elegant than JSF.

* GWT - Google Web Toolkit, is the most scalable.

Monday, April 16, 2012

Connection pools

One of the oft-heard terms in Java is "Connection pool".

This is a very simple idea which is at times blown out of proportion.

Whenever you make a HTTP request to a web application, you need to open a TCP connection. After you are done, you need to close the connection.

Suppose you make several requests to the server, it is not very efficient to open and close connections each and every time.

Better to open a connection and leave it open for the duration of the requests. That way you can send all requests on the same connection, saving yourself significant overhead.

Now, pushing this idea further, why not open several connections to the server and keep them ready. Now you can send multiple requests to the server simultaneously.

This is a connection pool.

The idea is simple as that. But not without its quirks.

First, how do you know when to close the connections. Leaving a pool of connections open for eternity is not smart and consumes resources. How can you tell when the "last" request has been fulfilled?

Second, how many connections should be in the pool? 5 or 10 or 1000? This is called pool size.

Worse problems surface very soon. What if a connection has been idle for a long time and TCP has timed out and closed it? This leaves dead connections in the pool.

Even more challenging - what if you have 10 connections in the pool and a 11th request is received? Should you queue the request? How many requests should be queued??

It is all these questions which have no easy answer which make connection pools easy to understand, but hard to configure.

Eventually, all connection pool implementations come with several configuration parameters like pool size, idle timeout, queuing policy, connection validation, etc.

What makes things worse is that there are usually several queues involved in a typical web application infrastructure - connection pool maintained by hibernate, another pool maintained by web server, yet another from app server to databases, etc.

Mismatches between their configuration means you really have no idea what is going on under the hood!

Monday, April 9, 2012

Form Validation

Besides internationalization, the other top functionality needed by web applications is form validation (or user input validation).

Java does not provide any standard interface to do this, so it is mostly left to the application developer.

There are primarily two ways to do form validation - on the client side using javascript, or on the server side using java.

The first is faster, while the second is easier (it is usually easier to write code and debug in Java than in javascript).

In the coming posts we will see several front end frameworks like Tapestry, JSF and GWT, which provide facilities for input validation, amongst other things.

ResourceBundle and i18n

i18n = internationalization (there are 18 characters between i and n!)

When you need your application to be internationalized, you want all messages displayed to the user to be in the language of their locale.

Java has a class called java.util.ResourceBundle which helps you do this.

You can create property files with extensions which correspond to various locales.

For example, I can have greetings_en_US.properties and greetings_fr_CA.properties.
The first contains greetings to be displayed to english users from US. The second is for french users from Canada.

Inside the first, I will have a key-value pair like:
greet="Hello World!"

In the second, I wil have:
greet="Bonjour"

In my application, I will have the code:
 ResourceBundle res = ResourceBundle.getBundle("greetings");  
String greetStr = res.getString("greet");


Java's ResourceBundle class automatically picks the correct property file based on the current locale. If it is a HTTP request, the browser will send the locale of the user, and that will determine which property file will be picked up.

Property files which are designed to be used by ResourceBundle class are themselves called "resource bundles".

Let us modify our project from the previous post to use resource bundles.

In the /src/main/resources folder, create two files:
greetings_en_US.properties and greetings_fr_CA.properties

In the first, type:
greet="Hello World!"

In the second, type:
greet="Bonjour"

Now update your index.jsp to:
 <html>  
<head>
<%@ page import="java.util.ResourceBundle" %>
</head>
<body>
<% ResourceBundle res = ResourceBundle.getBundle("greetings"); %>
<h2><%= res.getString("greet")%></h2>
</body>
</html>



R-click on the project in Eclipse navigator and select Run As-->Maven install.
I am assuming you are using the cargo plugin to deploy the war, as described in this post.

Then point your browser to:
http://localhost:8080/HelloWorldWARArch/

You will see "Hello World!" if you are in the US.

Now, let us force our code to change locale.

Change your index.jsp to:
 <html>  
<head>
<%@ page import="java.util.ResourceBundle" %>
<%@ page import="java.util.Locale" %>
</head>
<body>
<% ResourceBundle res = ResourceBundle.getBundle("greetings",new Locale("fr","CA")); %>
<h2><%= res.getString("greet")%></h2>
</body>
</html>



Now if you build and deploy your application, you will see "Bonjour!"

You can have as many resource bundles as you want to reflect different locales.

If a resource bundle for a given locale is not found, the default resource bundle (i.e. the one which has no locale specification - greetings.properties) will be used.

Sunday, April 1, 2012

Maven - profiles

With a ordinary pom.xml, the exact exact same plugins and goals are executed no matter which environment the build is run in.

Ordinarily, this is exactly what you want. That the build steps are the same no matter who runs the build and where.

But there are times when different environments need slightly different builds.

For example, we may want to run the cargo plugin only in our local build.

In our production build, we would not want to automatically deploy to the server.

We do this by creating Profiles.

A profile, in effect, is nothing but a name for section of the build.

Different sections of the build can be enclosed in different profiles.

Any build section enclosed in a profile will be executed only when that profile is active.

For example, let us enclose our cargo plugin in a profile, like this:
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>org.confucius</groupId>
<artifactId>HelloWorldWARArch</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Webapp demonstrating cargo plugin</name>
<url>http://www.confucius.org</url>

<pluginRepositories>
<pluginRepository>
<id>codehaus-releases</id>
<url>http://nexus.codehaus.org/releases/</url>
</pluginRepository>
</pluginRepositories>

<profiles>
<profile>
<id>local-profile</id>

<build>
<finalName>HelloWorldWARArch</finalName>
<plugins>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.2.0</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>undeploy</goal>
<goal>deploy</goal>
</goals>
</execution>
</executions>
<configuration>
<container>
<containerId>tomcat7x</containerId>
<type>remote</type>
</container>
<deployer>
<type>remote</type>
<deployables>
<deployable>
<groupId>org.confucius</groupId>
<artifactId>HelloWorldWARArch</artifactId>
<type>war</type>
</deployable>
</deployables>
</deployer>
<configuration>
<type>runtime</type>
<properties>
<cargo.server.settings>localhost</cargo.server.settings>
</properties>
</configuration>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

We have defined a profile "local-profile" and enclosed the cargo plugin in it.

Our cargo plugin will be executed only when the local-profile is active.

By default, profiles are inactive.

Update your /src/main/java/webapp/index.jsp, like this:
 <html>  
<body>
<h2>Hello World v4!</h2>
</body>
</html>


R-click on HelloWorldWARArch project and select Run As-->Maven install.

If you look at the messages in the console, you will see that the cargo plugin was not executed.

If you point your browser to:
http://localhost:8080/HelloWorldWARArch/

you will see "Hello World v3!", further proof that the cargo plugin did not execute.

How to activate the profile?

There are several ways to activate profiles.

We will activate the profile from our settings.xml, like this:
 <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<usePluginRegistry/>
<offline/>
<pluginGroups/>
<servers>
<server>
<id>localhost</id>
<configuration>
<cargo.tomcat.manager.url>http://localhost:8080/manager</cargo.tomcat.manager.url>
<cargo.remote.username>admin</cargo.remote.username>
<cargo.remote.password>s3cret</cargo.remote.password>
</configuration>
</server>
</servers>
<mirrors/>
<proxies/>
<profiles/>
<activeProfiles>
<activeProfile>local-profile</activeProfile>
</activeProfiles>
</settings>

Now if you run Maven install, you will see the cargo plugin execute.

Refresh your browser, and you will see:
"HelloWorld v4!"

You can create different profiles for different environments (development/testing/production) and execute the correct build for each environment.

Maven - settings.xml

While pom.xml is the configuration for a specific Maven project, settings.xml is the configuration for Maven itself.

The default settings.xml is located in the <maven_home>/conf

It looks like this (after removing the comments):
 <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<usePluginRegistry/>
<offline/>
<pluginGroups/>
<servers/>
<mirrors/>
<proxies/>
<profiles/>
<activeProfiles/>
</settings>


Anything you specify in the settings.xml applies to all Maven projects.

As you can see, the default settings.xml does not specify anything.

But if you were to update it by specifying servers, proxies, mirrors, repositories, etc - it would be picked up by all maven projects.

If you update the settings.xml in <maven_home>/conf, then all users of maven will be affected by your changes.

A better way to do things is to create a settings.xml in your <home directory>/.m2. If you do this, Maven merges your settings.xml with the settings.xml in <maven_home>/conf. Your settings taking precedence.

I will not describe each and every setting in settings.xml, but just show one as an example.

In our previous post, we put the username and password to Tomcat in the pom.xml.
This is not a good idea because the pom.xml gets distributed with the project and it will expose your credentials.

So we will specify our server credentials in settings.xml, which stays in our home directory.

In your <home directory>/.m2, create a settings.xml file, like this:
 <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<usePluginRegistry/>
<offline/>
<pluginGroups/>
<servers>
<server>
<id>localhost</id>
<configuration>
<cargo.tomcat.manager.url>http://localhost:8080/manager</cargo.tomcat.manager.url>
<cargo.remote.username>admin</cargo.remote.username>
<cargo.remote.password>s3cret</cargo.remote.password>
</configuration>
</server>
</servers>
<mirrors/>
<proxies/>
<profiles/>
<activeProfiles/>
</settings>

Here we have specified a server called "localhost" and given it the url and credentials of our local tomcat server.

Now update your pom.xml to use the server in the settings.xml, like this:
(we have updated the properties in the bottom section of pom.xml)
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>org.confucius</groupId>
<artifactId>HelloWorldWARArch</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Webapp demonstrating cargo plugin</name>
<url>http://www.confucius.org</url>

<pluginRepositories>
<pluginRepository>
<id>codehaus-releases</id>
<url>http://nexus.codehaus.org/releases/</url>
</pluginRepository>
</pluginRepositories>

<build>
<finalName>HelloWorldWARArch</finalName>
<plugins>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.2.0</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>undeploy</goal>
<goal>deploy</goal>
</goals>
</execution>
</executions>
<configuration>
<container>
<containerId>tomcat7x</containerId>
<type>remote</type>
</container>
<deployer>
<type>remote</type>
<deployables>
<deployable>
<groupId>org.confucius</groupId>
<artifactId>HelloWorldWARArch</artifactId>
<type>war</type>
</deployable>
</deployables>
</deployer>
<configuration>
<type>runtime</type>
<properties>
<cargo.server.settings>localhost</cargo.server.settings>
</properties>
</configuration>
</configuration>
</plugin>
</plugins>
</build>
</project>

Update your /src/main/webapp/index.jsp, like this:
 <html>  
<body>
<h2>Hello World v3!</h2>
</body>
</html>


In your Eclipse Navigatory, R-click on HelloWorldWARArch project and select Run As-->Maven install

Now if you point your browser to:
http://localhost:8080/HelloWorldWARArch/

you will see "Hello World v3!"

This shows that the pom.xml picked up the server settings from settings.xml

You can now safely distribute this project without exposing the server credentials.

Also, you do not need to specify the credentials in each and every project. All projects will pick up the configuration from settings.xml.