Monday, January 18, 2010

Comparison of Tapestry vs Wicket

This study was a part of graduate project done by the students of MIT Engineering College, Pune. The aim of the project was to compare the two web frameworks Tapestry and wicket and look into some of the components support. The team memebers in alphabetical order are:
Tapestry Team: Darshana Patil, Pradnya Mankar, Sheetal More
Wicket Team: Lotika Rao, Priyanka Ratnappagol, Rashi Singh, Shreya Sharma
The versions used for comparison are Tapestry 5.0.14 and Wicket 1.4-rc1
Wicket and Tapestry are two popular component based framework for making web applications. Component based framework are the next generation to the MVC based framework like Struts and Spring MVC. In this post, we will compare some of the features of both the framework.
Wicket is easier than Tapestry in terms of learning. Also documentation available on internet related to Wicket is quite sufficient to develop a web application more easily. In case of Tapestry it is quite difficult initially but once you gain mastery in Tapestry you can develop a web application as easy as in Wicket. Tapestry is very productive once you learn it.
The versions of frameworks for this study are as follows:
  • Tapestry 5.0.14
  • Wicket 1.4-rc1
Ease of learning
      Tapestry has steep learning curve while Wicket has easy learning curve. Wicket has lots of documentation but less ordered. Tapestry has less documentation but more ordered. Tapestry’s site released by Apache is quite sufficient in that regard.
!!!Support for components
Listing
 
Tapestry
  • Tapestry provides support for Listing.
  • Listing is implemented using Grid component of Tapestry5  (Grid)
  • A grid presents tabular data. It is a composite component, created in terms of several sub-components. The sub-components are statically wired to the Grid, as it provides access to the data and other models that they need. A Grid may operate inside a Form.
Implementation in Tapestsry
     List is implemented using Grid component. To display a list of students with pagination.
<t:grid source="students" rowsPerPage="5" pagerPosition="bottom" />
NameTypeFlagDescription
sourceSource of DataRequired, NOT NullThe source of data for the Grid to display. This will usually be a List or array but can also be an explicit GridDataSource. For Lists and object arrays, GridDataSource is created automatically as a wrapper around the underlying List.
rowsPerPageIntNOT NullThe number of rows of data displayed on each page. If there are more rows than will fit, the Grid will divide up the rows into "pages" and provide a pager to allow the user to navigate within the overall result set. (default: 25)
pagerPositionGridPagerPositionNOT Allow NullDefines where the pager (default : “top”) should be displayed: "top", "bottom", "both" or "none".
Depending on the ‘source’ specified an appropriate method from the corresponding java file will get called.
public List<Student> getStudents()
{
   //Retrieve list of students
   //………………
}
     
Additional Functionality:
  • Sorting : The Grid component shows list but additionally it also provides Sorting in ascending or descending order on any of the fields of the list shown. That eases developer’s work for handling sorting function on various fields.
  • Pagination is made very easy using Grid component by adding just one parameter i.e. rowsPerPage = number of rows to be displayed.
 Wicket
  • Wicket supports listing by providing repeater ListView
  • ListView uses ListItem as a container to hold items of ListView
Implementation
For listing purpose ListView and ListItems are used with the help of some markup. For example to display a list of User
userListView = new ListView("userlist", userList)
{
   public void populateItem(final ListItem listItem)
   {
      //…
    listItem.add(new Label("name", student.getName()));
     //..
    }
};
ListItem is a container created for every list item in the list that feeds the listview. Then method populateItem(ListItem) comes in, it populates given item. It is called once for every listitem created and allows you to add components to it, so the listview render process looks like this:
Before each render:
  • Clear all children.
  • For every list item in the list.
  • Create a ListItem webmarkupcontainer.
  • Add created ListItem as a child.
  • Call populateItem with the created ListItem container to allow users to populate it.
During render:
  • Render all immediate children with own markup.
