Wednesday, February 17, 2010

Create and Run a JEE6 Client Application with Netbeans 6.8 and Glassfish V3 - Part 2: Enhancing and Deploying the Application

This is the second part of a two part article aiming to share some experiences with developing JEE6 client applications. In the first part the skeleton of a basic micro-blogging enterprise application was set up, composed of a client application and an EJB module. In this part we will add a simple Swing form to enable users to post messages and to check the central timeline. It will be covered how to deploy to a standalone server and run the client both with the appclient tool and with Java Web Start.

First off, we want to add a JFrame based form to the application. Right click on the Glitter-app-client source package and chose New > JFrame Form. In our example the class will be named GlitterJFrame. In the visual editor, add a couple of UI elements: two text fields, one for the username input and the other for a message to post, along with a list box for the message timeline and two buttons to initiate posting and refreshing of messages.

Switch to the source code and add a DefaultListModel property named timelineModel, which we will use to populate the message list with the posts from the server. We also need a reference to our GlitterPostEJBRemote, which will be wired up on application start.

public class GlitterJFrame extends javax.swing.JFrame {
@EJB
private static GlitterPostEJBRemote glitterPostEJB;

private DefaultListModel timelineModel = new DefaultListModel();
...
}

Switch back to design mode, select the list box and activate the editor for model property in the properties view. Select Custom code, and fill in the name of the newly created property:


To make our life a little bit easier, we add a convenience constructor as well as an useful toString implementation to our GlitterPost entity model class:

public class GlitterPost implements Serializable {

public GlitterPost() {
}

public GlitterPost(String username, String content) {
this.username = username;
this.content = content;
}
...
@Override
public String toString() {
StringBuilder sb = new StringBuilder("<")
.append(username).append("> ")
.append(content);
return sb.toString();
}
}

Now it's time to perform some action. Double click the Refresh button to insert a new click handler. The following code snippet is responsible to perform the actual refresh:

    private void refreshActionPerformed(java.awt.event.ActionEvent evt) {
refresh();
}

private void refresh() {
timelineModel.clear();
List<GlitterPost> posts = glitterPostEJB.findPosts();
for (GlitterPost post : posts) {
timelineModel.addElement(post.toString());
}
}

In similar manner a handler for the Post button is added:

    private void postActionPerformed(java.awt.event.ActionEvent evt) {
glitterPostEJB.createPost(new GlitterPost(username.getText(), message.getText()));
refresh();
message.setText("");
}

Time to run the application: since we already had a Main class defined in the application client project, we have to change configuration to run the new Swing UI main class rather than the initial one. Right click on the Glitter-app-client project and select Properties > Run. Change Main Class to GlitterJFrame:


Run the GlitterEA application. If everything worked out well, the application window appears and the functionality can be tested:


At this point, the application could be considered to have it's initial functionality in place and is ready to be rolled out. The Glassfish V3 infrastructure imposes two basic ways to enable a server deployed client application to be run locally on client computers:

  • Using a local appclient container
  • Provisioning via Java WebStart

The Application Client Container (ACC) is a runtime environment for running a JEE client application locally, featuring transparent communication with the server based enterprise application as well as serving dependency injection. The appclient utility enables you to start a downloaded client application locally.

With the Netbeans embedded Glassfish instance still running, it is quite easy to give this a try. To get a version of the client application that can be run locally, we need to download the client stubs from the server. Open a command shell and change to a folder of your choice. Locate the Glassfish home and invoke $GLASSFISH_HOME/bin/asadmin with the get-client-stubs command:

> /Applications/NetBeans/sges-v3/glassfish/bin/asadmin get-client-stubs --appname GlitterEA .


After having issued this command, the current working directory should contain the file GlitterEAClient.jar along with a folder named GlitterEAClient which contains further resources. To start the application, the $GLASSFISH_HOME/bin/appclient tool is needed:

> /Applications/NetBeans/sges-v3/glassfish/bin/appclient -client GlitterEAClient.jar

Most likely some exceptions with complaints about recursive invocations will occur, which seem to be safe to be ignored. After a short while the client window should appear and work as expected.

Nevertheless, this solves only half of the problem. Running the application against a standalone server opposed to the instance started and controlled by Netbeans might cause some troubles, especially when using the same Glassfish installation for both Netbeans and standalone deployment.

To get an understanding what the troubles are, try the following:

  1. Stop the Netbeans controlled Glassfish instance under Services > Servers
  2. Stop the Netbeans controlled JavaDB instance under Services > Databases
  3. Switch to your command shell
  4. Start the standalone JavaDB instance:
    $GLASSFISH_HOME/bin/asadmin start-database
  5. Start the standalone Glassfish domain:
    $GLASSFISH_HOME/bin/asadmin start-domain domain1
  6. Invoke the client application with appclient as described above

You will notice a couple of things going wrong:

  • While the application may seem to start up normally and without problems, as soon as you hit the Refresh or Post button exceptions will be thrown. A short investigation reveals that the glitter database is missing.
    Indeed the standalone JavaDB instance does not know anything about the glitter database yet, since we created it against the Netbeans managed instance which uses a local storage folder in the user's home directory. For the standalone instance we need to create the glitter database again.
  • If you activate Java Web Start for the GlitterEA application via the Glassfish web administration console on http://localhost:4848 (detailed description follows), you will notice that starting the application fails when trying to launch it.
    The reason is that Netbeans uses a simplified deployment process when running the application from within the IDE, which besides others will cause the server side client application jars not to be signed as needed for Web Start. See this java.net forum thread for more detailed information on that topic.

