David R. Heffelfinger

  Ensode Technology, LLC


OpenPortal First Impressions

I recently got involved in a project that may need some portlet development. The project is a completely new application to be built from the ground up.

The customer has been using GlassFish as their application server and they are very pleased with it, therefore it just makes sense to continue using it.

The OpenPortal Portlet Container can be installed in GlassFish from its update tool, therefore it made sense to try it out.

GlassFish Update Center

Once installed, I also installed the NetBeans Portal Pack plugin from NetBeans 6.5 RC2, that can be installed directly from the NetBeans Plugin Manager.

NetBeans Plugin Manager

The plugin makes deploying portlets to OpenPortal a breeze, as can be seen in this flash demo.

My main complaint? The default look and feel of the portlet is, let's just say, not the best looking.

OpenPortal default look

As far as I can tell the only way to change the default look is to hack the CSS and JSPs by hand. I noticed the icons to minimize a portlet, maximize it, edit it, etc had transparent backgrounds, therefore it gave me some hope that they should be able to be used when simply changing the background color of the portlet bar. I made a simple modification to the CSS to test this, unfortulately it seems like some of the pink background creeped into the icons.

OpenPortal modified look

Also, as far as I can tell, modifying the available tabs to match our application requirements will involve some customizations of the JSPs included with OpenPortal, there is no tool to create or modify tabs as necessary.

Even with these disadvantages, I'm leaning towards using OpenPortal if we in fact turn out to need portlets for this project. The tight integration with GlassFish and NetBeans is a great advantage and I can live with having to do some CSS and JSP hacking to make it look the way we need it to look.


Java EE Development With NetBeans 6 has been published

I'm pleased to announce that my latest book, Java EE Development With NetBeans 6 has been published.

Java EE 5 Development With NetBeans 6

The book covers several aspects of Java EE development using NetBeans, such as:

  • Visual Web JSF Development
  • JPA development, including automatic JPA generation from existing database schemas.
  • Automated JSF CRUD application generation from existing JPA entities
  • EJB 3 development, including session and message driven beans.
  • Debugging Java EE applications with the NetBeans debugger
  • Profiling Java EE applications with the NetBeans profiler
  • Additional Java EE Development Topics
I have been working on the book for the past several months, I am glad to finally see the fruits of my labor.

NetBeans Book Promotion Next Week On JavaRanch

Java EE 5 Development With NetBeans 6

Next week I'll be discussing my new book, Java EE 5 Development With NetBeans 6 in the IDEs, Version Control and other tools of the JavaRanch Big Moose Saloon.

I will be answering questions about the book, Java EE 5 and NetBeans.

See you there!


Linux Command Line Tricks

There are several "shells" that can be used in the command line for Linux and Unix systems.

The default shell for most Linux distributions such as Ubuntu and Fedora is called bash, which stands for "Bourne Again Shell", bash is an improved version of the Bourne Shell.

The first feature I would like to mention is tab completion.

  • Typing the first few letters of an executable command, then hitting tab completes the command.
  • After entering an executable command, hitting tab again shows a list of available arguments. Typing the first letter of the argument then hitting tab shows a list of arguments that start with that letter.
  • tab completion is especially useful to change directories, for example, to change directories to /home/david/Documents we could simply type "cd /ho<tab>/da<tab/Do<tab, saving us several keystrokes.

In addition to tab completion, the !$ character combination can be used for substitution, for example, if we were examining a file with the cat, more or less, then we realized we need to edit it, we don't need to type in the file the second time around:

less foo.txt
vi !$

The second line is equivalent to vi foo.txt, the !$ character combination is substituted for the last argument in the previous command.

The !! character combination executes the last command executed, preventing us from having to type it again.

We can view the history of the last several commands entered by using the history command, the output would look something like this:

476 ls
477 ls -larth
478 su
479 history |grep sudo
480 ls
481 ls f*
482 ls -ld fo*
483 cd
484 history

