Monday, January 20, 2014

RichFaces 4.3.x Tip of the Day: Complex RichFaces Data Tables

Introduction

I have been working on JSF tables for the various projects I have been involved with over the years. Starting in 2012, I began looking at RichFaces <rich:dataTable /> for some projects at my day job. The research into how to handle a number of complex situations has been enlightening to say the least.

The table is the most complex component in HTML. It is seemingly boundless in its extensibility. You can have multi-column headers that span multiple rows, you can multi-row cells, or multi-column cells. Tables can be displayed left-to-right, or right-to-left, top-to-bottom and vice-versa. As a result, when developing components for JSF, or any component framework, decisions must be made on how to generate them.

A couple of the component frameworks like PrimeFaces, and RichFaces allow developers to create more complex tables with more ease. However there are limitations with each of these frameworks. We trade flexibility for consistency, and this is fine in most cases.

The demonstration code in this post is about getting some of the flexibility back, or taking advantage of the flexibility that comes with a framework like RichFaces. We will gain the flexibility back, but it is a function of complexity. The examples will show you techniques for doing the "same thing" in multiple ways. For example, sorting can be done on the server, client, or a combination of both.

The question is where we put the complex bits. The answer to that question depends on you as a developer. You need to examine the problem domain, and understand the limits to the techniques presented.

Solutions

Please let me confess something. I like building HTML objects programmatically. There I said it. In this case I am trading the ease of development for flexibility. The solutions below will demonstrate the different techniques for accomplishing the same functionality. Please examine the code carefully before discounting it. I spent a lot of time playing with it to make it look simple.

The code for this project was developed using NetBeans and Apache Maven. The code was tested on GlassFish 3.1.2.2 and 4.0. It should work on other application servers, but I have not tested it on other servers. This project assumes you are using NetBeans which includes a sample database that these examples require. If you are not using NetBeans, you will need to create your own database with sample data to display some of the tables.

The code can be downloaded from Bitbucket at the link below, or in the references section at the end of the post.

richfaces-tables-poc

Dynamic Data Table with Sorting

Dynamic Table with Sorting
This example uses the binding attribute of the <rich:dataTable /> to bind our table to a CDI @ManagedBean. The bean is responsible for generating the table programmatically, and returning it back to the page. The data is sortable by column.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:rich="http://richfaces.org/rich">
    <h:head>
        <title>Dynamic Data Table Design #1</title>
    </h:head>
    <h:body>
        <h1>
Dynamic Data Table Design #1</h1>
<p>
            The table is bound to the page backing bean, and is generated dynamically.
  
            Please use the Source and Code links to see the details.
        </p>
<h:form id="form1">
            <rich:dataTable id="dataTable" binding="#{dataTable1.dataTable}"/>
        </h:form>
        <div style="padding-top: 5px;">
            <a href="#{facesContext.externalContext.requestContextPath}">Index</a>
            <a href="#{facesContext.externalContext.requestContextPath}/source/dataTable1.xhtml">Source</a>
            <a href="#{facesContext.externalContext.requestContextPath}/source/resources/src/dataTable1.java">Code</a>
        </div>
</h:body>
</html>
As you can see the page is very simple. In fact, most of the page is plumbing and navigation. The <rich:dataTable /> is the smallest part of the page. The code to generate the table is much more complex.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
package com.bluelotussoftware.example.richfaces;
 
import com.bluelotussoftware.example.richfaces.model.Customer;
import com.bluelotussoftware.example.richfaces.ssb.CustomerFacade;
import com.bluelotussoftware.jsf.utils.JSFUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.Application;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import org.richfaces.component.SortOrder;
import org.richfaces.component.UIColumn;
import org.richfaces.component.UIColumnGroup;
import org.richfaces.component.UICommandLink;
import org.richfaces.component.UIDataTable;
 
/**
 * <p>
Proof of Concept #1 Programmatic RichFaces data table
 * <code><rich:dataTable/></code> with server side sorting</p>
*
 * <p>
<strong>Note:</strong> Please note that the scope must be set to session
 * for the object holding a reference to the bound datatable.</p>
*
 * @author John Yeary
 * @version 1.0
 */
@Named
@SessionScoped
public class DataTable1 implements Serializable {
 
    private static final long serialVersionUID = 3733919546663290317L;
    private List<customer> customers;
    private SortOrder nameSortOrder = SortOrder.unsorted;
    private SortOrder creditSortOrder = SortOrder.unsorted;
    private SortOrder phoneSortOrder = SortOrder.unsorted;
    @EJB
    private CustomerFacade cf;
    private UIDataTable dataTable;
 
    public DataTable1() {
        customers = new ArrayList<customer>();
    }
 
