The idea is to develop a reusable mulit step panel with defined user exits to react on the panel flow.
The search form is very simple and consist of a text field and a submit button. After the user has submitted the form a result table is
shown under the form. The user can select a customer from the result list.
Delegate Pattern:
With the delegate pattern you have the possiblity to react on defined events of the panel from outside. In the above described example
you have two delegate methods.
- void searchSumitted(SearchPanel panel);
This method is invoked after the form was successfully submitted. Here
you have the possiblity to read the data from the form, execute some backend methods
(for example reading some customers from the database) and set a list of customers
which will be shown in the result table.
- customerSelected(SearchPanel panel, Customer customer);
This method is invoked after a customer was selected from the result table.
The the method tells you which customer was selected.
The form handles all the stuff regarding the search fields. For example the panel check whether all
mandatory fields are filled. If everything is fine the delegate method void searchSumitted(SearchPanel panel) is invoked.
Inside this method you have access to the submitted form values and you can provide the result list.
After that the result table is shown. When the user selects a row of the result table the second delegate method customerSelected(SearchPanel panel, Customer customer) is executed.
Inside this method you get the selected customer value object.
Source structure
Code Block |
---|
|
src
|-com.sample
|-searchpanel
| |-Customer.java // Customer value object
| |-CustomerDataProvider.java // custom implmentation of data provider
| |-SearchPanel.java // reusable search panel
| |-SearchPanelDelegate.java // delegate interface
| |-SearchPanel.html // template for the search panel
|-HomePage.java // Sampel page which uses the search panel
|-WicketApplication.java // wicket app
|-HomePage.html // template of the sample page
|
All the sources inside the searchpanel package are reusable and can for example packed into separate jar file.
Test Application
The following three sources files are the sample application which uses the search panel.
Using the SearchPanel is very easy.
1. The Wicket page has to implement the interface SearchPanelDelegate
2. The Wicket page HTML needs a div with a wicket id. (see <div wicket:id="search">)
3. Create a SearchPanel with the id any the object which implements the SearchPanelDelegate interace
4. Add the panel object to the Wicket page.
5. Implement your custom functionality inside the delegate methods
HomePage.java
Code Block |
---|
package com.sample;
import java.util.ArrayList;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebPage;
import com.sample.seachpanel.Customer;
import com.sample.seachpanel.SearchPanel;
import com.sample.seachpanel.SearchPanelDelegate;
/**
* Homepage
*/
public class HomePage extends WebPage implements SearchPanelDelegate {
private static final long serialVersionUID = 1L;
/**
* Constructor that is invoked when page is invoked without a session.
*
* @param parameters
* Page parameters
*/
public HomePage(final PageParameters parameters) {
// create the search panel and add it to the Page
SearchPanel panel = new SearchPanel("search", this);
add(panel);
}
/**
* This delegate method is invoked when a customer was selected from the SearchPanel
*/
public void customerSelected(SearchPanel panel, Customer customer) {
System.out.println("A customer was selected");
System.out.println(customer.toString());
}
/**
* This delegate method is invoked when the SearchPanel form was sumitted
*/
public void searchSumitted(SearchPanel panel) {
System.out.println("The search was sumitted");
System.out.println(panel.getSearchString());
// implement here some backend access
ArrayList<Customer> list = new ArrayList<Customer>();
list.add(new Customer("1000", "Tom"));
list.add(new Customer("2000", "Sue"));
list.add(new Customer("3000", "Paul"));
list.add(new Customer("4000", "Linda"));
// set the data list to the SearchPanel
panel.getResultlist().setList(list);
}
}
|
HomePage.html
Code Block |
---|
|
<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd" >
<head>
<title>Wicket Panel with using delegate pattern</title>
</head>
<body>
<strong>Wicket Panel with using delegate pattern</strong>
<div wicket:id="search">Here is the search panel and result list displayed</div>
</body>
</html>
|
WicketApplication.java
Code Block |
---|
package com.sample;
import org.apache.wicket.protocol.http.WebApplication;
/*\*
* Application object for your web application. If you want to run this application without deploying, run the Start class.
*
* @see com.sample.Start#main(String\[\])
\*/
public class WicketApplication extends WebApplication
{
/*\*
* Constructor
\*/
public WicketApplication()
{
}
/*\*
* @see org.apache.wicket.Application#getHomePage()
\*/
public Class<HomePage> getHomePage(){
return HomePage.class; }
}
|
Reusable panel source code
Here is the source of the reusable panel.
Customer
Code Block |
---|
package com.sample.seachpanel;
import java.io.Serializable;
/**
* This class is a value object for customers
*
* @author manuel.fritsch
*/
public class Customer implements Serializable {
private String id;
private String name;
/**
* Default empty constructor
*/
public Customer() {
}
/**
* This constructor can used to set directly the customer id and name
*
* @param id
* @param name
*/
public Customer(String id, String name) {
super();
this.id = id;
this.name = name;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id
* the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Customer Id = " + id + " Customer Name = " + name;
}
}
|
CustomerDataProvider
Code Block |
---|
package com.sample.seachpanel;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import org.apache.wicket.markup.repeater.data.IDataProvider;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
/**
* This a customer data proivder
* The advantage of this data provider is that you can update the data list
* @author manuel.fritsch
*
* @param <T>
*/
public class CustomerDataProvider<T extends Serializable> implements IDataProvider<T>
{
private static final long serialVersionUID = 1L;
/** reference to the list used as dataprovider for the dataview */
private List<T> list;
/**
*
* @param list
* the list used as dataprovider for the dataview
*/
public CustomerDataProvider(List<T> list)
{
if (list == null)
{
throw new IllegalArgumentException("argument [list] cannot be null");
}
this.list = list;
}
/**
* @see IDataProvider#iterator(int, int)
*/
public Iterator<? extends T> iterator(final int first, final int count)
{
int toIndex = first + count;
if (toIndex > list.size())
{
toIndex = list.size();
}
return list.subList(first, toIndex).listIterator();
}
/**
* @see IDataProvider#size()
*/
public int size()
{
return list.size();
}
/**
* @see IDataProvider#model(Object)
*/
public IModel<T> model(T object)
{
return new Model<T>(object);
}
/**
* @see org.apache.wicket.model.IDetachable#detach()
*/
public void detach()
{
}
/**
*
* @return
*/
public List<T> getList() {
return list;
}
/**
*
* @param list
*/
public void setList(List<T> list) {
this.list = list;
}
}
|
SearchPanel
Code Block |
---|
package com.sample.seachpanel;
import java.util.ArrayList;
import org.apache.wicket.feedback.ContainerFeedbackMessageFilter;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.model.PropertyModel;
public class SearchPanel extends Panel {
/**
*
*/
private static final long serialVersionUID = 1L;
private SearchPanelDelegate delegate;
private String searchString;
private WebMarkupContainer resulttable;
private CustomerDataProvider resultlist;
private DataView dataView;
public SearchPanel(String id, final SearchPanelDelegate delegate) {
super(id);
this.delegate = delegate;
// create form and add form to the search panel
Form<?> form = new SearchForm("form");
add(form);
// create markup container around the result table
// this is necessary to hide the result list before the form submit
this.resulttable = new WebMarkupContainer("resulttable");
this.resulttable.setVisible(false);
add(resulttable);
// init the hitlist with an empty dataprovider
ArrayList<Customer> emptylist = new ArrayList<Customer>();
resultlist = new CustomerDataProvider(emptylist);
// create data view component
this.dataView = new DataView<CustomerDataProvider>("resultlist", resultlist) {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* The
*/
@Override
protected void populateItem(Item item) {
// get customer object for row
final Customer customer = (Customer) item.getModelObject();
// create a link for column 1
SearchPanelLink link = new SearchPanelLink("select");
// the customer object to the link.
//This customer object will be returned when the row is selected
link.setCustomer(customer);
// Add link and labels to the data view
item.add(link);
item.add(new Label("name", customer.getName()));
item.add(new Label("id", customer.getId()));
}
};
// add data view to search panel
this.resulttable.add(dataView);
// Filter the feedback messages
// Only messages which belongs to the current form will be displayed
FeedbackPanel feedback = new FeedbackPanel("feedback");
feedback.setFilter(new ContainerFeedbackMessageFilter(form));
add(feedback);
}
/**
* @return the searchString
*/
public String getSearchString() {
return searchString;
}
/**
* @param searchString the searchString to set
*/
public void setSearchString(String searchString) {
this.searchString = searchString;
}
/**
* @return the resultlist
*/
public CustomerDataProvider getResultlist() {
return resultlist;
}
/**
* @param resultlist the resultlist to set
*/
public void setResultlist(CustomerDataProvider resultlist) {
this.resultlist = resultlist;
}
/**
* The inner search form class
* @author manuel.fritsch
*/
public final class SearchForm extends Form {
// The form seach field
private TextField<String> searchfield;
public SearchForm(String id) {
super(id);
// init seachfield
searchfield = new TextField<String>("seachfield", new PropertyModel<String>(SearchPanel.this, "searchString"));
// set field required
searchfield.setRequired(true);
// add searchfield to search form
add(searchfield);
}
/**
* This method is executed the the searach butten was pressed
*/
@Override
protected void onSubmit() {
// invoke delegate method
// the search is submitted and the delegate object will be informed
delegate.searchSumitted(SearchPanel.this);
// make the result table visible
resulttable.setVisible(true);
super.onSubmit();
}
}
/**
* Link implementation for the table rows
* @author manuel.fritsch
*
*/
public class SearchPanelLink extends Link<String> {
private Customer customer;
public SearchPanelLink(String id) {
super(id);
}
/**
* This method will be executed when the select link
* used in the result page
*/
@Override
public void onClick() {
// invoke delegate method
// a customer was the selected an the delegate object will be informed
if(delegate != null) {
delegate.customerSelected(SearchPanel.this, customer);
}
}
/**
* @return the customer
*/
public Customer getCustomer() {
return customer;
}
/**
* @param customer the customer to set
*/
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
}
|
SearchPanelDelegate
Code Block |
---|
package com.sample.seachpanel;
/**
* This is the delegation interface It describes the all possible delegate
* methods
*
* @author manuel.fritsch
*
*/
public interface SearchPanelDelegate {
// This delegate method is invoked when the from was successfully submitted
void searchSumitted(SearchPanel panel);
// This delegate method is invoked when the customer was selected from the
// result list
void customerSelected(SearchPanel panel, Customer customer);
}
|
SearchPanel.html
Code Block |
---|
|
<html
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd">
<head>
<title>Wicket panel with using a delegate pattern</title>
</head>
<body>
<wicket:panel>
<div id="message" wicket:id="feedback">[Feedback Panel]</div>
<form wicket:id="form">
<input type="text" wicket:id="seachfield" value="" />
<input type="submit" value="Search" />
</form>
<div wicket:id="resulttable">
<table>
<thead>
<th>Action</th>
<th>Customer Id</th>
<th>Customer Name</th>
</thead>
<tbody>
<tr wicket:id="resultlist">
<td><a wicket:id="select" href="#">Select</a></td>
<td><span wicket:id="id">Test Name</span></td>
<td><span wicket:id="name">Test Name</span></td>
</tr>
</tbody>
</table>
</div>
</wicket:panel>
</body>
</html>
|
Tipps
It is possible to have several search panels on one Wicket page. To identify which panel has been
called the delegate method use the following snippet:
Code Block |
---|
public void customerSelected(SearchPanel panel, Customer customer) {
if("search".equals(panel.getId())) {
// Panel one
}
if("search".equals(panel.getId())) {
// Panel tow
}
System.out.println("A customer was selected");
System.out.println(customer.toString());
}
|