Thursday, April 25, 2013

JSF Tip of the Day: Reading Authorization Header in JSF

After I did the JAX-RS Tip of the Day today, I wondered about reading the authorization header from JSF. The technique is the same as the JAX-RS version, but the methods are different depending on what is available to the JSF application. The JAX-RS Base64 class is not part of the web profile in Java EE 6. It will be part of Java EE 7 so you could use it. I chose to add the comments in the code below, but decided that I would use the com.sun.misc.Base64Decoder which is currently available in Java SE 6 and 7.
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
/**
  * This method examines the request headers for an authorization header. If
  * the header is found, this will return the base64 decoded values of the
  * username, and password.  
  *
  * @param facesContext The context to get the request headers from.  
  * @return an array containing the username and password, or {@code null}.  
  * @throws IOException if the authorization header can not be parsed.  
  */
 public String[] getAuthorization(final FacesContext facesContext) throws IOException {
     String[] decoded = null;
     ExternalContext ec = facesContext.getExternalContext();
     Map<String, String> map = ec.getRequestHeaderMap();
     String authorization = map.get("authorization");
 
     if (authorization != null && !authorization.isEmpty()) {
         // There is a space between "Basic" and the Base 64 encoded string.
         authorization = authorization.substring("Basic ".length());
         /*
          * This would work if JAX-RS (Jersey) was available, but it is not part of
          * Web Profile in EE 6, but will work in EE 7 since JAX-RS 2.0
          * is part of the profile.
          */
         // decoded = Base64.base64Decode(authorization).split(":");
 
         /*
          * This mechanism relies on sun.misc.BASE64Decoder that is an internal
          * proprietary API and may be removed in a future release.
          */
         // decoded = new String(new BASE64Decoder().decodeBuffer(authorization)).split(":");
 
         /*
          * This method uses a class from the Java API for XML Binding (JAXB) to parse. This is
          * available in Java EE 5 and 6.
          */
         decoded = new String(DatatypeConverter.parseBase64Binary(authorization), "UTF-8").split(":");
     }
     return decoded;
 }
UPDATE: I got a suggestion on Google+ from +Thomas Darimont who mentioned using DatatypeConverter.parseBase64Binary() from the Java API for XML Binding (JAXB). I confirmed that it is available in Java EE 5 and 6. It is also in the Web Profile in Java EE 6.

JAX-RS Tip of the Day: How Do I Read the Authorization Header?

I was looking for a simple method to read the HttpHeaders to determine the username and password for a request. I didn't find a quick answer so I wrote a simple utility method that will return the Base 64 decoded values from the authorization header.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * This method examines the request {@link HttpHeaders} for an authorization
 * header. If the header is found, this will return the base64 decoded
 * values of the username, and password.
 *
 * @param headers The headers to be examined.
 * @return an array containing the username and password, or {@code null} if
 * the authorization header was not present.
 */
public String[] getAuthorization(HttpHeaders headers) {
    String[] decoded = null;
    List<String> header = headers.getRequestHeader("authorization");
    if (header != null) {
        String authorization = header.get(0);
        // There is a space between "Basic" and the Base 64 encoded string.
        authorization = authorization.substring("Basic ".length());
        decoded = Base64.base64Decode(authorization).split(":");
    }
    return decoded;
}

Thursday, April 11, 2013

JSF 2.x Tip of the Day: RichFaces 4.3.x Charts in JSF using JSFlot, JFreeCharts, and PrimeFaces

Sexy PrimeFaces Charts in RichFaces

Introduction

I was asked to look at various charting solutions for JSF. Specifically, I was asked for some choices for use with RichFaces 4.3.1. I knew that PrimeFaces has really good chart components already so I knew it might be kind of fun to integrate them if possible. I was also aware of JFreeChart which will work, but produces some... rather ugly charts. Finally, someone had suggested that I look at jsflot. This was a very promising solution. This project is a proof of concept which demonstrates integration between projects, and technologies.

Requirements

  • jsflot
  • NetBeans This is required for the sample database, although you could create your own data.
The jsflot framework is currently not Mavenized, so if you are going to run my example code, you will need to download it from the link above, and install it in Maven using the command below.
1
mvn install:install-file -Dfile=jsflot-0.7.0.jar -DgroupId=org.jsflot -DartifactId=jsflot -Dversion=0.7.0 -Dpackaging=jar -Dsource=jsflot-0.7.0-src.zip

Code

The code for this NetBeans Maven project can be found on BitBucket here: chart-demo