    @PostConstruct
    private void init() {
        customers.addAll(cf.findAll());
 
        Class<?>[] klazz = new Class<?>[]{};
        Application application = FacesContext.getCurrentInstance().getApplication();
 
        // Create RichFaces Table <rich:dataTable/>
        dataTable = (UIDataTable) application.createComponent(UIDataTable.COMPONENT_TYPE);
        dataTable.setVar("customer");
        dataTable.setValue(customers);
 
        // Create A4J CommandLink <a4j:commandLink/> Column Headers
        UICommandLink clink = (UICommandLink) application.createComponent(UICommandLink.COMPONENT_TYPE);
        clink.setValueExpression("value", JSFUtils.createValueExpression("#{dataTable1.customerColumnHeader}", String.class));
        clink.setActionExpression(JSFUtils.createMethodExpression("#{dataTable1.nsort()}", String.class, klazz));
        clink.setRender("dataTable");
 
        UICommandLink clink1 = (UICommandLink) application.createComponent(UICommandLink.COMPONENT_TYPE);
        clink1.setValue("Phone");
        clink1.setActionExpression(JSFUtils.createMethodExpression("#{dataTable1.psort()}", String.class, klazz));
        clink1.setRender("dataTable");
 
        UICommandLink clink2 = (UICommandLink) application.createComponent(UICommandLink.COMPONENT_TYPE);
        clink2.setValue("Credit Limit");
        clink2.setActionExpression(JSFUtils.createMethodExpression("#{dataTable1.csort()}", String.class, klazz));
        clink2.setRender("dataTable");
 
        // Create Data Elements
        HtmlOutputText htmlOutputText = (HtmlOutputText) application.createComponent(HtmlOutputText.COMPONENT_TYPE);
        htmlOutputText.setValueExpression("value", JSFUtils.createValueExpression("#{customer.name}", String.class));
 
        HtmlOutputText htmlOutputText1 = (HtmlOutputText) application.createComponent(HtmlOutputText.COMPONENT_TYPE);
        htmlOutputText1.setValueExpression("value", JSFUtils.createValueExpression("#{customer.phone}", String.class));
 
        HtmlOutputText htmlOutputText2 = (HtmlOutputText) application.createComponent(HtmlOutputText.COMPONENT_TYPE);
        htmlOutputText2.setValueExpression("value", JSFUtils.createValueExpression("#{dataTable1.format(customer.creditLimit)}", String.class));
        htmlOutputText2.setValueExpression("rendered", JSFUtils.createValueExpression("#{customer.creditLimit gt 25000}", Boolean.class));
 
        // Create RichFaces Columns <rich:column/>
        UIColumn column = (UIColumn) application.createComponent(UIColumn.COMPONENT_TYPE);
        column.setValueExpression("sortBy", JSFUtils.createValueExpression("#{customer.name}", String.class));
        column.setValueExpression("sortOrder", JSFUtils.createValueExpression("#{dataTable1.nameSortOrder}", SortOrder.class));
 
        UIColumn column1 = (UIColumn) application.createComponent(UIColumn.COMPONENT_TYPE);
        column1.setValueExpression("sortBy", JSFUtils.createValueExpression("#{customer.phone}", String.class));
        column1.setValueExpression("sortOrder", JSFUtils.createValueExpression("#{dataTable1.phoneSortOrder}", SortOrder.class));
        column1.setValueExpression("comparator", JSFUtils.createValueExpression("#{dataTable1.phoneComparator}", Comparator.class));
 
        UIColumn column2 = (UIColumn) application.createComponent(UIColumn.COMPONENT_TYPE);
        column2.setValueExpression("sortBy", JSFUtils.createValueExpression("#{customer.creditLimit}", String.class));
        column2.setValueExpression("sortOrder", JSFUtils.createValueExpression("#{dataTable1.creditSortOrder}", SortOrder.class));
        column2.setValueExpression("comparator", JSFUtils.createValueExpression("#{dataTable1.creditComparator}", Comparator.class));
 
        // Assemble Columns and values
        column.setHeader(clink);
        column.getChildren().add(htmlOutputText);
 
        column1.setHeader(clink1);
        column1.getChildren().add(htmlOutputText1);
 
        column2.setHeader(clink2);
        column2.getChildren().add(htmlOutputText2);
 
        // Create Table Header
        UIColumn hcolumn = (UIColumn) application.createComponent(UIColumn.COMPONENT_TYPE);
        hcolumn.setColspan(3);
        HtmlOutputText columnText = (HtmlOutputText) application.createComponent(HtmlOutputText.COMPONENT_TYPE);
        columnText.setValue("Customer Information");
        hcolumn.getChildren().add(columnText);
        UIColumnGroup columnGroup = (UIColumnGroup) application.createComponent(UIColumnGroup.COMPONENT_TYPE);
        columnGroup.getChildren().add(hcolumn);
 
        // Assemble Table
        dataTable.setHeader(columnGroup);
        dataTable.getChildren().add(column);
        dataTable.getChildren().add(column1);
        dataTable.getChildren().add(column2);
 
    }
 
    public UIDataTable getDataTable() {
        return dataTable;
    }
 
    public void setDataTable(UIDataTable dataTable) {
        this.dataTable = dataTable;
    }
 
    public List<customer> getCustomers() {
        return customers;
    }
 
    public SortOrder getNameSortOrder() {
        return nameSortOrder;
    }
 
    public SortOrder getCreditSortOrder() {
        return creditSortOrder;
    }
 
    public SortOrder getPhoneSortOrder() {
        return phoneSortOrder;
    }
 
    /**
     * Customer name sorting enumeration "three position switch":
     * default (unsorted), ascending, and descending.
     */
    public void nsort() {
        creditSortOrder = SortOrder.unsorted;
        phoneSortOrder = SortOrder.unsorted;
 
        switch (nameSortOrder) {
            case unsorted: {
                nameSortOrder = SortOrder.ascending;
                break;
            }
            case ascending: {
                nameSortOrder = SortOrder.descending;
                break;
            }
            case descending: {
                nameSortOrder = SortOrder.unsorted;
                break;
            }
        }
    }
 
    /**
     * Credit limit sorting enumeration "three position switch":
     * default (unsorted), ascending, and descending.
     */
    public void csort() {
        nameSortOrder = SortOrder.unsorted;
        phoneSortOrder = SortOrder.unsorted;
 
        switch (creditSortOrder) {
            case unsorted: {
                creditSortOrder = SortOrder.ascending;
                break;
            }
            case ascending: {
                creditSortOrder = SortOrder.descending;
                break;
            }
            case descending: {
                creditSortOrder = SortOrder.unsorted;
                break;
            }
        }
    }
 
    /**
     * Phone sorting enumeration "three position switch": default
     * (unsorted), ascending, and descending.
     */
    public void psort() {
        nameSortOrder = SortOrder.unsorted;
        creditSortOrder = SortOrder.unsorted;
 
        switch (phoneSortOrder) {
            case unsorted: {
                phoneSortOrder = SortOrder.ascending;
                break;
            }
            case ascending: {
                phoneSortOrder = SortOrder.descending;
                break;
            }
            case descending: {
                phoneSortOrder = SortOrder.unsorted;
                break;
            }
        }
    }
 
    public Comparator<customer> getPhoneComparator() {
 
        return new Comparator<customer>() {
            @Override
            public int compare(Customer o1, Customer o2) {
                return o1.getPhone().compareTo(o2.getPhone());
            }
        };
    }
 
    public Comparator<customer> getCreditComparator() {
        return new Comparator<customer>() {
            @Override
            public int compare(Customer o1, Customer o2) {
                return o1.getCreditLimit().compareTo(o2.getCreditLimit());
            }
        };
    }
 
    /**
     * This method returns the customer name header with the specified sort
     * order based on the current {@link SortOrder}.
     *
     * @return customer name header with the specified sort order.
     */
    public String getCustomerColumnHeader() {
        switch (nameSortOrder) {
            case unsorted: {
                return "Customer Name";
            }
            default: {
                return "Customer Name (" + nameSortOrder + ")";
            }
        }
    }
 
    /**
     * Generates custom formatted USD currency value based on {@code Integer}.
     *
     * @param value The value to be formatted.
     * @return $USD formatted value.
     */
    public String format(Integer value) {
        return String.format("$ %1$,d", value);
    }
}
As you can see we have traded simplicity in the page for complexity in the @ManagedBean. If you are satisfied with this technique, lets take a look at another one.

Dynamic Data Table with Sorting Revisited