ListView is a type of repeater. The markup contained within the ListView's component ID is repeated for each object passed in through the model. Here's the markup for our ListView:
Html
<tr wicket:id = "userlist">
<td><span wicket:id = "name">1/1/2004</span></td>
<td><span wicket:id = "age">1/1/2004</span></td>
<td><span wicket:id = "email">1/1/2004</span></td>
<td><span wicket:id = "birthdate">1/1/2004</span></td>
</tr>
The span tag provides a way to add a hook to a part of a text or a part of a document. When the text is hooked in a span element you can add styles to the content, or manipulate the content with for example JavaScript. The above markup will render the values of each wicket:id attribute of every record.
List for Tapestry vs Wicket
  • Tapestry’s Grid component for listing provides sorting on all fields of the table.
  • Pagination can be easily done in Tapestry by just adding ‘rowPerPage’ parameter for the grid component. But in wicket little more coding is required for it.
  • There are no extra coding efforts needed in tapestry other than including grid component with parameters and their corresponding java files. But wicket needs explicit writing of td and tr tags of table in their markup to display items in ListView.
  • Tapestry’s grid component for listing looks better because Tapestry Grid component is more developed and provides more functionality with little coding efforts.
Calendar
Tapestry
  • Tapestry provides support for Calendar.
  • Calendar component is rendered using DateField component which used to collect a provided date from the user using a client-side JavaScript calendar. Tapestry's DateField component is a wrapper around WebFX DatePicker.
Implementation:
  • Calendar is used to enter birthdate of student. A BeanEditForm component is used for showing registration form.
  • BeanEditForm creates an entire form editing the properties of a particular bean. It generates a simple UI for editing the properties of a JavaBean, the order and validation for the properties determined from annotations on the property's getter and setter methods.
  • For each property that it can edit, BeanEditForm automatically selects a certain control. For a string or a numeric property it displays a text box, for an enumeration—a drop-down list, for a boolean property—a checkbox.
  • Similarly for a Date property, DateField component is selected by BeanEditForm.
To implement BeanEditForm component the following code is written in  .tml file
<t:beaneditform t:id="form" t:object="student"/>
      Here, student is the object to be edited. This will be read when the component renders and will be updated when the form for the component is submitted.

NameTypeFlagDescription
ObjectObjectRequired, NOT NullThe object to be edited. This will be read when the component renders and updated when the form for the component is submitted. Typically, the container will listen for a "prepare" event, in order to ensure that a non-null value is ready to be read or updated. Often, the BeanEditForm can create the object as. The object property defaults to a property with the same name as the component id.
Wicket
Wicket does not provide any component for calendar. Third party component should be used in order to include calendar in Wicketapplications.
Implementation :
To implement  calendar component Yahoo calendar component is used. Yahoo calendar component includes some javascript files
TextField birthdate = new DateTextField("date",
                                         new PropertyModel(student, "date"));