This is the bean that provides the data models for the charting solutions. There are a number of chart demos in the project. The two charts above are just examples.

ChartBean.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
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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
package com.bluelotussoftware.example.jsf;
 
import com.bluelotussoftware.example.model.Customer;
import com.bluelotussoftware.example.model.Product;
import com.bluelotussoftware.example.model.PurchaseOrder;
import com.bluelotussoftware.example.ssb.CustomerFacade;
import com.bluelotussoftware.example.ssb.ProductFacade;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.imageio.ImageIO;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.jsflot.components.FlotChartRendererData;
import org.jsflot.xydata.XYDataList;
import org.jsflot.xydata.XYDataPoint;
import org.jsflot.xydata.XYDataSetCollection;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;
import org.primefaces.model.chart.BubbleChartModel;
import org.primefaces.model.chart.BubbleChartSeries;
import org.primefaces.model.chart.CartesianChartModel;
import org.primefaces.model.chart.ChartSeries;
import org.primefaces.model.chart.MeterGaugeChartModel;
import org.primefaces.model.chart.PieChartModel;
 
/**
 *
 * @author John Yeary
 * @version 1.0
 */
@ManagedBean
@RequestScoped
public class ChartBean {
 
    private Map<Integer, Map<String, Number>> CustomerPurchasesByYearTotals = new HashMap<Integer, Map<String, Number>>();
    private double totalSales;
    //PrimeFaces
    private PieChartModel pieChartModel;
    private CartesianChartModel cartesianChartModel;
    private BubbleChartModel bubbleChartModel;
    private MeterGaugeChartModel meterGaugeChartModel;
    //JSFlot
    private XYDataList series1DataList = new XYDataList();
    private XYDataList series2DataList = new XYDataList();
    private XYDataList series3DataList = new XYDataList();
    private FlotChartRendererData chartData;
    private StreamedContent streamedContent;
    @EJB
    private CustomerFacade cf;
    @EJB
    private ProductFacade pf;
 
    /**
     * Creates a new instance of ChartBean
     */
    public ChartBean() {
    }
 
    @PostConstruct
    private void initialize() throws IOException {
        bubbleChartModel = new BubbleChartModel();
        cartesianChartModel = new CartesianChartModel();
        pieChartModel = new PieChartModel(getSalesByCustomer());
        createCartesianChartModel();
        createBubbleModel();
        createMeterGaugeModel();
 
        //JFreeChart 
        JFreeChart jfreechart = ChartFactory.createPieChart("Products", getPartsDataset(), true, false, false);
        String path = FacesContext.getCurrentInstance().getExternalContext().getRealPath("/");
        File chartFile = new File(path + "dynamichart.png");
        ChartUtilities.saveChartAsPNG(chartFile, jfreechart, 600, 400);
        streamedContent = new DefaultStreamedContent(new FileInputStream(chartFile), "image/png");
 
 
        chartData = new FlotChartRendererData();
 
        for (int i = 0; i <= 100; i++) {
            NumberFormat nf = NumberFormat.getNumberInstance();
            nf.setMaximumFractionDigits(3);
 
            series1DataList.addDataPoint(new XYDataPoint(i, Math.random() * 10, "Point: " + i));
            series2DataList.addDataPoint(new XYDataPoint(i, Math.random() * 10, "Point: " + i));
            series3DataList.addDataPoint(new XYDataPoint(i, Math.random() * 10));
        }
        series1DataList.setLabel("Series 1");
        series2DataList.setLabel("Series 2");
        series3DataList.setLabel("Series 3");
    }
 
    public PieChartModel getPieChartModel() {
        return pieChartModel;
    }
 
    public BubbleChartModel getBubbleChartModel() {
        return bubbleChartModel;
    }
 
    public CartesianChartModel getCartesianChartModel() {
        return cartesianChartModel;
    }
 
    public MeterGaugeChartModel getMeterGaugeChartModel() {
        return meterGaugeChartModel;
    }
 
    private Map<String, Number> getSalesByCustomer() {
        Map<String, Number> salesByCustomer = new HashMap<String, Number>();
 
        List<customer> customers = cf.findAll();
 
        for (Customer c : customers) {
            double sales = 0.0;
            for (PurchaseOrder p : c.getPurchaseOrderCollection()) {
                sales += p.getProductId().getPurchaseCost().doubleValue() * p.getQuantity();
            }
            salesByCustomer.put(c.getName(), sales);
        }
        return salesByCustomer;
    }
 