Of course, typical output is much longer, in any case, if we want to re-execute any command in the history, we simply need to enter it's number in the history preceded by an exclamation point, for example, if we wanted to re-execute command number 482, all we would need to enter is:


We can also navigate through the history by simply using the up and down arrows, the up arrow shows the previous command in the history, the down arrow shows the next command in the history.

Knowing these bash shell scripts help us be very proficient with the Unix command line, which I miss dearly when I am using a Windows box (by the way Cygwin provides a bash shell for Unix systems).

Ubuntu Intrepid Ibex is coming, worth the upgrade?

Ubuntu 8.10, also known as Intrepid Ibex, is about to be released soon.

I downloaded the release candidate and installed it under VirtualBox, an open source virtual machine that allows operating systems to be installed inside other host operating systems, similar to VMWare.

My impression of Intrepid is that it is not much different from Hardy Heron, the main difference is that it has updated versions of all the included applications.

Having written three books using OpenOffice.org, my one wish list is an updated version of this free and open source office suite. Unfortunately I found out that Ubuntu Intrepid Ibex does not come with OpenOffice.org 3.0, which is the recently released latest version.

I'm sure OpenOffice.org will end up in the Ubuntu Backports repository, but it feels kind of "hackish" to have to install it that way. It would be nice if OpenOffice.org 3.0 was included by default.

I may end up upgrading anyway, just to get updated versions of other applications, however I don't have that "must update now!" feeling I've had when other versions of Ubuntu were released.


NetBeans Book Title Changed

After some discussion with the publisher, we decided to change the title of my NetBeans book scheduled to be released very soon.

The new title is "Java EE 5 Development With NetBeans 6", the main reason for the change is that we wanted to have version numbers in the title, so that the title gives a better idea of exactly what is covered.

I would like to clarify that the book targets NetBeans 6.5, however, most of the material is applicable to NetBeans 6.0 and 6.1, therefore we decided to just state "NetBeans 6" in the title, since the material applies to any NetBeans 6.X version.


NetBeans 6.5 RC1 Released

NetBeans 6.5 RC1 available, it can be found at http://download.netbeans.org/netbeans/6.5/rc/.

My soon to be published book, Java EE Development With NetBeans, covers NetBeans 6.5.


Netbeans 6.5 RC1 to be released soon

The NetBeans Core QA Team has announced that NetBeans 6.5 RC1 will be released soon . It is expected to be available this afternoon.

I would like this opportunity to mention that my new NetBeans Book covers NetBeans 6.5.

Java EE Development With NetBeans Book

JRE 6u12 to include Java Plugin for 64 bit Linux

For the longest time, 64 bit versions of the Java Runtime Environment (JRE) and Java Development Kit (JDK) have not included a Java Plugin.

This fact has let us 64 bit Linux users out in the cold when it comes to running Java applets in our operating system of choice. There are workarounds, but they involved downloading a 32 bit browser and a 32 bit JRE, a less than ideal solution.

There has been a bug in Java's bug parade reporting this issue (submitted in 2003!), finally, today I got notice that this issue will finally be addressed.

According to the comments in the bug report, JRE 6u12 will include a Java plugin for 64 bit Linux, freeing us from jumping through hoops to be able to execute Java applets under 64 bit Linux.

JRE 6u12 is scheduled to be released early 2009.

Installing the Java Plugin on Ubuntu 64 bit

Recently I acquired a new client that has a lot of client side Java technology as part of their infrastructure. A lot of this infrastructure is in the form of Java applets.

My primary operating system is Ubuntu Hardy 64 bit. Unfortunately there is still no Java plugin for the 64 bit Linux version of Firefox, therefore, I was finding myself having to boot to Windows to be able to use some of these utilities.

Since I am much more comfortable in a Unix environment, I wanted to find a solution to run this software on my Linux laptop. I knew from past experience that a 32 bit version of Firefox can be installed under 64 bit Linux, and a 32 bit JRE can be installed as well, and the 32 bit firefox can be made to work with the 32 bit JVM.