Dynamic Table
This table uses the same dynamic binding as the example above on the JSF page, but uses helper utilities to create JSF components dynamically from a library that I have written. It is a separate project that you can download (Please see references). This reduces the chances for errors creating common components, but it is still a lot of code. To check our sorting, I have made a "random" data generator for the table data for the code to sort.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:rich="http://richfaces.org/rich">
    <h:head>
        <title>Dynamic Data Table Design #2</title>
    </h:head>
    <h:body>
        <h1>
Dynamic Data Table Design Design #2</h1>
<p>
            The table is bound to the page backing bean, and is generated dynamically.
  
            Please use the Source and Code links to see the details.
        </p>
<h:form id="form1">
            <rich:dataTable id="dataTable" binding="#{dataTable2.dataTable}"/>
        </h:form>
        <div style="padding-top: 5px;">
            <a href="#{facesContext.externalContext.requestContextPath}">Index</a>
            <a href="#{facesContext.externalContext.requestContextPath}/source/dataTable2.xhtml">Source</a>
            <a href="#{facesContext.externalContext.requestContextPath}/source/resources/src/dataTable2.java">Code</a>
        </div>
</h:body>
</html>

The more simplified code in the @ManagedBean is shown below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package com.bluelotussoftware.example.richfaces;
 
import com.bluelotussoftware.jsf.utils.JSFUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.Application;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import org.richfaces.component.SortOrder;
import org.richfaces.component.UIColumn;
import org.richfaces.component.UICommandLink;
import org.richfaces.component.UIDataTable;
 
/**
 * <p>
Proof of Concept #2 Programmatic RichFaces data table
 * <code><rich:dataTable/></code> with server side sorting</p>
*
 * <p>
<strong>Note:</strong> Please note that the scope must be set to session
 * for the object holding a reference to the bound datatable.</p>
*
 * @author John Yeary
 * @version 1.0
 */
@Named
@SessionScoped
public class DataTable2 implements Serializable {
 
    private static final long serialVersionUID = -2771295649562837525L;
    private SortOrder sorting = SortOrder.unsorted;
    private static final String DATA_TABLE_NAME = "dataTable";
    private UIDataTable dataTable;
 
    public DataTable2() {
    }
 
    @PostConstruct
    private void init() {
        FacesContext context = FacesContext.getCurrentInstance();
        Application application = context.getApplication();
        // ~~~~~~~~~~~~~~~~~~~~ Data Table
        dataTable = (UIDataTable) application.createComponent(UIDataTable.COMPONENT_TYPE);
        dataTable.setVar("v");
        dataTable.setValue(getData());
        UIColumn column0 = createUIColumn(context, "#{v.get(0).value}", String.class, "#{dataTable2.sorting}");
        UIColumn column1 = createUIColumn(context, "#{v.get(1).value}", String.class, "#{dataTable2.sorting}");
        UICommandLink commandLink0 = createUICommandLink(context, "Column 0", DATA_TABLE_NAME, "#{dataTable2.sort()}");
        UICommandLink commandLink1 = createUICommandLink(context, "Column 1", DATA_TABLE_NAME, "#{dataTable2.sort()}");
        HtmlOutputText htmlOutputText0 = createHtmlOutputText(context, "#{v.get(0).value}", String.class);
        HtmlOutputText htmlOutputText1 = createHtmlOutputText(context, "#{v.get(1).value}", String.class);
        column0.setHeader(commandLink0);
        column0.getChildren().add(htmlOutputText0);
        column1.setHeader(commandLink1);
        column1.getChildren().add(htmlOutputText1);
        dataTable.getChildren().add(column0);
        dataTable.getChildren().add(column1);
    }
 
    public SortOrder getSorting() {
        return sorting;
    }
 
    public void setSorting(SortOrder sorting) {
        this.sorting = sorting;
    }
 
    public UIDataTable getDataTable() {
        return dataTable;
    }
 
    public void setDataTable(UIDataTable dataTable) {
        this.dataTable = dataTable;
    }
 
    public void sort() {
        switch (sorting) {
            case unsorted: {
                sorting = SortOrder.ascending;
                break;
            }
            case ascending: {
                sorting = SortOrder.descending;
                break;
            }
            case descending: {
                sorting = SortOrder.unsorted;
                break;
            }
        }
    }
 
    public UICommandLink createUICommandLink(final FacesContext context, final String value, final String render, final String methodExpression) {
        Class<?>[] clazz = new Class<?>[]{};
        UICommandLink link = (UICommandLink) context.getApplication().createComponent(UICommandLink.COMPONENT_TYPE);
        link.setValue(value);
        link.setRender(render);
        link.setActionExpression(JSFUtils.createMethodExpression(methodExpression, String.class, clazz));
        return link;
    }
 
    public UIColumn createUIColumn(final FacesContext context, final String sortByValueExpression, final Class<?> sortByType, final String sortOrderValueExpression) {
        UIColumn column = (UIColumn) context.getApplication().createComponent(UIColumn.COMPONENT_TYPE);
        column.setValueExpression("sortBy", JSFUtils.createValueExpression(sortByValueExpression, sortByType));
        column.setValueExpression("sortOrder", JSFUtils.createValueExpression(sortOrderValueExpression, SortOrder.class));
        return column;
    }
 
    public HtmlOutputText createHtmlOutputText(final FacesContext context, final String valueValueExpression, Class<?> valueType) {
        HtmlOutputText text = (HtmlOutputText) context.getApplication().createComponent(HtmlOutputText.COMPONENT_TYPE);
        text.setValueExpression("value", JSFUtils.createValueExpression(valueValueExpression, valueType));
        return text;
    }
 
    public List<List<valueholder>> getData() {
        List<List<valueholder>> datax = new ArrayList<List<valueholder>>();
 
        for (int i = 0; i < 10; i++) {
            List<ValueHolder> subelement = new ArrayList<valueholder>();
 
            for (int j = 0; j < 10; j++) {
                ValueHolder vh = new ValueHolder(String.format("Row %1$d Element %2$d", i, j));
 
                List<ValueHolder> sub = new ArrayList<valueholder>();
                for (int k = 0; k < 3; k++) {
                    ValueHolder sube = new ValueHolder("SubElement " + k);
 
                    List<ValueHolder> subsub = new ArrayList<valueholder>();
                    for (int l = 0; l < 10; l++) {
                        ValueHolder subx = new ValueHolder("SubSubElement " + l);
                        subsub.add(subx);
                    }
                    sube.setSubValues(subsub);
                    sub.add(sube);
                }
 
                vh.setSubValues(sub);
                subelement.add(vh);
            }
            datax.add(subelement);
        }
 
        Collections.shuffle(datax);
        return datax;
    }
}