    private void createCartesianChartModel() {
        Calendar cal = Calendar.getInstance();
        List<customer> customers = cf.findAll();
        List<integer> customersLessThan10K = new ArrayList<integer>();
        List<integer> customersGreaterThan10K = new ArrayList<integer>();
        Collections.sort(customers);
 
        for (Customer c : customers) {
            double sales = 0.0;
 
            for (PurchaseOrder p : c.getPurchaseOrderCollection()) {
                cal.setTime(p.getSalesDate());
                double vx = p.getProductId().getPurchaseCost().doubleValue() * p.getQuantity();
                addOrUpdate(c.getCustomerId(), String.valueOf(cal.get(Calendar.YEAR)), vx);
                sales += vx;
            }
 
            if (sales < 10000.00) {
                customersLessThan10K.add(c.getCustomerId());
            } else {
                customersGreaterThan10K.add(c.getCustomerId());
            }
            totalSales += sales;
        }
 
        Map<Object, Number> lt10k = new HashMap<Object, Number>();
        Map<Object, Number> gt10k = new HashMap<Object, Number>();
 
        for (Integer i : customersLessThan10K) {
            populateMap(lt10k, CustomerPurchasesByYearTotals.get(i));
        }
 
        for (Integer i : customersGreaterThan10K) {
            populateMap(gt10k, CustomerPurchasesByYearTotals.get(i));
        }
 
        ChartSeries customersLessThan10k = new ChartSeries("Customers with Sales < 10K");
        customersLessThan10k.setData(lt10k);
        ChartSeries customersGreaterThan10k = new ChartSeries("Customers with Sales > 10K");
        customersGreaterThan10k.setData(gt10k);
        cartesianChartModel.addSeries(customersLessThan10k);
        cartesianChartModel.addSeries(customersGreaterThan10k);
    }
 
    private void addOrUpdate(Integer customerId, String year, Number value) {
        Map<String, Number> map = CustomerPurchasesByYearTotals.get(customerId);
 
        if (map == null) {
            map = new HashMap<String, Number>();
            CustomerPurchasesByYearTotals.put(customerId, map);
        }
        Number n = map.get(year);
 
        if (n == null) {
            map.put(year, value);
        } else {
            map.put(year, (map.get(year).doubleValue() + value.doubleValue()));
        }
    }
 
    private void populateMap(Map<Object, Number> map, Map<String, Number> data) {
        if (data == null) {
            return;
        }
        for (String key : data.keySet()) {
            Number n = map.get((Object) key);
            if (n == null) {
                map.put((Object) key, data.get(key));
            } else {
                map.put((Object) key, n.doubleValue() + data.get(key).doubleValue());
            }
        }
    }
 
    private void createBubbleModel() {
        for (Product p : pf.findAll()) {
            bubbleChartModel.add(new BubbleChartSeries(
                    p.getDescription(), //label
                    p.getQuantityOnHand(), // x
                    p.getMarkup().intValue(), //y
                    p.getPurchaseCost().intValue() //radius
                    ));
        }
    }
 
    private void createMeterGaugeModel() {
        List<number> intervals = new ArrayList<number>() {
            {
                add(200000);
                add(400000);
                add(600000);
                add(800000);
            }
        };
//        meterGaugeChartModel = new MeterGaugeChartModel("Sales", totalSales, intervals); //PrimeFaces 3.3+
        meterGaugeChartModel = new MeterGaugeChartModel(Double.valueOf(totalSales), intervals); //PrimeFaces 3.4+
    }
 