Let's start a deployment from scratch to get around these problems. We now assume that $GLASSFISH_HOME/bin is in your path, to invoke asadmin and appclient. If not, prefix the commands with the correct directory as shown above. We also assume that the standalone Glassfish instance as well as the standalone JavaDB instance are already started as describes earlier.

  1. In Netbeans, right click on the GlitterEA project and select Clean and Build. This will create an up to date ear-file in the dist folder of our project. We will need this for later deployment.
  2. Undeploy GlitterEA if it is deployed already, either in the web admin console (which is suitable for all the following steps as well) or via shell:
    asadmin undeploy GlitterEA
  3. Delete the database pool glitterPool if existent:
    asadmin delete-jdbc-connection-pool --cascade=true "glitterPool"
  4. Recreate the connection pool, this time including the advice to create the database if it does not exist:
    asadmin create-jdbc-connection-pool \
    --datasourceclassname=org.apache.derby.jdbc.ClientConnectionPoolDataSource \
    --property user=glitter:password=glitter:databaseName=glitter:connectionAttributes=\;create\\=true \
    --restype=javax.sql.DataSource glitterPool

  5. Recreate the JDBC resource:
    asadmin create-jdbc-resource --connectionpoolid glitterPool jdbc/glitterDS
  6. Deploy the GlitterEA.ear we created earlier:
    asadmin deploy ~/NetBeansProjects/GlitterEA/dist/GlitterEA.ear
    Note: Although it is possible to extend the command line with the option --property java-web-start-enabled=true, Glassfish V3 currently does not seem to recognize this to enable WebStart capabilities for the deployed application, which we will cover later
  7. After making sure that your current working directory is the one containing the client stubs we retrieved earlier, or alternatively re-fetching the client stubs to your local directory of choice, try again to start the client application locally:
    appclient -client GlitterEAClient.jar

Now the client application should start and work as expected.

Although this is interesting for testing purposes, this is not really a suitable solution for provisioning the application to client desktops. That is where the Java Web Start feature of Glassfish comes more than handy. Given a clean standalone deployment as just described, navigate to your web administration console usually found under http://localhost:4848/. Select Applications > GlitterEA, activate the Java Web Start checkbox and click Save:


After that the Launch action is available for the Glitter-app-client.jar module:


Clicking the Launch link brings you to the application launch page:


Click the Launch button to enjoy the application being run via Java Web Start after having confirmed the security information dialog box. An alternative way to launch the application, also suitable to create a program launcher on the client computers is to use this command line (remember to replace localhost with the server name of choice):
javaws http://localhost:8080/GlitterEA/Glitter-app-client

For more information on how to configure and use Java Web Start with Glassfish V3, see the Glassfish V3 documentation and this useful article.

Please keep in mind that this tutorial was not intended to address Swing or EJB best practices, the idea was to keep these parts as simple as possible and concentrate on the client application concept.

The source code can be found (and forked) at github. For feedback, leave a comment or contact me on Twitter.


15 comments:

  1. Anonymous4/3/10 12:37

    This comment has been removed by a blog administrator.

    ReplyDelete
  2. This comment has been removed by a blog administrator.

    ReplyDelete
  3. Anonymous1/4/10 03:01

    This comment has been removed by a blog administrator.

    ReplyDelete
  4. Anonymous19/4/10 06:47

    This comment has been removed by a blog administrator.

    ReplyDelete
  5. Anonymous19/4/10 06:47

    This comment has been removed by a blog administrator.

    ReplyDelete
  6. Anonymous26/4/10 17:26

    This comment has been removed by a blog administrator.

    ReplyDelete
  7. Anonymous7/5/10 05:55

    This comment has been removed by a blog administrator.

    ReplyDelete
  8. Anonymous13/5/10 05:03

    This comment has been removed by a blog administrator.

    ReplyDelete
  9. Anonymous23/5/10 20:29

    This comment has been removed by a blog administrator.

    ReplyDelete
  10. Anonymous31/5/10 06:35

    This comment has been removed by a blog administrator.

    ReplyDelete
  11. Anonymous5/6/10 07:23

    This comment has been removed by a blog administrator.

    ReplyDelete
  12. This comment has been removed by a blog administrator.

    ReplyDelete
  13. Anonymous12/6/10 05:39

    This comment has been removed by a blog administrator.

    ReplyDelete
  14. This comment has been removed by a blog administrator.

    ReplyDelete
  15. This comment has been removed by a blog administrator.

    ReplyDelete

Labels

howto (4) java (3) appclient (2) ejb (2) glassfish (2) jee6 (2) maven (2) netbeans (2) scm (2) tutorial (2) adp1 (1) android (1) announcements (1) cdi (1) dependencymanagement (1) deployment (1) eclipse (1) extusb (1) fluff (1) g1 (1) git (1) htc (1) jee (1) jsr299 (1) liferay (1) m2eclipse (1) miniusb (1) operations (1) plug (1) portlet (1) servlet (1) struts2 (1) svn (1) tomcat (1) windows (1)