The code above was written before I added more functionality to my jsf-utils project. The new methods would shorten this considerably, but it would still be fairly complex.

Dynamic Table using JSP/JSTL Tags with JSF

JSF/JSTL Dynamic Table
Let me start this example with a warning. If you are using JSP/JSTL tags in your JSF pages, you may encounter very bad behavior. This technique should only be used as a last resort. I will not labor a point. If you don't understand why this is a bad idea, take a look at this post for links: JSF 2.x Tip of the Day: Great Blog Posts Explaining JSTL vs. JSF.
In this example, I will generate the rows and columns using <c:forEach />. This transfers a lot of the complexity to the page and away from the @ManagedBean. Since we are using <c:forEach />, our mechanism for sorting has to change. I used Query jquery.tablesorter.js to allow sorting of the headers.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      xmlns:c="http://java.sun.com/jsp/jstl/core"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:rich="http://richfaces.org/rich">
    <h:head>
        <title>Dynamic Data Table Design #3</title>
    </h:head>
    <h:body>
        <h1>
Dynamic Data Table Design Design #3</h1>
<p>
            The table is bound to the page backing bean, and is generated dynamically using <code><c:forEach /></code> to create the column elements.
 
            This technique is not recommended unless you understand the limitations of using JSP/JSTL tags with JSF. This is a good working example of the technique.
 
            This table also uses jQuery <i>jquery.tablesorter.js</i> to allow sorting of the headers. Click on the headers to sort.
        </p>
<p>
            Please use the Source and Code links to see the details.
        </p>
<h:form id="form1">
            <rich:dataTable id="dataTable" value="#{dataTable3.customers}" var="customer"
                            rowKeyVar="idx" styleClass="tablesorter">
                <c:forEach items="#{dataTable3.customerByIndex(idx)}" var="cx">
                    <f:facet name="header">
                        <rich:columnGroup>
                            <rich:column colspan="2">
                                <h:outputText value="Customers"/>
                            </rich:column>
                            <rich:column breakRowBefore="true">
                                <h:outputText value="Name"/>
                            </rich:column>
                            <rich:column>
                                <h:outputText value="Phone"/>
                            </rich:column>
                        </rich:columnGroup>
                    </f:facet>
                    <rich:column>
                        <h:outputText value="#{cx.name}"/>
                        <f:facet name="footer">
                            Number of Customers: #{dataTable3.customers.size()}
                        </f:facet>
                    </rich:column>
                    <rich:column>
                        <h:outputText value="#{cx.phone}"/>
                        <f:facet name="footer"/>
                    </rich:column>
                </c:forEach>
            </rich:dataTable>
            <rich:jQuery/>
            <h:outputScript name="jquery.tablesorter.js" library="js"/>
        </h:form>
        <div style="padding-top: 5px;">
            <a href="#{facesContext.externalContext.requestContextPath}">Index</a>
            <a href="#{facesContext.externalContext.requestContextPath}/source/dataTable3.xhtml">Source</a>
            <a href="#{facesContext.externalContext.requestContextPath}/source/resources/src/dataTable3.java">Code</a>
        </div>
<script type="text/javascript">
            $(document).ready(function() {
                $('#form1\\:dataTable').tablesorter();
            });
        </script>
    </h:body>
</html>
As you can see we have much simpler code in the page bean. It looks like what you would expect for a normal JSF data table.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.bluelotussoftware.example.richfaces;
 
import com.bluelotussoftware.example.richfaces.model.Customer;
import com.bluelotussoftware.example.richfaces.ssb.CustomerFacade;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
 
/**
 * Proof of Concept #3 Client Side Sorting using jQuery TableSorter 2.0
 *
 * @author John Yeary
 * @version 1.0
 */
@Named
@RequestScoped
public class DataTable3 {
 
    private static final long serialVersionUID = -1246509549850361939L;
    private List<customer> customers;
    @EJB
    private CustomerFacade customerFacade;
 
    public DataTable3() {
        customers = new ArrayList<customer>();
    }
 
    @PostConstruct
    private void init() {
        customers.addAll(customerFacade.findAll());
    }
 
    public List<customer> getCustomers() {
        return customers;
    }
 
    /**
     * This method is used by
     * <code><c:forEach/></code>
     * <code>items</code> attribute which requires a {@code Collection}, or an
     * array to iterate over;
     *
     * @param index the {@link Customer} at the index position in the customer
     * list.
     * @return a list containing a single customer at the specified index.
     */
    public List<customer> customerByIndex(final int index) {
        List<customer> customer = new ArrayList<customer>();
        customer.add(customers.get(index));
        return customer;
    }
}

Complex Data Table Design

Complex Table Design
This table has a lot of really cool features, but the code is complex in the page, and the page bean is relatively simple.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      xmlns:a4j="http://richfaces.org/a4j"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:rich="http://richfaces.org/rich">
    <h:head>
        <title>Complex Data Table Design</title>
    </h:head>
    <h:body>
        <h:form id="form1">
            <h1>
Complex Data Table Design</h1>
<p>
                This example demonstrates how to use the <code><rich:columnGroup /></code> tag, along with Expression Language (EL)
 
                formatting of column output. It also demonstrates how to use AJAX sorting of the customer name.
            </p>
<p>
                Please use the Source and Code links to see the details.
            </p>