    public XYDataSetCollection getChartSeries() {
        XYDataSetCollection collection = new XYDataSetCollection();
        XYDataList currentSeries1DataList = new XYDataList();
        XYDataList currentSeries2DataList = new XYDataList();
        XYDataList currentSeries3DataList = new XYDataList();
 
        for (int i = 0; i <= 10; i++) {
            long startTime = 1196463600000l;
            if (chartData.getMode().equalsIgnoreCase("Time")) {
                XYDataPoint p1 = new XYDataPoint(series1DataList.get(i).getX(),
                        series1DataList.get(i).getY(), series1DataList.get(i).getPointLabel());
                p1.setX(startTime + (p1.getX().doubleValue() * 1000 * 60));
 
                XYDataPoint p2 = new XYDataPoint(series2DataList.get(i).getX(),
                        series2DataList.get(i).getY(), series2DataList.get(i).getPointLabel());
                p2.setX(startTime + (p2.getX().doubleValue() * 1000 * 60));
 
                XYDataPoint p3 = new XYDataPoint(series3DataList.get(i).getX(),
                        series3DataList.get(i).getY(), series3DataList.get(i).getPointLabel());
                p3.setX(startTime + (p3.getX().doubleValue() * 1000 * 60));
 
                currentSeries1DataList.addDataPoint(p1);
                currentSeries2DataList.addDataPoint(p2);
                currentSeries3DataList.addDataPoint(p3);
            } else {
                currentSeries1DataList.addDataPoint(series1DataList.get(i));
                currentSeries2DataList.addDataPoint(series2DataList.get(i));
                currentSeries3DataList.addDataPoint(series3DataList.get(i));
            }
        }
        currentSeries1DataList.setLabel(series1DataList.getLabel());
        currentSeries1DataList.setFillLines(series1DataList.isFillLines());
        currentSeries1DataList.setMarkerPosition(series1DataList.getMarkerPosition());
        currentSeries1DataList.setMarkers(series1DataList.isMarkers());
        currentSeries1DataList.setShowDataPoints(series1DataList.isShowDataPoints());
        currentSeries1DataList.setShowLines(series1DataList.isShowLines());
 
        currentSeries2DataList.setLabel(series2DataList.getLabel());
        currentSeries2DataList.setFillLines(series2DataList.isFillLines());
        currentSeries2DataList.setMarkerPosition(series2DataList.getMarkerPosition());
        currentSeries2DataList.setMarkers(series2DataList.isMarkers());
        currentSeries2DataList.setShowDataPoints(series2DataList.isShowDataPoints());
        currentSeries2DataList.setShowLines(series2DataList.isShowLines());
 
        currentSeries3DataList.setLabel(series3DataList.getLabel());
        currentSeries3DataList.setFillLines(series3DataList.isFillLines());
        currentSeries3DataList.setMarkerPosition(series3DataList.getMarkerPosition());
        currentSeries3DataList.setMarkers(series3DataList.isMarkers());
        currentSeries3DataList.setShowDataPoints(series3DataList.isShowDataPoints());
        currentSeries3DataList.setShowLines(series3DataList.isShowLines());
 
        collection.addDataList(currentSeries1DataList);
        collection.addDataList(currentSeries2DataList);
        collection.addDataList(currentSeries3DataList);
        return collection;
    }
 
    public FlotChartRendererData getChartData() {
        return chartData;
    }
 
    public void setChartData(FlotChartRendererData chartData) {
        this.chartData = chartData;
    }
 
    public XYDataList getSeries1DataList() {
        return series1DataList;
    }
 
    public void setSeries1DataList(XYDataList series1DataList) {
        this.series1DataList = series1DataList;
    }
 
    public XYDataList getSeries2DataList() {
        return series2DataList;
    }
 
    public void setSeries2DataList(XYDataList series2DataList) {
        this.series2DataList = series2DataList;
    }
 
    public XYDataList getSeries3DataList() {
        return series3DataList;
    }
 
    public void setSeries3DataList(XYDataList series3DataList) {
        this.series3DataList = series3DataList;
    }
 
    public void generateChartMethod(OutputStream out, Object data) throws IOException {
        JFreeChart chart = ChartFactory.createPieChart3D("Products", getPartsDataset(), false, false, false);
        BufferedImage buffImg = chart.createBufferedImage(600, 400, BufferedImage.TYPE_INT_RGB, null);
        ImageIO.write(buffImg, "png", out);
    }
 
    private PieDataset getPartsDataset() {
        DefaultPieDataset dataset = new DefaultPieDataset();
        double totalCost = 0.0;
        List<product> products = pf.findAll();
        for (Product p : products) {
            totalCost += p.getPurchaseCost().doubleValue();
        }
        for (Product p : products) {
            dataset.setValue(p.getDescription(), (p.getPurchaseCost().doubleValue() / totalCost));
        }
        return dataset;
    }
 
    public StreamedContent getStreamedContent() {
        return streamedContent;
    }
}

Wednesday, April 10, 2013

JSF 2.x Tip of the Day: Post Exception Back Button

Introduction

This is hopefully one simple example of how to make a "back" button when an exception occurs, and sends you to an exception page. The question becomes "How do I get back to the page where the exception occurred?" The navigation back to the offending page is possible, but you want to make sure that you handle the exception, or you may get into a cycle.