I searched around and found this thread in the Ubuntu forums, which provides a link to a script that will install the 32 version of Firefox, along with the 32 bit version of the Java plugin and other plugins such as Flash. I downloaded the script and ran it, but unfortunately Java applets were still not working, at least I had 32 bit Firefox in place.

In order to get the Java plugin under Firefox 32, I had to download the 32 bit JRE from java.com, since Ubuntu is a deb based distribution (as opposed to RPM based), the right version to download is the self extracting file.

After downloading the JRE, it needs to be installed, which can be done by simply executing the downloaded shell script as root. I installed mine under /opt.

Once the JRE is installed, I had to cd to my home directory, then cd to .mozilla. At this point, I had to create a plugins subdirectory, and cd to it.

Then I needed to create a symlink for the Java plugin in the downloaded JRE to the ~/.mozilla/plugins directory: ln -s /opt/jre32/jre1.6.0_10/plugin/i386/ns7/libjavaplugin_oji.so ~/.mozilla/plugins.

At this point I started the 32 bit version of Firefox, navigated to a test page and verified that my Java plugin was working properly.


Facelets To Be Default View Technology in JSF 2.0

By default, JSF 1.2 uses JSP as its view technology, however JSF was designed to be very modular, allowing defaults to be swapped out for alternative technologies.

Facelets, by Jacob Hookom, is an alternate view technology for JSF. The main advantage of Facelets is that pages are written using standard XHTML, which allows web designers to freely design the pages, using design tools such as Dreamweaver. Using Facelets allows a true separation of concerns, with web designers designing the user interface of the system, and Java developers implementing the functionality.

Another advantage of Facelets is that it provides templating for JSF. Facelets templating is similar in functionality to tools such as Sitemesh and Apache Tiles. Using Facelets templates, common areas of all pages in the application, such as headers, footers and navigation menus, can be placed in in separate files, and they are "included" by all pages in the application. Templating allows us to make changes to these common areas in a single file, and they are "inherited" by all pages in the application, greatly simplifying maintenance.

Until now, in order to take advantage of Facelets additional dependencies had to be added to our project, since Facelets was non standard. Well, according to Arun Gupta and Ed Burns, Facelets will become the default JSF technology as of JSF 2.0. This will be a great step in simplifying JSF application development.

Arun Gupta has a very nice tutorial explaining how to get started developing JSF 2.0 applications under GlassFish today.

NetBeans IDE Turning 10 Years Old

The NetBeans IDE will turn 10 years old this month.

To celebrate, the NetBeans team is planning several activities. Check it out at http://www.netbeans.org/birthday/.


Automated DAO Generation from JPA Entities with NetBeans

One very nice NetBeans feature is the ability to generate Java Persistence API (JPA) entitites from an existing database schema. NetBeans can also generate complete JSF CRUD applications from JPA entities in a project. Both of these features are covered in detail in my Java EE 5 Development With NetBeans book.

As of NetBeans 6.5, scheduled to be released next month, will also add the ability to automatically generate DAO's (NetBeans calls them controllers, but they are, in fact, Data Access Objects) from existing JPA Entities.

NetBeans JPA Controller

This will certainly save us developers a lot of work, here is a sample DAO from generated from the Customer JPA entity discussed in the book:

package com.ensode.customerdb.jpacontrollers;

import com.ensode.customerdb.jpa.Customer;
import com.ensode.customerdb.jpacontrollers.exceptions.NonexistentEntityException;
import com.ensode.customerdb.jpacontrollers.exceptions.PreexistingEntityException;
import com.ensode.customerdb.jpacontrollers.exceptions.RollbackFailureException;
import java.util.List;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import com.ensode.customerdb.jpa.CustomerOrder;
import java.util.ArrayList;
import java.util.Collection;
import com.ensode.customerdb.jpa.Address;
import com.ensode.customerdb.jpa.Telephone;
import javax.transaction.UserTransaction;