<rich:dataTable id="dataTable" value="#{complexDataTable.customers}" var="customer">
                <f:facet name="header">
                    <rich:columnGroup>
                        <rich:column colspan="6">
                            <h:outputText value="Customers"/>
                        </rich:column>
                        <rich:column breakRowBefore="#{true}" rowspan="2" colspan="2"/>
                        <rich:column colspan="2">
                            <h:outputText value="Address"/>
                        </rich:column>
                        <rich:column>
                            <h:outputText value="Contact Information"/>
                        </rich:column>
                        <rich:column rowspan="2">
                            <h:outputText value="Credit Limit" />
                        </rich:column>
                        <rich:column breakRowBefore="#{true}">
                            <h:outputText value="City"/>
                        </rich:column>
                        <rich:column>
                            <h:outputText value="State"/>
                        </rich:column>
                        <rich:column>
                            <h:outputText value="Phone"/>
                        </rich:column>
                    </rich:columnGroup>
                </f:facet>
                <rich:column>
                    <f:facet name="header">
                        <h:outputText value="Sales Code Word"/>
                    </f:facet>
                    <h:outputText rendered="#{customer.creditLimit eq 50000
                                              || customer.creditLimit eq 70000
                                              || customer.creditLimit eq 90000}"
                                  value="Partner"/>
                    <h:outputText rendered="#{customer.creditLimit eq 5000000}"
                                  value="Head Kahuna"/>
                    <h:outputText rendered="#{customer.creditLimit eq 100000}"
                                  value="Big Tuna"/>
                </rich:column>
                <rich:column sortBy="#{customer.name}" sortOrder="#{complexDataTable.sorting}">
                    <f:facet name="header">
                        <a4j:commandLink render="dataTable" value="#{complexDataTable.customerColumnHeader}" action="#{complexDataTable.sort()}"/>
                    </f:facet>
                    <h:outputText value="#{customer.name}"/>
                </rich:column>
                <rich:column>
                    <h:outputText value="#{customer.city}"/>
                </rich:column>
                <rich:column>
                    <h:outputText value="#{customer.state}"/>
                </rich:column>
                <rich:column>
                    <h:outputText value="#{customer.phone}"/>
                </rich:column>
                <rich:column>
                    <h:outputText value="#{complexDataTable.format(customer.creditLimit)}"/>
                </rich:column>
            </rich:dataTable>
        </h:form>
        <div style="padding-top: 5px;">
            <a href="#{facesContext.externalContext.requestContextPath}">Index</a>
            <a href="#{facesContext.externalContext.requestContextPath}/source/complexLayout.xhtml">Source</a>
            <a href="#{facesContext.externalContext.requestContextPath}/source/resources/src/complexDataTable.java">Code</a>
        </div>
</h:body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package com.bluelotussoftware.example.richfaces;
 
import com.bluelotussoftware.example.richfaces.model.Customer;
import com.bluelotussoftware.example.richfaces.ssb.CustomerFacade;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import org.richfaces.component.SortOrder;
 
/**
 * Proof of Concept #4 Complex layout table with server side sorting on single
 * column.
 *
 * @author John Yeary
 * @version 1.0
 */
@Named
@SessionScoped
public class ComplexDataTable implements Serializable {
 
    private static final long serialVersionUID = -5343878110987753773L;
    private List<customer> customers;
    @EJB
    private CustomerFacade customerFacade;
    private SortOrder sorting = SortOrder.unsorted;
 
    public ComplexDataTable() {
        customers = new ArrayList<customer>();
    }
 
    @PostConstruct
    private void init() {
        customers.addAll(customerFacade.findAll());
    }
 
    public List<customer> getCustomers() {
        return Collections.unmodifiableList(customers);
    }
 
    public SortOrder getSorting() {
        return sorting;
    }
 
    /**
     * Sorting enumeration "three position switch": default
     * (unsorted), ascending, and descending.
     */
    public void sort() {
        switch (sorting) {
            case unsorted: {
                sorting = SortOrder.ascending;
                break;
            }
            case ascending: {
                sorting = SortOrder.descending;
                break;
            }
            case descending: {
                sorting = SortOrder.unsorted;
                break;
            }
        }
    }
 
    /**
     * This method returns the customer name header with the specified sort
     * order based on the current {@link SortOrder}.
     *
     * @return customer name header with the specified sort order.
     */
    public String getCustomerColumnHeader() {
        switch (sorting) {
            case unsorted: {
                return "Customer Name";
            }
            default: {
                return "Customer Name (" + sorting + ")";
            }
        }
    }
 
    /**
     * Generates custom formatted USD currency value based on {@code Integer}.
     *
     * @param value The value to be formatted.
     * @return $USD formatted value.
     */
    public String format(Integer value) {
        return String.format("$ %1$,d", value);
    }
}

Conclusion

RichFaces supports complex table designs, and produces nice results. The amount of work required to create dynamic data tables depends on the technique chosen, and limitations on the data being presented. There is no "one good way" to create data tables. Suffice to say that the easiest path should be chosen.

References

SourceServlet: Displaying the Source Code and Pages from a Project on your Blog

SourceServlet
I had been working on a way to create nice examples that include a way to display the page and source code for it. I created a servlet that will display the code as plain text that I would like to share with all of you.

SourceServlet.java