A solution was suggested to me by my friend Markus Eisele using an ExceptionHandler in JSF. I had used exception handlers in the past, and thought that it was a simple and elegant idea. The code I am providing below DOES NOT handle the exception. This is specific to your implementation. This is just a handler that sits on top of your exception hierarchy, and provides a convenient mechanism to navigate back.

Code

The example code for the NetBeans Maven project can be downloaded from BitBucket here: exception-handler-navigation-button

You will need to register the factory below in the faces-config.xml file.

GeneralExceptionHandlerFactory.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
package com.bluelotussoftware.jsf.exception.handler;
 
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;
 
/**
 *
 * @author John Yeary
 * @version 1.0
 */
public class GeneralExceptionHandlerFactory extends ExceptionHandlerFactory {
 
    private ExceptionHandlerFactory parent;
 
    public GeneralExceptionHandlerFactory(final ExceptionHandlerFactory parent) {
        this.parent = parent;
    }
 
    @Override
    public ExceptionHandler getExceptionHandler() {
        ExceptionHandler result = parent.getExceptionHandler();
        result = new GeneralExceptionHandler(result);
        return result;
    }
}

GeneralExceptionHandler.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
package com.bluelotussoftware.jsf.exception.handler;
 
import java.util.Iterator;
import java.util.logging.Logger;
import javax.faces.FacesException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import javax.servlet.http.HttpServletRequest;
 
/**
 *
 * @author John Yeary
 * @version 1.0
 */
public class GeneralExceptionHandler extends ExceptionHandlerWrapper {
 
    private ExceptionHandler parent;
    private static final Logger LOG = Logger.getLogger(GeneralExceptionHandler.class.getName());
 
    public GeneralExceptionHandler(final ExceptionHandler parent) {
        this.parent = parent;
    }
 
    @Override
    public ExceptionHandler getWrapped() {
        return parent;
    }
 
    @Override
    public void handle() throws FacesException {
        for (Iterator<exceptionqueuedevent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
            ExceptionQueuedEvent event = i.next();
            ExceptionQueuedEventContext eqec = (ExceptionQueuedEventContext) event.getSource();
            Throwable throwable = eqec.getException();
 
            if (throwable instanceof FacesException) {
                FacesContext fc = FacesContext.getCurrentInstance();
                ExternalContext ec = fc.getExternalContext();
                HttpServletRequest request = (HttpServletRequest) ec.getRequest();
                String originalRequestURI = request.getRequestURI();
                String encodedURL = ec.encodeRedirectURL(originalRequestURI, null);
                ec.getSessionMap().put("com.bluelotussoftware.jsf.exception.handler.GeneralExceptionHandler.URL", encodedURL);
            }
        }
        parent.handle();
    }
}

Usage

Here is an example of how to use it from an exception page.
1
<h:commandButton value="Previous Page" action="#{indexBean.navigate()}"/>
1
2
3
4
5
public String navigate() throws IOException {
       String redirectURL = (String) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("com.bluelotussoftware.jsf.exception.handler.GeneralExceptionHandler.URL");
       FacesContext.getCurrentInstance().getExternalContext().redirect(redirectURL);
       return null;
   }

Tuesday, April 09, 2013

JSF 2.x Tip of the Day: PrimeFaces Chart Coding Exam

PrimeFaces Pie Chart

Background

I have been asked to interview a number of engineers over the last couple of years. We were interested in hiring an engineer with a background in JSF specifically PrimeFaces, Java EE 6, and NetBeans.

Basically I wanted someone...like me.

I came into work one day, and I was told that I needed to interview someone in about an hour about a position. The person claimed experience in all of the aforementioned technologies. I needed to come up with a coding exam idea for them. Tick tock tick tock.

I decided to create a NetBeans project using the sample Java DB database, JPA, EJB facades, and a JSF front end using PrimeFaces with a pie chart. The whole process took about 7 minutes to create. When the engineer arrived, I showed him the result and said "I want to see the same results", and explained that I used the sample database from NetBeans.

The engineer was successful and created something similar in about 30 minutes, and additionally showed me up by adding percentage tags to the chart. We hired him after the interview. I am glad to say he is an integral part of our team today.

Coding Exam

What do I want?

Please create a JSF application using PrimeFaces that displays a pie chart using data provided. The application must be developed using NetBeans and Java EE 6 technologies. The example data is provided using the sample Java DB database in NetBeans  We would like to have a pie chart that shows sales totals by customer as a percentage of all sales. You have 1 hour to complete the code, and will be required to explain your design decisions, and results.