//id - The id of the text field 
//object - The model
//Returns: A new date text field instance
DateTextfield  public DateTextField(java.lang.String id,
                                    wicket.model.IModel object)
  • Creates a new DateTextField instance to be added to this panel.
  • A TextField that is mapped to a java.util.Date object. If you provide a SimpleDateFormat pattern, it will both parse and validate the text field according to it. If you don't, it is the same as creating a TextField with java.util.Date as it's type (it will get the pattern from the user's locale)
PropertyModel
   We can create form components that work dynamically on the given model object. For instance, we could create a text field that updates the name property of a person like this:
public PropertyModel(java.lang.Object modelObject,  java.lang.String expression)
Construct with a wrapped (IModel) or unwrapped (non-IModel) object and a     property expression that works on the given model.
Parameters:
  • modelObject - The model object, which may or may not implement IModel  
Calendar for Tapestry vs Wicket
  • Tapestry has a calendar component whereas Wicket does not have calendar component.
  • Due to use of javascript, rendering of calendar in wicket is difficult compared to that in tapestry.
  • Yearly Navigation is a problem
  • Selecting date in tapestry is more user friendly than in wicket.
Chart
Tapestry vs Wicket
  • Tapestry and Wicket both do not have component for Chart.
  • For implementation of chart in both the frameworks i.e. Tapestry and Wicket JFreeChart library is used.
JFreeChart is a free chart library for the Java platform. It is designed for use in applications,applets, servlets and JSP. It can generate pie charts, bar charts (regular and stacked, with an optional 3D-effect),line charts, scatter plots, time series charts (including moving averages, high-low-open-close chartsand candlestick plots), Gantt charts, meter charts (dial, compass and thermometer), symbol charts,wind plots, combination charts and more. JFreeChart is implemented in Java itself.
Implementing JFreeChart
Download the latest version of JFreeChart. Unpack the files. For configuring JFreeChart with Eclipse IDE include JFreeChart library as an user library.
Creating charts with JFreeChart involves the following step:
  • Create the dataset which contains the data that needs to be displayed.
  • Create a JFreeChart object using ChartFactory.
  • Draw the chart.
An example to create a pie chart is as follows:
// Create the chart using ChartFactory
JFreeChart chart = ChartFactory.createPieChart
                  ("Pie Chart",
                    dataset,
                    true, // legend required
                    true, // tooltips required
                    false // URLs required
      );
Notice how we have passed a reference to the dataset to the factory method. JFreeChart keeps a reference to this dataset so that it can obtain data later on when it is drawing the chart. The chart that we have created uses default settings for most attributes. There are many ways to customise the appearance of charts created with JFreeChart, but in this example we will just accept the defaults.
Displaying the Chart
To display the chart in a frame on the screen ChartFrame is used. The ChartFrame class contains the a ChartPanel to display charts:
// create and display a frame...
ChartFrame frame = new ChartFrame("First", chart);
frame.pack();
frame.setVisible(true);
The above code will display the chart in the frame.
To save the chart as an image which can be later embedded in the webpage.
Final File file = new File("<Temp Dir. to Store Chart Image>/MyChart.png");
ChartUtilities.saveChartAsPNG(file, chart, 500, 500,null);
Chart for Tapestry vs Wicket:
  • As both the frameworks do not have chart component External libraries are used for its implementation. (Here, JFreeChart)
  • Coding efforts are the same in both frameworks for chart implementation
Validation
Tapestry
Support:
  • Tapestry provides easy to configure, robust validation on the client side & provides good out of the box messages and allows us to easily customize them.
  • Every form component has a ValidationTracker object associated with it. It is provided automatically, we do not need to care about it. Basically, ValidationTracker is the place where any validation problems, if they happen, are recorded.
  • As soon as a validator decides that the value entered associated with the component is not valid, it records an error in the ValidationTracker automatically.
  • If there are any errors recorded in ValidationTracker, Tapestry will redisplay the form, decorating the fields with erroneous input and their labels appropriately.
Implementation:
A BeanEditForm is used for taking input from user.
Student.java
public class Student
{
  //…
  @Validate("required") 
  public String getName() { return name; }
  @Validate("required,min=5,max=35")
  public Integer getAge() { return age; }
  @Validate("required,regexp")
  public String getEmail() { return email;}
}
The new @Validate annotations added to the first name and last name properties indicates that a non-blank value must be provided. Minimum & maximum values allowed for a field & regular expression for email validation is given in properties file as shown below:
myapp.properties
email-regexp=^([a-zA-Z0-9_.-])+@(([a-zA-Z0-9-])+.)+([a-zA-Z0-9]{3})+$
email-regexp-message=Email address is not valid.
age-min-message=You are too young!
age-max-message=You are too old!
Validation for each field occurs when the form is submitted, and when the user tabs out of a field. If you submit immediately, Tapestry will display popup bubbles for each field identifying the error. In addition, fields with errors are marked with a red X, the font for the first turns red, and the label for the field turns red.
Wicket
Support:
  • Wicket has a FeedbackPanel that displays the error messages captured during form validation. Actually, the FeedbackPanel will display all types of feedback message attached to the components contained within the Page.
Implementation
StudentForm.html
<html>
  <head><title>Student Form</title></head>
  <body>
     <span wicket:id="feedback"/>
     <form wicket:id="form">
        Name <input type="text" wicket:id="name"/>
        Age  <input type="text" wicket:id="age"/>
        <input type="submit" value="Submit"/>
     </form>
  </body>
</html>
The place holder for the panel is specified through the span tag with wicket:id='feedback'.
StudentForm.java
public final class StudentForm extends Form {
   private final Student student = new Student();
   public StudentForm(final String componentName, Model m) {
        super(componentName, m);
        FeedbackPanel feedback = new FeedbackPanel("feedback");
        add(feedback);
   }
}
Leave the 'Username' field blank and enter an invalid value for the 'Age' field and click on Submit. You should see something like this on the browser. This is basic server-side validation.
Validations in Tapestry vs Wicket
  • Tapestry provides both client-side and server-side validations.
  • Wicket provides only server-side validation which increases network traffic.
  • Tapestry provides client-side validations with good built-in messages. Also the messages can be customized easily as per developer’s need.
  • Tapestry validation is robust and looks better than Wicket validations.
Page Templating
Tapestry
Support
   In Tapestry we can create a Layout component that acts like a template for our pages. Layout isn't a component, it's a component pattern.
Implementation
    A Layout component exists to provide common content across all pages in your application. In traditional servlet development, you may be familiar with the use of a JSP include to include a banner across the top of your page and a copyright message across the bottom.
Layout.tml
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
   <head><title>Tapestry</title>  </head>
   <body>
      <t:body/>
   </body>
</html>
The magic is in the <t:body/> element in the center; this will be replaced by the page's content.
Layout.java
@IncludeStylesheet("context:css/site.css")
public class Layout
      { }
We can save ourselves some typing using the @IncludeStylesheet annotation to specift css instead of using <link> tag.
Start.tml
<html t:type="layout"
      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">

   <h1>Tapestry Components</h1>
        Welcome
</html>
            This is an example of using the Layout component. To keep our Start.tml template relatively previewable, we are using an <html> element and the t:type attribute to specify that it is a component. The <html> tag will be removed, and replaced with the content from the Layout.tml template. The <t:body> in Layout.tml will be replaced with the page specific content.
            Any page in the application that follows this pattern, using the Layout component, will have the same look and feel.
Wicket
Wicket provides layout templates using markup inheritance. Thanks to one of user who brought this to notice (See comment below). Please see [http://wicket.apache.org/examplemarkupinheritance.html|wicket Markup Inheritance].
Page templating for Tapestry vs Wicket
  • Tapestry provides annotation @InludeStylesheet for providing template for webpages.
  • Wicket provides StyleSheetReference for this purpose.
  • In Tapestry <t:body> tag dynamically replaces itself by page-specific content. So we don’t need to write the same HTML code that will appear on all pages. The common code will be put in Layout.tml. This reduces the amount of code in a .tml file considerably.
  • Wicket provide this functionality using markup inheritance.
Progress Bar
Tapestry
In tapestry the Progress bar is implemented as custom component.
Implementation:
  • Create a new package in src  tapestry.components. Note that the first part (in italics) should follow the same naming convention as your other packages (e.g. tapestry.pages), but the components part is compulsory.
  • Within the component package, create a new class, e.g. Pbar.java
  • After Studying the diagram on component rendering , we can select which states we need to implement as annotations.
You can now reference your Progress Bar component in every PDemo.tml as follows:
PDemo.tml
  <t:ProgressBar></t: ProgressBar >
    
ProgressBar.java
@ SetupRender
void setupRender(MarkupWriter writer)
{
    //create frame to display Progress Bar
}
@BeginRender
void beginRender(MarkupWriter writer)
{
   //Start a new Thread
    newWorker.Start();
}
private Class Worker extends Thread
{
    public void run()
    {
       //………
       x1=x1+10;
       //…………
       progressBar.setValue(x1);
      //…………
      new Worker().sleep(500);
     }
}
  • We have used beginrender and afterrender methods of component rendering for building our own custom component Progress bar.
  • In the Setuprender method a Progressbar object which will display progressbar and a Frame, on which progress bar is displayed, are created.
  • In the Beginrender method a new Thread is started in which Progressbar value is updated and displayed.
  • So, when in .tml file t:progressbar tag is encountered these methods will execute and the component is rendered
Wicket
Support:
  • Wicketstuff progressbar provides a progress bar component for wicket
  • The component can be used both for displaying just a progress bar or for showing progress of a background task. The progress of a background task is updated via AJAX.
Implementation:
  • Create a new package here, "org.wicketstuff.progressbar" and write ProgressBar.java, ProgressBar.html and Progression.java
  • The ProgressBar component uses a special model of type ProgressionModel. The current progress is encapsulated in a Progression value-object as the percentage of completion.
  • The onfinished method is executed when the progress reaches 100 or more generally if the Progression object returns true for isDone.
  • The progress bar is started to update itself with the start method and stops if the progress is done.
  • To use Progressbar as a component import the above packages and you can use Progress bar component.
Progress.java
private int progress = 0;
public SimpleProgressExamplePage() {
   final ProgressBar bar;
   add(bar = new ProgressBar("bar", new ProgressionModel() {
      protected Progression getProgression() {
         return new Progression(progress);
      }
    }) {
        protected void onfinished(AjaxRequestTarget target) {
            setVisible(false);
            target.appendJavascript("alert('Task done!')");
        }
    });
    //   ...
    form.add(new IndicatingAjaxButton("submit", form) {
    protected void onsubmit(AjaxRequestTarget target, Form form) {
        bar.start(target);
        new Thread() {
          public void run() {
             for(int i = 0; i <= 100; i++) {
               try {
                   Thread.sleep(200);
                } catch (InterruptedException e) { }
                progress = i;
        }
     }}.start();
   }
});
   //    ...
}
On the markup side, just use a div element for the progress bar:
Progress.html
<div wicket:id="bar">[Progress]</div>
Custom component for Tapestry and Wicket
  • Tapestry is specifically designed to make creating new components very easy, as this is a routine approach when building applications, creating components is as easy as creating pages.
  • Wicket also provides ways to create custom components.
  • Creation of custom component in Tapestry needs to be completely aware of page rendering phases. Only after understanding rendering methods completely, one can go ahead with custom component in Tapestry.
  • Tapestry provides clear separation between customized components since they are put in yourpackage.components
  • Custom components can be reused in both the frameworks by just importing respective packages where component is created
  • Both frameworks have their own style of creating custom components with ease.
AJAX
Tapestry Support:
  • Tapestry supports Ajax
  • The benefit of Tapestry AJAX components is that you can use AJAX without any knowledge of JavaScript whatsoever. Components encapsulate everything required for their work, and you only need to configure their required bindings.
  • Autocomplete Mixin (org.apache.tapestry5.corelib.mixins.Autocomplete) - The Autocomplete mixin exists to allow a text field to query the server for completions for a partially entered phrase. It is often used in situations where the field exists to select a single value from a large set, too large to succesfully download to the client as a drop down list.
Implementation:
  • Autocompleter has the same two required bindings, model and value, and its model is an implementation of a special interface with a few methods for us to implement
  • When the user types into the field, the client-side JavaScript will send a request to the server to get completions.
  • You must write an event handler to provide these completions. The name of the event is "providecompletions". The context is the partial input value, and the return value will be converted into the selections for the user.
Ajax.tml
<input t:id="Name" t:type="TextField" t:mixins="autocomplete"/>
    
Ajax.java
List<String> onProvideCompletionsFromName(String partial)
{
   StudentQuery s = new StudentQuery();
   List<String> stud_ajax = null;
   stud_ajax = s.searchAjax(partial);
   return stud_ajax;
}
StudentQuery.java
public List<String> searchAjax(String name)
{
   //……
   List<String> matches = new ArrayList<String>();
   matches.add(sname);
   return matches;
}
  • You can return an object array, a list, even a single object. You may return objects instead of strings ... and toString() will be used to convert them into client-side strings.
  • Tapestry's default stylesheet includes entries for controlling the look of the floating popup of selections.
  • You may override DIV.t-autocomplete-menu UL to change the main look and feel, DIV.t-autocomplete-menu LI for a normal item in the popup list, and DIV.t-autocomplete-menu LI.selected for the element under the cursor (or selecting using the arrow keys).
Wicket Support:
  • Wicket supports various ajax components. One if them is AutoCompleteTextField. (wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteTextField)
  • The AutocompleteTextField is an extention of the normal Wicket text field with some additional javascript and css output added.
  • The ajax textfield is added on form. Locales is used, It gives the country names
Implementation
   AutoCompleteTextField provides methd getChoices which retrieves data.
Callback method that should return an iterator over all possible assist choice objects. These objects will be passed to the renderer to generate output. Usually it is enough to return an iterator over strings.
Parameters: getChoices(java.lang.String input)
            input - current input
Returns: protected abstract java.util.Iterator
         iterator for all possible choice objects
AjaxFormSubmitBehavior()
    Ajax event behavior that submits a form via ajax when the event it is attached to is invoked. The form must have an id attribute in the markup or have MarkupIdSetter added.
It uses the following constructor:
public AjaxFormSubmitBehavior(Form form, java.lang.String event)
  Construct.
  Parameters: form - form that will be submitted
  event - javascript event this behavior is attached to, like onclick, onchange
AutoComplete.html
Country: <input type="text" wicket:id="auto" size="20"/>
AutoComplete.java
protected Iterator getChoices(String input)
{
    //…………
    return choices.iterator();
}
...
 field.add(new AjaxFormSubmitBehavior(form, "onchange")
{
     protected void onsubmit(AjaxRequestTarget target)
     {
         target.addComponent(label);
      }
     @Override
     protected void on<x>error(AjaxRequestTarget target)
     {  }
});
         
Autocomplete for Tapestry vs Wicket
  • Tapestry Provides a mixin called autocomplete whereas Wicket provides a specializes textfield for the same.
  • Tapestry Provides default and attractive look and feel to the autocomplete component which can be overridden.
  •  Mixin concept of Tapestry is little difficult to understand compared to Wicket’s Autocomplete Textfield.
  • In Tapestry there is no specialized ajax support for textfield or in other word for input elements.
  • Efforts required for Ajax from coding perspective in both frameworks i.e. Tapestry and Wicket are nearly same.
  • Both the frameworks provide without writing any javascript.
  • As long as AJAX support is concerned Wicket provides more components compared to Tapestry.
Conclusion
  • Tapestry and Wicket are completely a component-centric Java web-framework which provides various components to develop web applications.
  • Tapestry requires java files and tapestry markup language files and does not require any XML configuration except web.xml file. It also requires use of annotations on a larger extent.
  • Tapestry provides AJAX support without the knowledge of javascript, easy custom component creation, good validation and templating support, but does not provide any component for chart.
  • Tapestry does not provide any backward compatibility. Its new version is completely a rewrite. The learning curve of Tapestry is steep and there is minimal documentation available on this framework.
  • Wicket with java files and markup files requires an application file. It also requires no XML configuration except web.xml file. Wicket needs to register the HTML elements like label, panel etc. Wicket’s AJAX support is more developed than that of Tapestry, also allows custom component creation, but it does not provide any client side validation. Validations need to be done in Java. Documentation of Wicket is more compared to Tapestry, and also wicket has backward compatibility so the developer need not study the framework from scratch with every new version of the framework
  • Tapestry and Wicket both can be used for web application development by learning its pros and cons over one another and best suitable framework can be chosen according to requirements

No comments:

Post a Comment