package com.bluelotussoftware.example.richfaces;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* A servlet that displays XHTML/Java Source code as plain text from the project
* in which the servlet is included.
*
* @author John Yeary
* @version 1.0
*/
@WebServlet(name = "SourceServlet", urlPatterns = {"/source/*"})
public class SourceServlet extends HttpServlet {
private static final long serialVersionUID = 3859447979763694232L;
/**
* Processes requests for both HTTP
* <code>GET</code> and
* <code>POST</code> methods.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String basePath = getServletContext().getRealPath("/");
if (request.getPathInfo() == null || "/".equals(request.getPathInfo())) {
//NOI18N
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "An file name is required.");
return;
}
String filename = URLDecoder.decode(request.getPathInfo(), "UTF-8");
File file = new File(basePath, filename);
if (!file.exists()) {
//NOI18N
response.sendError(HttpServletResponse.SC_NOT_FOUND, file.getName() + " was not found.");
return;
}
response.setContentType("text/plain");
response.setContentLength((int) file.length());
response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(file));
output = new BufferedOutputStream(response.getOutputStream());
byte[] buffer = new byte[8192];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} finally {
if (output != null) {
try {
output.close();
} catch (IOException ignore) {
}
}
if (input != null) {
try {
input.close();
} catch (IOException ignore) {
}
}
}
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP
* <code>GET</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP
* <code>POST</code> method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "This servlet will serve source code from a project as text/plain.";
}// </editor-fold>
}

Sunday, January 19, 2014

JSF 2.x: Nested Templates, Decorators, Fragments, and Includes

Ugly for Illustrative Purpose
I was looking at some JSF pages that I had been playing with to see about using decorators, fragments, etc. I thought someone might find it instructional, so I thought I would publish it before deleting the project. It demonstrates using a combination of methods to composite a JSF page into a cohesive unit.

DecoratedPage.xhtml


1
2
3
4
5
6
7
8
9
10
11
12
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <h:head>
        <title>Decorated Table</title>
    </h:head>
    <h:body>
         <ui:include src="decoratedTable.xhtml"/>
    </h:body>
</html

decoratedTable.xhtml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version='1.0' encoding='UTF-8' ?>
       xmlns:ui="http://java.sun.com/jsf/facelets" border="1" bgcolor="salmon" width="50%" align="center">
    <caption>
        This is a decorated table.
    </caption>
<tr>
        <td>
            <ui:decorate template="unorderedListTemplate.xhtml">
                <ui:define name="content">
                    <ui:include src="listElements.xhtml"/>
                </ui:define>
            </ui:decorate>
        </td>
    </tr>
</table>

unorderedListTemplate.xhtml


1
2
3
4
5
6
<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
             xmlns:ui="http://java.sun.com/jsf/facelets">
    <ul>
        <ui:insert name="content">Content</ui:insert>
    </ul>
</ui:fragment

listElements.xhtml


1
2
3
4
5
6
7
8
9
<?xml version='1.0' encoding='UTF-8' ?>
<ui:fragment xmlns="http://www.w3.org/1999/xhtml"
             xmlns:h="http://java.sun.com/jsf/html"
             xmlns:ui="http://java.sun.com/jsf/facelets">
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ui:fragment

JSF 2.x Tip of the Day: Custom JSF AJAX Error Handling on Client

Introduction

One of the holes in JSF, in my professional judgement, is the lack of really good exception handling on the client for AJAX exceptions. A number of client frameworks like PrimeFaces, OmniFaces, and RichFaces attempt to cleanup for this shortcoming, it is still a deficiency.

The capabilities are present to make AJAX exception handling more robust. The "chemistry" is present in the framework, but it is not really standardized.

In this short example, I am demonstrating how to use the jsf.ajax.addOnError functionality to make client exception handling better. We will display at a minimum, an alert to let them know something bad has happened to their request.

Additionally, I will demonstrate how to use XPath to get additional information from the response.

Solution

The solution is to add the following code to the <head />: of the JSF page, or to an external JavaScript file that is included in the head. In my case, I am using an external JS file called jsf.ajax.handler.js that is loaded using JSF <h:outputScript />.
1
<h:outputScript library="js" target="head" name="jsf.ajax.handler.js"/>

Here are the contents of the file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 * Copyright 2012-2014 John Yeary <jyeary@bluelotussoftware.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
jsf.ajax.addOnError(function(data) {
    // This shows how to get the information via XPath, but it is not required. The error name can be found using data.errorName
    var errorName = data.responseXML.evaluate('//error/error-name', data.responseXML, null, XPathResult.STRING_TYPE, null);
    var message = 'AJAX Exception';
    message += '\nSource: ' + data.source.id;
    message += '\nValue:' + data.source.value;
    message += '\nError: ' + errorName.stringValue;
    message += '\nMessage: ' + data.errorMessage;
    alert(message);
    //TODO Take Additional actions
});
 
jsf.ajax.addOnEvent(function(data) {
    alert(data.source.id + " " + data.type + " " + data.status);
});

References

JSF 2.2.x Tip of the Day: Custom JSF Exception Page including the default Facelets Exception Page

If you want to create a custom exception page in JSF and include the default exception page, you simply need to include one line of code.
1
<ui:include src="javax.faces.error.xhtml" />

This is an example of a custom exception page using the code above.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    <h:head>
        <title>Custom Exception</title>
        <style type="text/css">
            h1{color: red;}
            span{font-weight: bold;}
        </style>
    </h:head>
    <h:body
        <h1>
Custom Exception</h1>
<ul>
<li id="dte"><span>Date/Time:</span> </li>
<li><span>User Agent:</span> #{header['user-agent']}</li>
<li><span>User IP:</span> #{empty header['x-forwarded-for'] ? request.remoteAddr : fn:split(header['x-forwarded-for'], ',')[0]}</li>
<li><span>Request URI:</span> <a href="#{requestScope['javax.servlet.error.request_uri']}">#{requestScope['javax.servlet.error.request_uri']}</a></li>
<li><span>Ajax Request:</span> #{facesContext.partialViewContext.ajaxRequest ? 'Yes' : 'No'}</li>
<li><span>Status Code:</span> #{requestScope['javax.servlet.error.status_code']}</li>
<li><span>Exception Type:</span> #{requestScope['javax.servlet.error.exception_type']}</li>
<li><span>Exception Message:</span> #{requestScope['javax.servlet.error.message']}</li>
</ul>
<ui:include src="javax.faces.error.xhtml" />
 
        <script type="text/javascript">
            window.onload = function() {
                document.getElementById('dte').innerHTML += (new Date()).toUTCString();
            };
        </script>
    </h:body>
</html>

The resulting page will look like the image below. Please note that we are including the default JSF exception page.

Saturday, January 18, 2014

Java EE Tip of the Day: @WebFilter (Servlet Filter) Redirection

There is a common case to check a condition in a filter, and if the condition is not satisfied to redirect back to the context root of the application. This may be the case in a login filter, or a filter that performs some session management.

Here is a simple code example of how to perform the redirection:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
 
    //TODO perform conditional check here
    if (check()) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        String url = httpServletResponse.encodeRedirectURL(httpServletRequest.getContextPath());
        httpServletResponse.sendRedirect(url);
    } else {
        chain.doFilter(request, response);
    }
}

HOWTO: Adding SyntaxHighlighter to Blogger

If you want to use SyntaxHighlighter in your blog, you can simply add the code below to the <head /> element in the template for your Blogger blog.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!-- BEGIN SyntaxHighlighter BEGIN -->
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCoreDefault.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/>
<script language='javascript' type='text/javascript'>
    SyntaxHighlighter.config.bloggerMode = true;
    SyntaxHighlighter.all();
 </script>
<!-- END SyntaxHighlighter END -->

JSF 2.x Tip of the Day: Redirecting to the context path with parameters

This is just a quick code example that demonstrates how to do a redirect to the Servlet context path with parameters.

1
2
3
4
5
6
7
public String redirect(Map<String, List<string>> parameters) throws IOException {
    FacesContext fc = FacesContext.getCurrentInstance();
    ExternalContext ec = fc.getExternalContext();
    ec.redirect(ec.encodeRedirectURL(ec.getRequestContextPath(), parameters));
    fc.responseComplete();
    return null;
}
The code above will correctly format parameters to be passed as part of the redirection.

Here is an example using bogus parameters.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public Map<String, List<string>> getParameters() {
    Map<String, List<string>> map = new HashMap<>();
 
    map.put("Alpha", new ArrayList<string>() {
        {
            add("A");
        }
    });
 
    map.put("Beta", new ArrayList<string>() {
        {
            add("B");
        }
    });
    map.put("Gamma", new ArrayList<string>() {
        {
            add("G");
        }
    });
    map.put("Delta", new ArrayList<string>() {
        {
            add("D");
        }
    });
    map.put("Epsilon", new ArrayList<string>() {
        {
            add("E");
        }
    });
 
    return map;
}


Here is the JSF Form I used to generate the output below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>Redirect</title>
    </h:head>
    <h:body>
        <h1>Redirect</h1>
        <h:form>
            <h:commandButton action="#{utils.redirect(utils.parameters)}" value="Redirect with Parameters"/>
        </h:form>
    </h:body>
</html>

Friday, January 17, 2014

GlassFish 4 Tip of the Day: Removing Expired GTE CyberTrust Solution Certificate

Problem

Have you seen this ugly warning message in your logs, or NetBeans IDE?

Do you want to get rid of it?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
SEVERE:   SEC5054: Certificate has expired: [
[
  Version: V3
  Subject: CN=GTE CyberTrust Root 5, OU="GTE CyberTrust Solutions, Inc.", O=GTE Corporation, C=US
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
  Key:  Sun RSA public key, 2048 bits
  modulus: 23741889829347261660812437366387754385443431973861114865490414153884050331745811968523116847625570146592736935209718565296053386842135985534863157983128812774162998053673746470782252407673402238146869994438729551246768368782318393878374421033907597162218758024581735139682087126982809511479059100617027892880227587855877479432885604404402435662802390484099065871430585284534529627347717530352189612077130606642676951640071336717026459037542552927905851171460589361570392199748753414855675665635003335769915908187224347232807336022456537328962095005323382940080676931822787496212635993279098588863972868266229522169377
  public exponent: 65537
  Validity: [From: Fri Aug 14 10:50:00 EDT 1998,
               To: Wed Aug 14 19:59:00 EDT 2013]
  Issuer: CN=GTE CyberTrust Root 5, OU="GTE CyberTrust Solutions, Inc.", O=GTE Corporation, C=US
  SerialNumber: [    01b6]
Certificate Extensions: 4
[1]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen:5
]
[2]: ObjectId: 2.5.29.32 Criticality=false
CertificatePolicies [
  [CertificatePolicyId: [1.2.840.113763.1.2.1.3]
[]  ]
]
[3]: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  Key_CertSign
  Crl_Sign
]
[4]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 76 0A 49 21 38 4C 9F DE   F8 C4 49 C7 71 71 91 9D  v.I!8L....I.qq..
]
]
]
  Algorithm: [SHA1withRSA]
  Signature:
0000: 41 3A D4 18 5B DA B8 DE   21 1C E1 8E 09 E5 F1 68  A:..[...!......h
0010: 34 FF DE 96 F4 07 F5 A7   3C F3 AC 4A B1 9B FA 92  4.......<..J....
0020: FA 9B ED E6 32 21 AA 4A   76 C5 DC 4F 38 E5 DF D5  ....2!.Jv..O8...
0030: 86 E4 D5 C8 76 7D 98 D7   B1 CD 8F 4D B5 91 23 6C  ....v......M..#l
0040: 8B 8A EB EA 7C EF 14 94   C4 C6 F0 1F 4A 2D 32 71  ............J-2q
0050: 63 2B 63 91 26 02 09 B6   80 1D ED E2 CC B8 7F DB  c+c.&...........
0060: 87 63 C8 E1 D0 6C 26 B1   35 1D 40 66 10 1B CD 95  .c...l&.5.@f....
0070: 54 18 33 61 EC 13 4F DA   13 F7 99 AF 3E D0 CF 8E  T.3a..O.....>...
0080: A6 72 A2 B3 C3 05 9A C9   27 7D 92 CC 7E 52 8D B3  .r......'....R..
0090: AB 70 6D 9E 89 9F 4D EB   1A 75 C2 98 AA D5 02 16  .pm...M..u......
00A0: D7 0C 8A BF 25 E4 EB 2D   BC 98 E9 58 38 19 7C B9  ....%..-...X8...
00B0: 37 FE DB E2 99 08 73 06   C7 97 83 6A 7D 10 01 2F  7.....s....j.../
00C0: 32 B9 17 05 4A 65 E6 2F   CE BE 5E 53 A6 82 E9 9A  2...Je./..^S....
00D0: 53 0A 84 74 2D 83 CA C8   94 16 76 5F 94 61 28 F0  S..t-.....v_.a(.
00E0: 85 A7 39 BB D7 8B D9 A8   B2 13 1D 54 09 34 24 7D  ..9........T.4$.
00F0: 20 81 7D 66 7E A2 90 74   5C 10 C6 BD EC AB 1B C2   ..f...t\.......
]

Solution

The technique to remove it is quite simple if you are using a basic GlassFish installation. This is a combination of posts from the resources listed in the references below.
  1. Go to the ${GLASSFISH_INSTALLATION_DIRECTORY}/glassfish/domains/domain1/config/ directory. You will need to repeat this if you have multiple domains.
  2. Execute the following command:
    1
    2
    3
    $ keytool -delete -v -alias gtecybertrust5ca -keystore cacerts.jks
    Enter keystore password:  changeit
    [Storing cacerts.jks]
  3. Restart server, and the expired certificate warning will disappear.

References

Thursday, January 16, 2014

How do you cancel a scheduled Thread in an ExecutorService?

Executors in the Middle Ages
Humm... I thought...

I was asked this question a while ago, and I came up with a quick solution since it was just a general question. I went back and cleaned up my example which uses Callable and Future to demonstrate the concurrency libraries in Java.

In the example, I use a ExecutorService with a fixed thread pool size of two (2), to make the code slower to demonstrate the point. You can manipulate the value to see the effect on the code execution.

The code is to demonstrate you can do it,  there may be other cleaner ways of doing this. If you have an example, or idea on how to do it cleaner, please comment. :-)

Solution

The code for the project was developed using NetBeans and can be downloaded from Bitbucket at the link below. It is a NetBeans (Apache Ant) based project and should work with Ant without NetBeans.

CallOrderCancel

CallOrderCancel.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package com.bluelotussoftware.example.concurrency;
 
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
 
/**
 *
 * @author John Yeary
 * @version 1.0
 */
public class CallOrderCancel {
 