Note: I just showed them the pie chart that was generated in the browser and not the actual code. I don't want to sway the candidates decision making, or give them hints on how to solve the problem.

Here is the code for the project: PrimeFacesCodingExam

Conclusion

Even if you don't use this in a coding exam, it is a good example of combining Java EE technologies using NetBeans  and PrimeFaces.

Saturday, April 06, 2013

Java EE @WebFilter Filters

I got an email from a developer a couple of days ago that was complaining that the filters he implemented were not executing on the url patterns he had set. The email was not explicit enough for me to determine if the ordering was an issue too. I created a simple project that shows how to use @WebFilter (Servlet Filters). I was going to dispose of the code, but I thought it might have some redeeming qualities for those who may need a working example.

I have commented out the @WebFilter annotations so that the web.xml controls the ordering. If you uncomment the @WebFilter annotations, you will need to comment the lines in the web.xml. Doing so will produce the same issues reported to me about execution and ordering.

Here is the NetBeans project using Apache Maven: zsolt-filter-example. I didn't want to put in a repo since it was not really a planned project.

JSF 2.x Tip of the Day: JSF Expression Language (EL) Keywords and Implicit Objects

A friend of mine asked me if there was a list of reserved words in EL and JSF. He had previously looked for it, and after some Google searching I didn't find a comprehensive list anywhere. I decided to create one for him and anyone else who may need it. If you are aware of any other keywords, please post a comment and I will add them to the listings.

Expression Language (EL) Reserved Keywords
Value Description
and Logical operator alternative to (&&)
false Boolean literal
le Relation operator less than or equal to alternative to (<=)
not Logical operator reverse alternative to (!)
div Arithmetic operator division alternative to (/)
ge Relational operator greater or equal to alternative to (>=)
lt Relational operator less than alternative to (<)
null Null literal
empty The empty operator is a prefix operation that can be used to determine whether a value is null or empty.
gt Relational operator greater than alternative to (>)
mod Arithmetic operator modulo alternative to (%)
or Logical operator alternative to (||)
eq Logical operator alternative to (==)
instanceof Java Keyword to do a Class comparison between Objects
ne Relational operator not equal alternative to (!=)
true Boolean literal


JSF 2.x Expression Language (EL) Implicit Objects
Value Description
application This provides user access to the ApplicationContext implementation of ServletContext that represents a web application's execution environment.
Note: This is not related to the JSF Application object.
applicationScope Maps application-scoped variable names to their values.
cc Implicit EL object that provides access to the JSF Composite Component. cc refers to the top level composite component processed at the time of evaluation
component Implicit EL object representing javax.faces.component.UIComponentfor the current component.
cookie Maps a cookie name to a single cookie.
facesContext The FacesContext instance for the current request.
flash Provides user access to the EL implicit javax.faces.context.Flash object. It may additional obtained via #{facesContext.externalContext.flash}. The implementation must ensure that the flash is usable from both JSP and from Facelets for JSF 2.
header Maps a request header name to a single value.
headerValues Maps a request header name to an array of values.
initParam Maps a context initialization parameter name to a single value.
param Maps a request parameter name to a single value.
paramValues Maps a request parameter name to an array of values.
request EL implicit object for current request.
requestScope Maps request-scoped variable names to their values.
resource EL implicit object for javax.faces.application.ResourceHandler.
session Provides EL access to the current HttpSession object.
sessionScope Maps session-scoped variable names to their values.
view Provides access to the javax.faces.component.UIViewRoot for the current instance.
viewScope Maps view-scoped variable names to their values.

Tuesday, April 02, 2013

JSF 2.x Tip of the Day: RichFaces <rich:tree /> Component Examples

Custom TreeModel and TreeNode
I have some code that I originally wrote for a proof of concept for doing some RichFaces <rich:tree /> examples. The modified code in these examples demonstrate how to use custom TreeNode, and TreeDataModel implementations to make really nice and functional trees. The code for my generic TypedTreeNode and TreeNodesSequenceKeyModel are fully functional and can be used out of the box as the basis of your own tree implementations.

The examples include the model provided by RichFaces, my custom model (TreeNodesSequenceKeyModel), and a custom implementation of a node. The custom node is generic so you can pass in any object you like. I chose to use text, but you could use a more complex object.

The custom model, custom node, and tree are shown in the image on the right. This also has events being shown when a node is selected, or toggled.

The project was developed using NetBeans along with Apache Maven.

The project can be found on GitHub here: richfaces-tree

