`

Tapestry and Wicket compared

 
阅读更多
 

Tapestry and Wicket compared

Need to create Web applications quickly? Give these two component frameworks a look

Artem Papkov (artem@us.ibm.com), Solution Architect, IBM 
Jim Smith (jamessmi@us.ibm.com), Manager, IBM 
Ilya Kanonirov (kio@isg.axmor.com), Software Engineer, Axmor

 

Summary:  JSF and Struts are the traditional component frameworks developers turn to for Web development. You have an alternative, however: Tapestry and Wicket are component-oriented Web frameworks designed to create Web applications. A simple example application implementing a to-do list workflow is developed here, using Tapestry and Wicket technologies.

Date:  08 Apr 2008 
Level:  Intermediate 
Also available in:   Japanese 

Activity:  28741 views 
Comments:   0 (View | Add comment - Sign in)

Average rating 4 stars based on 50 votes Average rating (50 votes)
Rate this article

 

Tapestry and Wicket are touted as modern familiar component-based Web frameworks. Unlike the Model 2 architecture frameworks Struts or Spring MVC, Tapestry and Wicket offer a fresh approach to the process of Web development by emphasizing a methodology for thinking about Web applications, their behavior, and component interaction in the same way you think about stand-alone GUI-based applications.

A typical component-based application represents a set of pages that consist of a set of components. The components, in turn, may be assembled from smaller components, etc. User interaction here is a specific component event. This is the main difference from MVC-based applications, where the entry point for interactions is a servlet or an action with general attributes (such as URLs, its parameters, forms, etc.).

Developers who use component-based frameworks focus on components and their interaction by implementing event-driven models. Servlets, HTTP sessions, and other entities from the servlet API are moved one level lower and are never used directly. However, the developer is responsible for the server-side state through the way a component or its properties are declared, which can be session-persistent.

Unlike JSF or WebWorks using JSPs or Velocity markups, both Tapestry and Wicket use their own template systems that allow creating HTML templates fully compliant with HTML standards. This gives us a clear separation of concerns: Web designers work on the GUI without a concern about what platform the application is written on; likewise, application developers implement the components not concerned with the final design of pages using stub elements for debugging and testing. Both Tapestry and Wicket support such separation.

Tapestry at a glance

Currently, Tapestry V4.1 is the officially released version of the project. V5.0 is under active development, and at the time of this writing, some 18 months had passed since the team had started rewriting Tapestry from scratch. Even though V5.0 is still not released publicly, it is safe to say that it is completely different from its predecessor in that it is not backward-compatible. Given the unsettled status of V5.0, we will focus on V4.1.

Tapestry V4.1 is heavily based on the HiveMind microkernel, which is a serious representation of Inversion-of-Control containers. All Tapestry services are registered using HiveMind.

A typical Tapestry component is assembled from a component specification that is an XML descriptor, from component logic that is a portion of the Java™ programming language and from UI layout that is an HTML template.

Wicket at a glance

At the heart of the Wicket architecture is the Component class, which all components and markup containers extend. A component is responsible for dealing with its model — an implementation of the IModel interface. The model represents any kind of data relevant to the component instance and defines its behavior. One of the noticeable IModel implementations is theLoadableDetachableModel that allows passing transient data, loading it before rendering the component, and detaching (destroying) it when it is not needed anymore, thus reducing the size of the Wicket session.

Wicket pages are components also, and their states are stored in the Wicket session if they are stateful. Pages can be version-enabled, so every time the state of a page is changed (page is simply viewed, its components state is changed, etc.), it is stored with an incremented version number.

 

Development process

This section describes how typical tasks are accomplished in Tapestry and Wicket. Note that code snippets given below in most cases are taken from a larger source, such as components or pages. Therefore, they may contain invocations of business methods that are not described here.

Data-type support

Both frameworks support Java data types. Tapestry adapts the Object-Graph Navigation Language (OGNL). it is an expression language for getting and setting properties of Java objects. Wicket uses its own mechanisms for data binding. There are two convenient implementations that dynamically retrieve and update object properties: PropertyModel and CompoundPropertyModel.

Let's review an example for using the float type. In Tapestry, a text field with a float value is specified as follows.


Listing 1. Sample Tapestry code
                
<component id="weight" type="TextField">
        <binding name="value" value="ognl:weight"/>
        <binding name="translator" value="translator:number,pattern=#.#"/>
        <binding name="displayName" value="literal:Weight"/>
    </component>

In Wicket, such a text field is specified as follows.


Listing 2. Sample Wicket code
                
FormComponent field = new TextField("weight", Float.class);
field.setLabel(new Model("Weight"));
add(field);

Thus, using simple data types, such as string, integer, float, and even BigDecimal, are natural.

Validation

As a rule, all user input should be validated against business rules. Tapestry and Wicket are both able to perform server-side or client-side (using DHTML) validation on form input fields. Consider how this task can be done at the server side. Field input validation in the framework goes through specific validators in the following manner.


Listing 3. Tapestry validators
                
<component id="weight" type="TextField">
        ...
        <binding name="validators" value="validators:min=1,max=500"/>
    </component>


Listing 4. Wicket validators
                
...
field.add(NumberValidator.range(1, 500));

It is also possible to define a custom field validator if none of the existing ones fit your needs. If any validation error occurs, it should be displayed to the user, indicating that the input is invalid.

In Tapestry, we should define a loop over the field tracking of the default ValidationDelegate form bean to display all existing form errors.


Listing 5. ValidationDelegate form bean
                
    <property name="currentFieldTracking"/>
    <component id="errors" type="For">
        <binding name="source" value="beans.delegate.fieldTracking"/>
        <binding name="value" value="currentFieldTracking"/>
    </component>
    <component id="isInError" type="If">
        <binding name="condition" value="currentFieldTracking.inError"/>
    </component>
    <component id="error" type="Delegator">
        <binding name="delegate" value="currentFieldTracking.errorRenderer"/>
    </component>

The corresponding HTML markup is shown below.


Listing 6. Tapestry validators
                
     <ul jwcid="errors">
         <li jwcid="isInError">
             <span jwcid="error">Form validation error </span>
         </li>
     </ul>

In Wicket, displaying multiple errors is already implemented in the FeedbackPanel: add(new FeedbackPanel("feedback"));. The HTML markup is as follows: <span wicket:id="feedback" /></div>.

Enabling client-side validation consists of adding the clientValidationEnabled parameter to a form in Tapestry, as shown below.


Listing 7. Client-side validation in Tapestry
                
<component id="actionForm" type="Form">
        <binding name="delegate" value="beans.delegate"/>
        <binding name="clientValidationEnabled" value="true"/>
    </component>

In Wicket, the AjaxFormValidatingBehavior class is used for the same purpose..


Listing 8. Client-side validation in Wicket
                
    AjaxFormValidatingBehavior.addToAllFormComponents(form, "onkeydown");
    // Add the button to submit the form using AJAX
    form.add(new AjaxButton("ajax-button", form) {
        protected void onSubmit(AjaxRequestTarget target, Form form) {
            target.addComponent(feedback);
        }
        protected void onError(AjaxRequestTarget target, Form form) {
            target.addComponent(feedback);
        }
    });

Control constructs

Let's assume we have a list of tasks assigned to some person, and we want it to be displayed in an HTML table. In Tapestry, we use the For standard component for running through a collection, as shown in Listings 9, 10, and 11.


Listing 9. Tapestry page specification
                
    <component id="receivedItems" type="For">
        <binding name="source" value="ognl:receivedItems"/>
        <binding name="value" value="ognl:currentItem"/>
    </component>
    <component id="itemId" type="Insert">
        <binding name="value" value="ognl:currentItem.itemId"/>
    </component>
    <component id="subject" type="Insert">
        <binding name="value" value="ognl:currentItem.subject"/>
    </component>
    <component id="creator" type="Insert">
        <binding name="value" value="ognl:currentItem.creator"/>
    </component>
    <component id="recipient" type="Insert">
        <binding name="value" value="ognl:currentItem.recipient"/>
    </component>


Listing 10. Tapestry Java class
                
    public abstract List getReceivedItems();
    public abstract void setReceivedItems(List items);
    public abstract ActionItem getCurrentItem();


Listing 11. Tapestry HTML markup
                
    <tr jwcid="receivedItems">
        <td><span jwcid="itemId">ID</span></td>
        <td><span jwcid="subject">Subject</span></td>
        <td><span jwcid="creator">Creator</span></td>
        <td><span jwcid="recipient">Recipient</span></td>
    </tr>

In Wicket, we use the ListView class and anonymously implement its populateItem() method, as shown in Listings 12 and 13.


Listing 12. Wicket Java class
                
    add(new ListView("receivedItems", items) {
        protected void populateItem(final ListItem item) {
            ActionItem todo = (ActionItem) item.getModelObject();

            item.add(new Label("itemId", String.valueOf(todo.getItemId()));
            item.add(new Label("subject", todo.getSubject()));
            item.add(new Label("creator", todo.getCreator()));
            item.add(new Label("recipient", todo.getRecipient()));
        }
    });


Listing 13. Wicket HTML markup
                
    <tr wicket:id="receivedItems">
        <td><span wicket:id="itemId">ID</span></a></td>
        <td><span wicket:id="subject">Subject</span></td>
        <td><span wicket:id="creator">Creator</span></td>
        <td><span wicket:id="recipient">Recipient</span></td>
    </tr>

Let's make the goal more complex and add some conditional text rendering — for example, CSS class names for even and odd table rows. So we add the following. For page specification in Tapestry, see Listings 14 and 15.


Listing 14. In Tapestry, for page specification
                
    <component id="receivedItems" type="For">
        ...
        <binding name="index" value="ognl:currentIndex"/>
        <binding name="class" value="ognl:currentStyleClass"/>
    </component>


Listing 15. In Tapestry, for Java class
                
    ...
    public abstract int getCurrentIndex();
    public String getCurrentStyleClass() {
        return (getCurrentIndex() % 2 == 0) ? "list-row-even" : "list-row-odd";
    }


Listing 16. In Wicket, for Java class
                
    add(new ListView("receivedItems", items) {
        protected void populateItem(final ListItem item) {
            ...
            item.add(new AttributeModifier("class", true, new AbstractReadOnlyModel() {
                public Object getObject() {
                    return (item.getIndex() % 2 == 0) ? "list-row-even" : "list-row-odd";
                }
            }));
        }
    });

Pagination

Now the page displays all of the user's tasks. However, with time, more tasks emerge and soon there are many in a single table. This is the case where using a multi-page table is highly desirable.

Tapestry provides the convenient Table component and its low-level friends, like the TableView from the Contrib Library module, as shown in Listings 17 and 18.


Listing 17. Tapestry page specification
                
    <component id="receivedItemsView" type="contrib:TableView">
        <binding name="source" value="ognl:itemsTableModel"/>
        <binding name="columns" value="itemId, subject, creator, recipient"/>
        <binding name="pageSize" value="10"/>
    </component>
    <component id="receivedItemsColumns" type="contrib:TableColumns" />
    <component id="receivedItemsRows" type="contrib:TableRows" />
    <component id="receivedItemsValues" type="contrib:TableValues" />
    <component id="receivedItemsPages" type="contrib:TablePages">
        <binding name="pagesDisplayed" value="10"/>
    </component>


Listing 18. Tapestry Java class
                
    public IBasicTableModel getItemsTableModel() {
        return new IBasicTableModel() {
            public int getRowCount() {
                return getActionItemManager().getActionItemsCountByRecipient(uid);
            }
            public Iterator getCurrentPageRows(int nFirst, int nPageSize,
                    ITableColumn objSortColumn, boolean bSortOrder) {
                return getActionItemManager()
                    .getActionItemsListByRecipient(uid, nFirst, nPageSize);
            }
        };
    }


Listing 19. Tapestry HTML markup
                
<span jwcid="table">
    <table>
        <tr><span jwcid="receivedItemsColumns" class="title"/></tr>
        <tr jwcid="receivedItemsRows">
            <td jwcid="receivedItemsValues"/>
        </tr>
    </table>
    <span jwcid="receivedItemsPages"/>
</span>

Wicket offers the DataView class, along with an IDataProvider implementation, as shown below.


Listing 20. Wicket's DataView class
                
public class ItemsDataProvider implements IdataProvider {

    public Iterator iterator(int first, int count) {
        return getActionItemManager().getActionItemsListByRecipient(uid, first, count);
    }

    public int size() {
        return getActionItemManager().getActionItemsCountByRecipient(uid);
    }

    public IModel model(Object object) {
        return new LoadableDetachableModel(object);
    }
}

public ListActionItems extends WebPage {
    public ListActionItems() {
        DataView dataView = new DataView("receivedItemsView", new ItemsDataProvider()) {
            protected void populateItem(final Item item) {
                ActionItem todo = (ActionItem) item.getModelObject();
                item.add(new Label("itemId", String.valueOf(todo.getItemId()));
                item.add(new Label("subject", todo.getSubject()));
                item.add(new Label("creator", todo.getCreator()));
                item.add(new Label("recipient", todo.getRecipient()));
            }
        };
        dataView.setItemsPerPage(10);
        add(dataView);
        add(new PagingNavigator("receivedItemsPages", dataView));
    }
}


Listing 21. Wicket's DataView HTML markup
                
    <table>
        <tr>
            <th>ID</th>
            <th>Subject</th>
            <th>Creator</th>
            <th>Recipient</th>
        </tr>
        <tr wicket:id="receivedItemsView">
            <td><span wicket:id="itemId">ID</span></td>
            <td><span wicket:id="subject">Subject</span></td>
            <td><span wicket:id="creator">Creator</span></td>
            <td><span wicket:id="creationDate">Creation Date</span></td>
            <td><span wicket:id="deadline">Deadline</span></td>
        </tr>
    </table>
    <span wicket:id="receivedItemsPages">Paging navigator links</span>

Internationalization

Internationalization support plays a significant role in decision-making when a multi-language application is developed. Tapestry and Wicket can offer almost infinite localization capabilities. You can localize component texts (labels, messages — the usual stuff), static resources like images, or even whole markup templates by just adding a suffix with locale identifier to the name of your localized resource, as shown below.


Listing 22. Localization in Tapestry and Wicket
                
ListActionItems.html
ListActionItems.properties
ListActionItems_ru_RU.html
ListActionItems_ru_RU.properties

When accessing a localized message from a page specification or from a template, use the message: prefix in parameters for Tapestry components. In Wicket, there is the powerful StringResourceModel class that helps in solving localization tasks.

Bookmarks, breadcrumbs, and the Back button

Tapestry and Wicket generate URLs in their own formats, which do not look like something bookmarkable. This leads to difficulties in referencing the pages. But the frameworks provide solutions for such cases, too.

In Tapestry, a page referred from outside should implement the IExternalPage interface, as shown below.


Listing 23. Tapestry implementing IExternalPage 
                
public abstract class ViewActionItem extends BasePage implements IExternalPage {

    public abstract Integer getItemId();
    public abstract void setItemId(Integer itemId);

    public void activateExternalPage(Object[] params, IRequestCycle cycle) {
        setItemId((Integer) params[0]);
    }

    public void pageBeginRender(PageEvent pageEvent) {
        ActionItem todo = getActionItemManager().getActionItemByItemId(getItemId());
    }
}

Further, it can be referred as http://host/webapp/tapestryapp?page=ViewActionItem&service=external&sp=123. This is, however, not the only way Tapestry pages can be accessed directly. We can use one of the HiveMind service encoders — page-service-encoder — which is able to encode page names into something readable in the URL.


Listing 24. HiveMind configuration: hivemodule.xml
                
<module id="com.ibm.cit.tvw" version="1.1.0">
    <contribution configuration-id="tapestry.url.ServiceEncoders">
        <page-service-encoder id="page" extension="html" service="page"/>
    </contribution>
</module>

Do not forget to add servlet mappings for the .html extension to web.xml, as shown below.


Listing 25. Add servlet mappings in hivemodule.xml
                
    <servlet-mapping>
        <servlet-name>TodolistApplication</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

From now on, each and every application page can be accessed as, for example, http://host/webapp/ListActionItems.html. This can be bookmarked. Note that you cannot supply request parameters in that fashion — pages will be invoked without (or with default) arguments.

In Wicket, you should only define the page constructor with PageParameters as an argument, as shown below.


Listing 26. Wicket and PageParameters 
                
public class ListActionItems extends WebPage {
    public ListActionItems(PageParameters parameters) {
        int id = parameters.getInt("id");
        // do something
    }
}

Later, this page can be referred as http://host/webapp/wicketapp/?wicket:bookmarkablePage=%3Acom.ibm.cit.tvw.wicket.page.ViewActionItem&id=123. You are also able to mount pages to a desirable path, as shown below.


Listing 27. Mount pages to a desirable path in Wicket
                
public class ToDoListApplication extends WebApplication {
    protected void init() {
        mountBookmarkablePage("/apath/login.html", Login.class);
    }
}

This approach allows you the greatest flexibility when manipulating page URLs.

Now we turn to breadcrumbs. Breadcrumbs are the action history of a client. Wicket has two interfaces intended for breadcrumb support: IBreadCrumbModel and IBreadCrumbParticipant, where the model represents participants as a list with one active breadcrumb. A useful implementation of the model interface BreadCrumbBar holds a stack of breadcrumb participants. A new participant is added to the top of the stack if it is not already on the way — in this case, the stack is cut off to that one.

Tapestry, on the other hand, does not offer any ready-to-use solution for breadcrumbs.

Next, we turn to the Back button. The Back button on Web browsers was always something that Web application developers wanted to eliminate to avoid unexpected effects of its use. But it remains. As a result, the application should react correctly to any related event.

In this context, Wicket shines since it uses page-version management — page state can be easily reverted to any previous version if page versioning is enabled. Page states are managed by a VersionManager and state changes are stored in user's session. However, this feature should be used very carefully.

What Tapestry can offer in reply? There is no simple way to do this in Tapestry. One option might be the use of the client-side persistence, but this is a rather long story that deserves some special consideration.

Custom components

One of the main and most powerful things in component-based frameworks is the reuse of custom components. You can describe your own component that could be a whole page, small panel, or even a single HTML element. Designing component templates comes naturally through component inheritance and does not cause a headache anymore. Once you created them, they can be simply injected anywhere in the application as many times as needed. Tapestry and Wicket allow managing components reuse without any limits, each in its own way.

Custom components become truly reusable when they are applicable among different applications. In Wicket, components can be packaged simply by creating a JAR archive containing the components' classes and markup templates. Putting the archive to the application's classpath automatically makes the components available. Tapestry requires a few more steps to define a custom components library —the JAR archive should contain an XML descriptor with the library-specification element. An application that uses this library should have it specified in the application's configuration file.

One of the greatest adoptions of reusable components is page templates with common navigation panel, header and footer, advertisement areas, etc The following sample template is a component that displays the home link, the name of the currently logged user, and the Logout button.

In Tapestry, the Template component specification is shown in Listings 28, 29, and 30.


Listing 28. Tapestry's Template component specification
                
<component-specification allow-body="yes" 
  allow-informal-parameters="no" 
  class="com.ibm.cit.tvw.tapestry.component.Template">

    <!--HTML head -->
    <asset name="stylesheet" path="/style.css" />
    <parameter name="pageTitle" default-value="literal:Todolist Application" />
    <component id="shell" type="Shell">
        <binding name="stylesheet" value="assets.stylesheet" />
        <binding name="title" value="ognl:pageTitle" />
    </component>

    <!-- HTML body -->
    <component id="body" type="Body" />

    <!-- The name of the currently logged user -->
    <component id="user" type="Insert">
        <binding name="value" value="ognl:currentUser"/>
    </component>

    <!-- The home page -->
    <component id="homeLink" type="PageLink">
        <binding name="page" value="literal:ListActionItems" />
    </component>

    <!-- User Profile page -->
    <component id="profileLink" type="DirectLink">
        <binding name="listener" value="listener:onEditUserProfile"/>
    </component>

    <!-- Logout link -->
    <component id="logoutLink" type="ServiceLink">
        <binding name="service" 
                value="ognl:@org.apache.tapestry.Tapestry@RESTART_SERVICE"/>
    </component>

    <!-- Page content -->
    <component id="pageContent" type="RenderBody"/>
</component-specification>


Listing 29. Tapestry's Template component specification Java class
                
public abstract class Template extends BaseComponent {

    public String getCurrentUser() {
        return getPage().getRequestCycle().getInfrastructure()
                .getRequest().getUserPrincipal();
    }

}


Listing 30. Tapestry's Template component specification HTML markup
                
<html jwcid="shell">
<body jwcid="body">
<div id="top">
<div id="header">
    <a jwcid="homeLink" class="homelink">Action Items Sample Application</a>
    Current user:   <span jwcid="user">Davy Jones</span>
    <a jwcid="logoutLink">Logout</a></span>
</div>
<div id="page-content">
<span jwcid="pageContent">This is a page content.</span>
</div>
</div>
</body>
</html>

Other pages use the template as shown in Listing 31, which is an example of the ViewActionItem page.


Listing 31. ViewActionItem example
                
<page-specification>
    <component id="template" type="Template">
        <binding name="pageTitle" value="literal:View Action Item"/>
    </component>
    ...
</page-specification>


Listing 32. ViewActionItem in HTML markup
                
<span jwcid="template">
    <!-- Page content -->
    ...
</span>

In Wicket, a template is represented as a base page, which is shown in Listings 33 and 34.


Listing 33. Wicket template
                
public abstract class TemplatePage extends WebPage {

    private String title;

    public TemplatePage() {
        add(new Label("title", new PropertyModel(this, "title")));
        add(new BookmarkablePageLink("homeLink", getApplication().getHomePage()));
        add(new Label("user", ((WebRequest) getRequest()).getHttpServletRequest()
                .getUserPrincipal().getName()));
        add(new Link("logoutLink") {
            public void onClick() {
                getSession().invalidate();
                getRequestCycle().setResponsePage(getHomePage());
                getRequestCycle().setRedirect(true);
            }
        });
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}


Listing 34. Wicket template as HTML markup
                
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:wicket="http://wicket.apache.org/">
<head>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="stylesheet" type="text/css" href="style.css" />
<title wicket:id="title">Sample Page Title</title>
</head>
<body>
<div id="top">
<div id="header">
    <a wicket:id="homeLink" class="homelink">Action Items Sample Application</a>
    Current user: <span wicket:id="user">Davy Jones</span>
    <input type="button" class="button" wicket:id="logoutLink" value="Logout" /></span>
</div>
<div id="page-content">
<wicket:child />
</div>
</div>
</body>
</html>

Child pages that use this template should inherit from the Template page, which is shown in Listings 35 and 36.


Listing 35. Inheriting from the Template page
                
public class ViewActionItem extends TemplatePage {

    public ViewActionItem() {
        setTitle("View Action Item");
        ...
    }
}


Listing 36. Inheriting from the Template page as HTML markup
                
<html xmlns:wicket="http://wicket.apache.org/">
<head></head>
<body>
<wicket:extend>
    <!-- Page content -->
    ...
</wicket:extend>
</body>
</html>

Ajax support

We reach the most interesting point in the frameworks comparison: the use of Asynchronous JavaScript + XML (Ajax).

Do you remember your first Web application with Ajax support and how much effort it required to implement? Yes, all that JavaScript communications and data parsing code with lots of tricks for multi-browser support. Servlets seemed to be a trivial work comparing to client-side implementations that always seemed like the worst ones.

Now, however, with the use of frameworks like Tapestry and Wicket, it takes only a few lines of code and a few minutes of your attention to add an Ajax action to an application. It is surprisingly easy. The example below represents a simple scenario: A click on the item from the list of to-dos should update (in Ajax mode) the preview pane with the corresponding data.

In Tapestry, set the async parameter for a link to true and define the list of components the link should update if needed, which is shown in Listings 37, 38, and 39.


Listing 37. Tapestry page specification fragment
                
    <component id="previewReceivedItem" type="DirectLink">
        <binding name="listener" value="listener:onPreviewItem"/>
        <binding name="parameters" value="ognl:currentItem.itemId"/>
        <binding name="async" value="true"/>
        <binding name="updateComponents" value="ognl:{'preview'}"/>
    </component>
    <component id="preview" type="Any"/>
    <component id="previewSubject" type="Insert">
        <binding name="value" value="ognl:previewSubject"/>
        <binding name="renderTag" value="true"/>
    </component>
    <component id="previewState" type="Insert">
        <binding name="value" value="ognl:previewState"/>
        <binding name="renderTag" value="true"/>
    </component>


Listing 38. Tapestry page specification fragment Java class
                
public abstract class ListPreviewActionItems extends BasePage {

    public abstract String getPreviewSubject();
    public abstract void setPreviewSubject(String previewSubject);

    public abstract String getPreviewState();
    public abstract void setPreviewState(String PreviewState);

    public void onPreviewItem(Integer itemId) {
        if (itemId != null) {
            ActionItem pitem = getActionItemManager().getActionItemByItemId(itemId);
            setPreviewSubject(pitem.getSubject());
            setPreviewState(pitem.getCurrentState());
        }
    }
}


Listing 39. Tapestry page specification fragment HTML markup
                
<h3>Preview Action Item</h3>
<div jwcid="preview">
    Subject: <span id="previewSubject" jwcid="previewSubject">subject</span><br/>
    State: <span id="previewState" jwcid="previewState">current state</span>
</div>

In Wicket, just use the AjaxLink with the implemented onClick() method, as shown in Listings 40 and 41.


Listing 40. Wicket's AjaxLink 
                
public class ListPreviewActionItems extends WebPage {

 public ListPreviewActionItems() {
   final LoadableActionItemModel previewItem = new LoadableActionItemModel(null);

   WebMarkupContainer preview = new WebMarkupContainer("preview");
   preview.setOutputMarkupPlaceholderTag(true);
   preview.add(new Label("previewSubject", new PropertyModel(previewItem, "subject")));
   preview.add(new Label("previewState", new PropertyModel(previewItem, "currentState")));
   add(preview);

   AjaxLink previewReceivedItem = new AjaxLink("previewReceivedItem") {
       public void onClick(AjaxRequestTarget target) {
           previewItem.setItemId(currentItem.getItemId());
           target.addComponent(previewContainer);
       }
   };
   add(previewReceivedItem);
 }
}


Listing 41. Wicket's AjaxLink HTML markup
                
<h3>Preview Action Item</h3>
<div wicket:id="preview">
    Subject: <span wicket:id="previewSubject">subject</span><br/>
    State: <span wicket:id="previewState">current state</span>
</div>

That's it. Communications, data handling, and all other dirty work are performed by the frameworks behind the scenes.

 

Development tools

There is not much that can be said about the difference in development process between Tapestry and Wicket frameworks. Implementing Tapestry components is easy with most Java IDEs that support Web application development. Wicket requires even less — any Java IDE plus HTML editor would fit your development needs.

You may only run into sync issues with the component model trees in Java and markup, but you will be notified of that each time you invoke the component. This stands in contrast to other frameworks, such as Google Web Toolkit, which can handle such issues at compile time.

 

IBM WebSphere Application Server CE use

Tapestry and Wicket are Java Web application-compatible frameworks, so you build and package your Web application as usual. To deploy the application onto IBM® WebSphere® Application Server Community Edition, provide an embedded or a separate application deployment plan, which is also typical.

Conclusion

Tapestry and Wicket are popular representatives of the component-based Web frameworks and probably the most exceptional ones from that camp. With their help, it is possible to build applications of any level of complexity. Of course, a set of pages with static information could be better managed with a CMS, but when talking about multiple user interactions with an application, the frameworks show off their best.

Despite the fact that there is a similarity between frameworks' architectures (both are component-oriented with clear separation of concerns), their implementation is quite different. While Tapestry offers a declarative approach in component specification, Wicket brings pure Java programming with no XML and no annotations. Wicket has a few strong advantages in page versioning and multi-window support. Wicket also has a few more helpful implementations, including breadcrumbs, a feedback panel, and many of the funny stuff found in dynamic HTML, such as tabbed panels and dialogs.

If you try to avoid using XML, or if you just like object-oriented programming, Wicket could be your choice for day-to-day use. A richer extensions library also gives a plus to Wicket.

Finally, Tapestry is in a period of transition today. Tapestry V5 promises many enhancements over V4.1, but there is no planned backward-compatibility. Thus, applications created with V4.1 may go on to live useful lives, but the expertise developers gain using today's Tapestry may not pay dividends for very long.


Resources

Learn

  • Learn more about Apache Wicket, the Apache Software Foundation project. See the Wicket wiki documentation on the Wicket home page.

  • Learn more about Tapestry, the Apache Software Foundation project. See the Tapestry wiki documentation on the Tapestry home page.

  • Learn more about HiveMind, the Apache Software Foundation project. See the HiveMind wiki documentation on the HiveMind home page.

  • To listen to interesting interviews and discussions for software developers, check out developerWorks podcasts.

  • Stay current with developerWorks' Technical events and webcasts.

  • Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.

  • Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.

  • Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.

Get products and technologies

  • Innovate your next open source development project with IBM trial software, available for download or on DVD.

  • Download IBM product evaluation versions, and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.

Discuss

About the authors

Artem Papkov is currently a Solution Architect with IBM's Client Innovation Team, working with customers and business partners to adopt emerging technologies, such as SOA, Web services, and alike. After graduating from the Belarusian State University of Informatics and Radioelectronics in 1998 with Masters Degree in Computer Science, he joined IBM in Research Triangle Park, N.C in 2000. His experience includes software development of multi-tier solutions using emerging technologies, architecture design, and integration of Internet-based solutions. For the past three years, he has been focused on working closely with customers, helping them adopt Web services as IBM's strategic integration technology and SOA as the integration approach.

Jim Smith has over 18 years of experience in software development. He started his career at Sandia National Labs in Livermore, California, designing high-speed data acquisition systems and distributed computing systems using a myriad of existing legacy code. With deep experience in Java language and customer-facing skills, Jim moved to the Emerging Internet Technologies team focusing on making Java solutions real for IBM customers. Jim was one of the founders of Advanced Technology Solutions (ATS), a global software services and development organization with a mission to develop, refine, and franchise advanced technologies and lightweight business processes for IBM, development labs, Business Partners, and customers, resulting in faster adoption and deployment of standard technologies and IBM products. Currently, Jim manages the organization.

Ilya Kanonirov is an IBM WebSphere-certified software engineer at Axmor Software, consulting at IBM's Client Innovation Team. He has seven years' experience in creating custom software solutions as a developer and as an architect.

Rate this article

Average rating 4 stars based on 50 votes Average rating (50 votes)

1 star1 star1 star
2 stars2 stars2 stars
3 stars3 stars3 stars
4 stars4 stars4 stars
5 stars5 stars5 stars

Comments

Add comment:

Sign in or register to leave a comment.

Note: HTML elements are not supported within comments.

Notify me when a comment is added1000 characters left

 



Be the first to add a comment

 
分享到:
评论
1 楼 zhaohuaxishiwzw 2017-03-21  
老贴留名!

相关推荐

    Java Web层框架之比较—比较JSF、Spring MVC、Stripes、Struts 2、Tapestry和Wicket.doc

    Java Web层框架之比较—比较JSF、Spring MVC、Stripes、Struts 2、Tapestry和Wicket.doc

    tapestry教程资料文档合集

    Tapestry5最新中文教程.doc 作者 Renat Zubairov & Igor Drobiazko译者 沙晓兰 发布于 2008年7月2日 下午9时30分 社区 Java 主题 Web框架 ----------------------------------------- Tapestry5.1实例教程.pdf ...

    tapestry5以上的帮助事例,帮助文档与spring衔接文档

    Tapestry是一个基于控件的框架以致于用它开发Web应用类似开发传统的GUI应用。你用Tapestry开发Web应用时你无需关注以操作为中心的(Operation-centric) Servlet API.引用Tapestry网站上的一句话:"Tapestry用对象...

    深入浅出Tapestry

    资源名称:深入浅出Tapestry内容简介:本书以循序渐进的方式,从Tapestry框架技术的基本概念入手,讲解Tapestry框架在J2EE Web应用程序中的整体架构实现。使读者在学习如何使用Tapestry框架技术的同时,还能够获得在...

    tapestry官方中文文档

    Tapestry 4 官方文档中文版本,现在中文资料比较少,和大家共享一下

    Tapestry5.0.16_API文档

    Tapestry5.0.16文档和大家一起学习

    tapestry 实例

    tapestry 实例tapestry 实例tapestry 实例tapestry 实例

    (Tapestry)An infrastructure for Fault-Tolerant Wide-area Location and Routing.ppt

    (Tapestry)An infrastructure for Fault-Tolerant Wide-area Location and Routing.

    tapestry3开发指南,带tapestry3所有jar包

    tapestry3开发指南,带tapestry3所有jar包

    深入浅出tapestry

    本书以循序渐进的方式,从Tapestry框架技术的基本概念入手,讲解Tapestry框架在J2EE Web应用程序中的整体架构实现。使读者在学习如何使用Tapestry框架技术的同时,还能够获得在J2EE Web应用程序中应用Tapestry框架的...

    Pastry and Tapestry

    关于Pastry和Tapestry的介绍,对于routing方法介绍的挺详细,网上有它的翻译版,但是相比这个原文少了不少东西。

    Tapestry4开发指南

    Tapestry4的雏形是Tapestry3.1,Tapestry的作者Howard,不光开发了Tapestry,还同时开发了一个轻量级框架Hivemind。所以Tapestry3.1的开发一开始就处于Hivemind框架之下。后来由于种种原因,Howard没有将Tapestry3.1...

    tapestry5.2.6 jar包

    tapestry5.2.6 最新jar包,Tapestry框架是一个位于java servlet容器和Tapestry应用程序之间的层

    tapestry技术

    tapestry技术 Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得...

    Tapestry5最新中文入门实例教程

    本文介绍Tapestry框架版本5。本文利用Tapestry 5开发一个简单的具有创建/读/更新/删除功能的应用,在创建这个应用的过程中,本文体会到Tapestry带来的开发效率的提升。从多方面来讲解 Tapestry应用,比如应用的...

    Tapestry开发指南

    Tapestry是一个开源的基于servlet的应用程序框架,它使用组件对象模型来创建动态的,交互的web应用。一个组件就是任意一个带有jwcid属性的html标记。其中jwc的意思是Java Web Component。Tapestry使得java代码与html...

    tapestry-src-5.1.0.5.zip

    包含: tapestry 的源代码, tapestry集成spring2.0 tapestry快速启动 tapestry upload tapestry hibernate tapestry annotations

    Wicket开发指南-简体版

    Wicket是一个基于Java的Web开发框架,与Struts,WebWork,Tapestry类似。其特点在于对Html和代码进行了有效的分离(有利于程序员和美工的合作),基于规则的配置(减少了XML等配置文件的使用),学习曲线较低(开发...

    tapestry学习入门资料

    强大的tapestry框架的学习入门资料,详细介绍了tapestry的常用开发文档。

Global site tag (gtag.js) - Google Analytics