    private static final ExecutorService es;
 
    static {
        es = Executors.newFixedThreadPool(2);
    }
    static List<Future<string>> futures = new ArrayList<>();
 
    /**
     * @param args the command line arguments
     * @throws java.lang.InterruptedException
     * @throws java.util.concurrent.ExecutionException
     */
    public static void main(String[] args) throws InterruptedException, ExecutionException {
 
        Collection<Callable<string>> callables = new ArrayList<>();
 
        for (int i = 0; i < 15; i++) {
            callables.add(new MyCallable(i));
        }
 
        for (Callable<String> cx : callables) {
            futures.add(es.submit(cx));
        }
 
        Thread.sleep(1000);
 
        for (Future<string> f : futures) {
 
            if (!f.isDone()) {
                f.cancel(true);
                System.out.println("Cancelled... " + f.isCancelled());
            } else {
                System.out.println("message -> " + f.get());
            }
        }
 
        es.shutdown();
    }
 
    static class MyCallable implements Callable<string> {
 
        private final int id;
 
        public MyCallable(int id) {
            this.id = id;
        }
 
        @Override
        public String call() throws Exception {
            String message = "Callable ID: " + id + " count:";
            AtomicInteger ctr = new AtomicInteger();
            synchronized (this) {
                while (true) {
                    wait(100);
                    if (ctr.incrementAndGet() == 5) {
                        break;
                    }
 
                }
            }
            return message + " " + ctr.get();
        }
    }
}

Tuesday, January 14, 2014

Unit Testing Example with Code Coverage using Cobertura

Cobertura Coverage in NetBeans 7.4
I gave a presentation on unit testing a few months ago at Greenville Java Users Group (GreenJUG) about unit testing using JUnit and Cobertura. I finally have gotten around to publishing the code with a little cleanup.

NetBeans will detect the addition of Cobertura in the POM file and automatically add menu items for checking code coverage. This is a very slick feature in NetBeans.

The Cobertura coverage shows 90% in the project because it does not handle the generics correctly at this time.

The Apache Maven based project can be downloaded from Bitbucket below:

unit-testing-demo

Here is an example snippet of the code.

ListDataStoreImplTest.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package com.bluelotussoftware.junit;
 
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
 
/**
 *
 * @author John Yeary
 * @version 1.0
 */
public class ListDataStoreImplTest {
 