Note: The project has been moved to GitHub and has a couple of release versions.
  • 1.0 - Initial Release using Java EE 6
  • 1.2 - Updated functionality using Java EE 6
  • 2.0 - Updated to RichFaces 4.5.14.Final and Java EE 7.


Code

TypedTreeNode.java



TreeNodesSequenceKeyModel.java


Monday, April 01, 2013

Determining What Classes are Loaded by ClassLoaders

I saw a question posted a couple of months ago on stackoverflow, or a forum. I can't remember where I saw it actually. The question was how do I determine what classes are currently loaded by the ClassLoader when an application is loaded and running. A number of folks posted various solutions like using java -verbose which are of limited help. Another solution was to get using something like ClassLoader.getSystemClassLoader();. The latter looks very promising, but is wrong. I knew that there are a number of classes that are loaded that this would not display.

Ssssh... I will show you how I know.

The problem and solution is surprisingly non-trivial. I thought I would come up with a solution like the one above in 5 minutes. I did come up with one above in about that much time. It turns out to be incorrect.

The solution is to use a Java agent to instrument the JVM and see what it is loading. I am sure a number of you have seen the -javaagent:[=] flag for the VM and wondered what is that for. I am going to show you.

First some results:

all length -> 815
system length -> 163
appLoader length -> 163
classes size -> 61

The first value all indicates all of the classes loaded by the JVM. That is a lot of classes. This is via an Instrumentation agent.

The second value system indicates all of the classes loaded by the System ClassLoader. This is significantly less than loaded by the JVM. This is via an Instrumentation agent.

The third value is the appLoader which is the application classloader. It matches the System, but this may not always be the case. This is via an Instrumentation agent.

Finally, the last value classes is what you get from the ClassLoader without instrumentation. It is a paltry amount of the total classes loaded.

So which one is right? Good question... Here is an answer only a parent, or teacher can give. "It depends."

If I am looking at everything being loaded to check for something forensically I would use the 815 and look at what these classes are and where they came from. If I am checking which classes are loaded to help with reflection, I would look at the 61.

If you have read this far, then you want the code to look at. I have split it into a couple of NetBeans Maven projects hosted on BitBucket using Mercurial.


Code

InstrumentationAgent.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
package com.bluelotussoftware.instrumentation.agent;
 
import java.lang.instrument.Instrumentation;
import java.util.logging.Level;
import java.util.logging.Logger;
 
/**
 * This provides a
 * <code>javaagent</code> instrumentation for the VM. This class provides
 * convenience methods for getting the classes loaded by the VM.
 *
 * @author John Yeary
 * @version 1.0
 */
public class InstrumentationAgent {
 
    private static final Logger log = Logger.getLogger(InstrumentationAgent.class.getName());
    private static Instrumentation instrumentation;
 
    /**
     * This method loads the agent prior to invoking the main method.
     *
     * @param agentArgs Arguments to be passed to the agent.
     * @param inst Instrumentation (agent).
     * @throws Exception if any {@code Exception} occurs while calling the
     * method and creating the agent.
     */
    public static void premain(String agentArgs, Instrumentation inst) throws Exception {
        log.log(Level.INFO, "premain() method called with agentArgs {0} and inst {1}", new Object[]{agentArgs, inst.getClass()});
        InstrumentationAgent.instrumentation = inst;
    }
 
    /**
     * This method is used to set the agent on the main method after the JVM is
     * already running.
     *
     * @param agentArgs Arguments to be passed to the agent.
     * @param inst Instrumentation (agent).
     */
    public static void agentmain(String agentArgs, Instrumentation inst) {
        log.log(Level.INFO, "agentmain() method called with agentArgs {0} and inst {1}", new Object[]{agentArgs, inst.getClass()});
        InstrumentationAgent.instrumentation = inst;
    }
 
    /**
     * This method returns the wrapped instrument (agent).
     *
     * @return The wrapped agent.
     */
    public static Instrumentation getInstrumentation() {
        return instrumentation;
    }
 
    /**
     * Returns an array of all classes currently loaded by the JVM.
     *
     * @return an array containing all the classes loaded by the JVM,
     * zero-length if there are none.
     */
    public static Class[] getAllLoadedClasses() {
        return instrumentation.getAllLoadedClasses();
    }
 