* @author heffel
public class CustomerJpaController {
private UserTransaction utx = null;
@PersistenceUnit(unitName = "WebApplication1PU")
private EntityManagerFactory emf = null;

public EntityManager getEntityManager() {
return emf.createEntityManager();

public void create(Customer customer) throws PreexistingEntityException, RollbackFailureException, Exception {
if (customer.getCustomerOrderCollection() == null) {
customer.setCustomerOrderCollection(new ArrayList());
if (customer.getAddressCollection() == null) {
customer.setAddressCollection(new ArrayList

if (customer.getTelephoneCollection() == null) {
customer.setTelephoneCollection(new ArrayList());
EntityManager em = null;
try {
em = getEntityManager();
Collection attachedCustomerOrderCollection = new ArrayList();
for (CustomerOrder customerOrderCollectionCustomerOrderToAttach : customer.getCustomerOrderCollection()) {
customerOrderCollectionCustomerOrderToAttach = em.getReference(customerOrderCollectionCustomerOrderToAttach.getClass(), customerOrderCollectionCustomerOrderToAttach.getCustomerOrderId());
attachedAddressCollection = new ArrayList
for (Address addressCollectionAddressToAttach : customer.getAddressCollection()) {
addressCollectionAddressToAttach = em.getReference(addressCollectionAddressToAttach.getClass(), addressCollectionAddressToAttach.getAddressId());
Collection attachedTelephoneCollection = new ArrayList();
for (Telephone telephoneCollectionTelephoneToAttach : customer.getTelephoneCollection()) {
telephoneCollectionTelephoneToAttach = em.getReference(telephoneCollectionTelephoneToAttach.getClass(), telephoneCollectionTelephoneToAttach.getTelephoneId());
for (CustomerOrder customerOrderCollectionCustomerOrder : customer.getCustomerOrderCollection()) {
Customer oldCustomerIdOfCustomerOrderCollectionCustomerOrder = customerOrderCollectionCustomerOrder.getCustomerId();
customerOrderCollectionCustomerOrder = em.merge(customerOrderCollectionCustomerOrder);
if (oldCustomerIdOfCustomerOrderCollectionCustomerOrder != null) {
oldCustomerIdOfCustomerOrderCollectionCustomerOrder = em.merge(oldCustomerIdOfCustomerOrderCollectionCustomerOrder);
for (Address addressCollectionAddress : customer.getAddressCollection()) {
Customer oldCustomerIdOfAddressCollectionAddress = addressCollectionAddress.getCustomerId();
addressCollectionAddress = em.merge(addressCollectionAddress);
if (oldCustomerIdOfAddressCollectionAddress != null) {
oldCustomerIdOfAddressCollectionAddress = em.merge(oldCustomerIdOfAddressCollectionAddress);
for (Telephone telephoneCollectionTelephone : customer.getTelephoneCollection()) {
Customer oldCustomerIdOfTelephoneCollectionTelephone = telephoneCollectionTelephone.getCustomerId();
telephoneCollectionTelephone = em.merge(telephoneCollectionTelephone);
if (oldCustomerIdOfTelephoneCollectionTelephone != null) {
oldCustomerIdOfTelephoneCollectionTelephone = em.merge(oldCustomerIdOfTelephoneCollectionTelephone);
} catch (Exception ex) {
try {
} catch (Exception re) {
throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
if (findCustomer(customer.getCustomerId()) != null) {
throw new PreexistingEntityException("Customer " + customer + " already exists.", ex);
throw ex;
} finally {
if (em != null) {

public void edit(Customer customer) throws NonexistentEntityException, RollbackFailureException, Exception {
EntityManager em = null;
try {
em = getEntityManager();
Customer persistentCustomer = em.find(Customer.class, customer.getCustomerId());
Collection customerOrderCollectionOld = persistentCustomer.getCustomerOrderCollection();
Collection customerOrderCollectionNew = customer.getCustomerOrderCollection();

addressCollectionOld = persistentCustomer.getAddressCollection();
addressCollectionNew = customer.getAddressCollection();
Collection telephoneCollectionOld = persistentCustomer.getTelephoneCollection();
Collection telephoneCollectionNew = customer.getTelephoneCollection();
Collection attachedCustomerOrderCollectionNew = new ArrayList();
for (CustomerOrder customerOrderCollectionNewCustomerOrderToAttach : customerOrderCollectionNew) {
customerOrderCollectionNewCustomerOrderToAttach = em.getReference(customerOrderCollectionNewCustomerOrderToAttach.getClass(), customerOrderCollectionNewCustomerOrderToAttach.getCustomerOrderId());
customerOrderCollectionNew = attachedCustomerOrderCollectionNew;
attachedAddressCollectionNew = new ArrayList
for (Address addressCollectionNewAddressToAttach : addressCollectionNew) {
addressCollectionNewAddressToAttach = em.getReference(addressCollectionNewAddressToAttach.getClass(), addressCollectionNewAddressToAttach.getAddressId());
addressCollectionNew = attachedAddressCollectionNew;
Collection attachedTelephoneCollectionNew = new ArrayList();
for (Telephone telephoneCollectionNewTelephoneToAttach : telephoneCollectionNew) {
telephoneCollectionNewTelephoneToAttach = em.getReference(telephoneCollectionNewTelephoneToAttach.getClass(), telephoneCollectionNewTelephoneToAttach.getTelephoneId());
telephoneCollectionNew = attachedTelephoneCollectionNew;
customer = em.merge(customer);
for (CustomerOrder customerOrderCollectionOldCustomerOrder : customerOrderCollectionOld) {
if (!customerOrderCollectionNew.contains(customerOrderCollectionOldCustomerOrder)) {
customerOrderCollectionOldCustomerOrder = em.merge(customerOrderCollectionOldCustomerOrder);
for (CustomerOrder customerOrderCollectionNewCustomerOrder : customerOrderCollectionNew) {
if (!customerOrderCollectionOld.contains(customerOrderCollectionNewCustomerOrder)) {
Customer oldCustomerIdOfCustomerOrderCollectionNewCustomerOrder = customerOrderCollectionNewCustomerOrder.getCustomerId();
customerOrderCollectionNewCustomerOrder = em.merge(customerOrderCollectionNewCustomerOrder);
if (oldCustomerIdOfCustomerOrderCollectionNewCustomerOrder != null && !oldCustomerIdOfCustomerOrderCollectionNewCustomerOrder.equals(customer)) {
oldCustomerIdOfCustomerOrderCollectionNewCustomerOrder = em.merge(oldCustomerIdOfCustomerOrderCollectionNewCustomerOrder);
for (Address addressCollectionOldAddress : addressCollectionOld) {
if (!addressCollectionNew.contains(addressCollectionOldAddress)) {
addressCollectionOldAddress = em.merge(addressCollectionOldAddress);
for (Address addressCollectionNewAddress : addressCollectionNew) {
if (!addressCollectionOld.contains(addressCollectionNewAddress)) {
Customer oldCustomerIdOfAddressCollectionNewAddress = addressCollectionNewAddress.getCustomerId();
addressCollectionNewAddress = em.merge(addressCollectionNewAddress);
if (oldCustomerIdOfAddressCollectionNewAddress != null && !oldCustomerIdOfAddressCollectionNewAddress.equals(customer)) {
oldCustomerIdOfAddressCollectionNewAddress = em.merge(oldCustomerIdOfAddressCollectionNewAddress);
for (Telephone telephoneCollectionOldTelephone : telephoneCollectionOld) {
if (!telephoneCollectionNew.contains(telephoneCollectionOldTelephone)) {
telephoneCollectionOldTelephone = em.merge(telephoneCollectionOldTelephone);
for (Telephone telephoneCollectionNewTelephone : telephoneCollectionNew) {
if (!telephoneCollectionOld.contains(telephoneCollectionNewTelephone)) {
Customer oldCustomerIdOfTelephoneCollectionNewTelephone = telephoneCollectionNewTelephone.getCustomerId();
telephoneCollectionNewTelephone = em.merge(telephoneCollectionNewTelephone);
if (oldCustomerIdOfTelephoneCollectionNewTelephone != null && !oldCustomerIdOfTelephoneCollectionNewTelephone.equals(customer)) {
oldCustomerIdOfTelephoneCollectionNewTelephone = em.merge(oldCustomerIdOfTelephoneCollectionNewTelephone);
} catch (Exception ex) {
try {
} catch (Exception re) {
throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
String msg = ex.getLocalizedMessage();
if (msg == null || msg.length() == 0) {
Integer id = customer.getCustomerId();
if (findCustomer(id) == null) {
throw new NonexistentEntityException("The customer with id " + id + " no longer exists.");
throw ex;
} finally {
if (em != null) {

public void destroy(Integer id) throws NonexistentEntityException, RollbackFailureException, Exception {
EntityManager em = null;
try {
em = getEntityManager();
Customer customer;
try {
customer = em.getReference(Customer.class, id);
} catch (EntityNotFoundException enfe) {
throw new NonexistentEntityException("The customer with id " + id + " no longer exists.", enfe);
Collection customerOrderCollection = customer.getCustomerOrderCollection();
for (CustomerOrder customerOrderCollectionCustomerOrder : customerOrderCollection) {
customerOrderCollectionCustomerOrder = em.merge(customerOrderCollectionCustomerOrder);

addressCollection = customer.getAddressCollection();
for (Address addressCollectionAddress : addressCollection) {
addressCollectionAddress = em.merge(addressCollectionAddress);
Collection telephoneCollection = customer.getTelephoneCollection();
for (Telephone telephoneCollectionTelephone : telephoneCollection) {
telephoneCollectionTelephone = em.merge(telephoneCollectionTelephone);
} catch (Exception ex) {
try {
} catch (Exception re) {
throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
throw ex;
} finally {
if (em != null) {

public List findCustomerEntities() {
return findCustomerEntities(true, -1, -1);

public List findCustomerEntities(int maxResults, int firstResult) {
return findCustomerEntities(false, maxResults, firstResult);

private List findCustomerEntities(boolean all, int maxResults, int firstResult) {
EntityManager em = getEntityManager();
try {
Query q = em.createQuery("select object(o) from Customer as o");
if (!all) {
return q.getResultList();
} finally {

public Customer findCustomer(Integer id) {
EntityManager em = getEntityManager();
try {
return em.find(Customer.class, id);
} finally {

public int getCustomerCount() {
EntityManager em = getEntityManager();
try {
return ((Long) em.createQuery("select count(o) from Customer as o").getSingleResult()).intValue();
} finally {


Isn't it great to get all this code generated? No need to develop and debug it ourselves, letting us focus on implementing business logic.


Excel Unlock Utility

After I implemented and deployed the PDF Unlocking Tool, I was fortunate to find out it became very popular. Apparently I had written and deployed a useful tool.

It's popularity got me thinking, what else I could write that would be helpful to others? Then it hit me, just like PDF files are sometimes restricted, preventing users from copying and pasting their content, sometimes Excel spreadsheets contain locked, uneditable cells.

I started looking around for Java libraries to manipulate Excel spreadsheets, and found JExcelAPI. I started researching this library and sure enough, I found a way to unlock cells in an Excel spreadsheet.

Using this API, I developed an online utility to unlock cells in a spreadsheet, which can be found at http://ensode.net/xls-crack.jsf. It soon became a very popular destination on my site.

Solution for Firefox 3 Always Starting in Offline Mode Under Ubuntu

Ubuntu Hardy Heron is my primary operating system. Although in general I think it is a great operating system, there was one little annoyance that was bothering me. Firefox 3 always started in offline mode.

Every time I opened Firefox I had to go to the File menu, and uncheck the "Work Offline" checkbox, very annoying.

Well fortunately I found a solution. In order to avoid this from happening, we need to type "about:config", then set the toolkit.networkmanager.disable preference to true. Problem solved.


« January 2018

© David R. Heffelfinger