    public ListDataStoreImplTest() {
    }
 
    @Test
    public void testConstuctor() {
        System.out.println("Constructor test");
        List<string> list = new ArrayList<string>() {
            private static final long serialVersionUID = 3109256773218160485L;
 
            {
                add("Hello");
                add("World");
            }
        };
 
        ListDataStore<string> instance = new ListDataStoreImpl(list);
        assertEquals(list.get(0), instance.getData().get(0));
        assertEquals(list.get(1), instance.getData().get(1));
        assertEquals(list, instance.getData());
        assertEquals(2, instance.getData().size());
    }
 
    @Test
    public void objectTest() {
        System.out.println("Generic Object test");
        List list = new ArrayList() {
            private static final long serialVersionUID = 3109256773218160485L;
 
            {
                add("Hello");
                add("World");
            }
        };
 
        ListDataStore instance = new ListDataStoreImpl(list);
        assertEquals(list.get(0), instance.getData().get(0));
        assertEquals(list.get(1), instance.getData().get(1));
        assertEquals(list, instance.getData());
        assertEquals(2, instance.getData().size());
    }
 
    /**
     * Test of getData method, of class ListDataStoreImpl.
     */
    @Test
    public void testGetData() {
        // Check #1 - Check the new datastore.
        System.out.println("getData");
        ListDataStoreImpl instance = new ListDataStoreImpl();
        List expResult = new ArrayList();
        List result = instance.getData();
        assertEquals(expResult, result);
 
        // Check #2 - Check the list. Mockito is overkill, but works.
        instance.add("ABC");
        List l = mock(List.class);
        when(l.get(0)).thenReturn("ABC");
        assertEquals(l.get(0), instance.getData().get(0));
 
        // Check #3 - Check to make sure that the list size is correct.
        assertEquals(1, instance.getData().size());
    }
 
    /**
     * Test of add method, of class ListDataStoreImpl.
     */
    @Test
    public void testAdd() {
        System.out.println("add");
        String element = "ABC";
        ListDataStoreImpl instance = new ListDataStoreImpl();
        boolean expResult = true;
        boolean result = instance.add(element);
        assertEquals(expResult, result);
    }
 
    /**
     * Test of remove method, of class ListDataStoreImpl.
     */
    @Test
    public void testRemoveEmpty() {
        System.out.println("remove");
        String element = "ABC";
        ListDataStoreImpl instance = new ListDataStoreImpl();
        boolean expResult = false;
        boolean result = instance.remove(element);
        assertEquals(expResult, result);
    }
 
    @Test
    public void testRemove() {
        System.out.println("remove");
        String element = "ABC";
        ListDataStoreImpl instance = new ListDataStoreImpl();
        instance.add(element);
        boolean expResult = true;
        boolean result = instance.remove(element);
        assertEquals(expResult, result);
    }
}

Friday, January 10, 2014

JSF 2.2.x Expression Language (EL) Delimiting { } in nested EL

Introduction

I was working on possible updates for our application to use JavaServer Faces 2.2 with Manfred Riem from Oracle. I mentioned that I was had tried to update to 2.2.3, but encountered an exception from EL that indicated that the statements were unbalanced. I didn't have time at that point to figure out what the issue was. It was annoying that the switch from 2.1 to 2.2 would cause such an issue, but I thought I would figure it out later. Later arrived...

There is an issue JAVASERVERFACES-2977 : Components get rendered twice we encountered that occurred when we tried to upgrade to 2.1.26. It was fixed in 2.2.5, but needs to be backported to 2.1.x branch. You can get around the issue by using 2.1.21, but Manfred suggested using JSF 2.2. I decided to give it another try, but I am also aware that I am trying to run it on an EE 6 container not EE 7. This is not an issue in the sense that the technology works, but it is not on a support matrix.

Issue

Fast forward, the EL issue appeared again. Manfred and I looked at the issue and it has the following code signature:

1
"#{abc:method('ABC$XYZ(current{QUANTITY})',bean.property)}"
or this in a more shortened form.
1
"#{'{}'}"

Manfred and I tried a number of solutions, one of which seemed to work. However, after further examination it failed to work too.
The troubling part is that existing code running on JSF 2.0, and 2.1 on Weblogic worked fine. I began to look a little deeper. I really want our application to run JSF 2.2 on the latest build. I created a simple project to work out how to delimit the EL which was causing a problem. The project can be downloaded below, or in the references section.

Code: jsf-el-delimiting
When I deployed the project to my GlassFish 4.0 server, it worked! I was really surprised. I went back to my modified GlassFish 3.1.2.2 instance which had JSF 2.2.4 running on it. It failed. So I realized that there was an issue introduced between 2.2.0 and 2.2.4. I later checked with 2.2.5 and found the same issue. I began the process of tracking down where the issue began. It looks like it started on 2.2.2.
JSF Version Passed
2.2.0 OK
2.2.1 OK
2.2.2 FAIL
2.2.3 FAIL
2.2.4 FAIL
2.2.5 FAIL

SOLUTION

The interim solution until the JIRA issue listed in the references is resolved, you can use JSF 2.2.0, or 2.2.1 in your project.

References

Popular Posts