    /**
     * Returns an array of all classes for which
     * {@link ClassLoader#getSystemClassLoader()} is an initiating loader.
     *
     * @return an array containing all the classes for which
     * {@link ClassLoader#getSystemClassLoader()} is an initiating loader,
     * zero-length if there are none.
     */
    public static Class[] getSystemClassLoaderInitiatedClasses() {
        return instrumentation.getInitiatedClasses(ClassLoader.getSystemClassLoader());
    }
 
    /**
     * Returns an array of all classes for which loader is an initiating loader.
     * If the supplied loader is null, classes initiated by the bootstrap class
     * loader are returned.
     *
     * @param classLoader the loader whose initiated class list will be
     * returned.
     * @return an array containing all the classes for which loader is an
     * initiating loader, zero-length if there are none
     */
    public static Class[] getClassLoaderInitiatedClasses(final ClassLoader classLoader) {
        return instrumentation.getInitiatedClasses(classLoader);
    }
 
    /**
     * Static initialization method to load the {@link Instrumentation} if it
     * has not already been loaded.
     */
    public static void initialize() {
        log.log(Level.INFO, "initialize() method called.");
        if (instrumentation == null) {
            log.log(Level.INFO, "Instrumentation was null calling AgentLoader.");
            AgentLoader.loadAgent();
        }
    }
}

AgentLoader.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
package com.bluelotussoftware.instrumentation.agent;
 
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import java.io.IOException;
import java.lang.management.ManagementFactory;
 
/**
 *
 * This class is responsible for dynamically loading the instrumentation agent
 * jar.
 *
 * @author John Yeary
 * @version 1.0
 */
public class AgentLoader {
 
    /**
     * This method returns the path to the {@link Instrumentation} agent located
     * in the .m2 repository.
     *
     * @return Path to the agent jar.
     */
    private static String getAgentPath() {
        return new StringBuilder().append(System.getProperty("user.home"))
                .append("/.m2/repository/com/bluelotussoftware/instrumentation-agent/1.0/instrumentation-agent-1.0.jar")
                .toString();
    }
 
    /**
     * Static method for loading an agent into the currently running JVM.
     */
    public static void loadAgent() {
        String runtimeMXBeanName = ManagementFactory.getRuntimeMXBean().getName();
        int endIndex = runtimeMXBeanName.indexOf('@');
        String pid = runtimeMXBeanName.substring(0, endIndex);
 
        try {
            VirtualMachine vm = VirtualMachine.attach(pid);
            vm.loadAgent(getAgentPath());
            vm.detach();
        } catch (AttachNotSupportedException | IOException | AgentLoadException | AgentInitializationException e) {
            throw new RuntimeException(e);
        }
    }
}

App.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
package com.bluelotussoftware.example;
 
import com.bluelotussoftware.instrumentation.agent.InstrumentationAgent;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
 
/**
 *
 * @author John Yeary <jyeary@bluelotussoftware.com>
 * @version 1.0
 */
@SuppressWarnings("UseOfObsoleteCollectionType")
public class App {
 
    static {
        InstrumentationAgent.initialize();
    }
 
    public static void main(String[] args) throws ClassNotFoundException {
        App app = new App();
         
        Class[] all = InstrumentationAgent.getAllLoadedClasses();
        System.out.println("all length -> " + all.length);
 
 
        Class[] system = InstrumentationAgent.getSystemClassLoaderInitiatedClasses();
        System.out.println("system length -> " + system.length);
 
 
        Class[] appLoader = InstrumentationAgent.getClassLoaderInitiatedClasses(App.class.getClassLoader());
        System.out.println("appLoader length -> " + appLoader.length);
 
 
        List<String> classes = app.getLoadedClasses(ClassLoader.getSystemClassLoader());
        System.out.println("classes size -> " + classes.size());
 
        for (String s : classes) {
            System.out.println(s);
        }
    }
 
    public List<String> getLoadedClasses(final ClassLoader classLoader) {
        List<String> classNames = null;
        try {
            Field f = ClassLoader.class.getDeclaredField("classes");
            f.setAccessible(true);
            List<Class> classes = new ArrayList<>((Vector<Class>) f.get(classLoader));
            classNames = new ArrayList<>(classes.size());
            for (Class c : classes) {
                classNames.add(c.getCanonicalName());
            }
            return classNames;
        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException ex) {
            Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
        }
        return classNames;
    }
}
Note: I had to put the tools.jar in my Maven repository to make it easy to add as a library.

References

We can not achieve success alone. It is on the shoulders of giants that we see further. I used an example from Dhruba Bandopadhyay to figure out some of the instrumentation process.

Popular Posts