Saturday, May 28, 2011

Fixing Redeployment Issues for Servlet Applications on Windows

Deployment is hard, redeployment even harder from time to time - especially when your web container, say Tomcat, runs on Windows. Even if you did a good job in avoiding memory leaks and classloader issues, you may experience the problem that the running application fails to undeploy, leaving a couple of files in the webapps folder that could not be deleted.

When Bill designed his beautiful operating system (or whatever you want to call it), he decided to introduce pessimistic locking for file system resources. While this generally sounds good regarding concurrency issues, most of us will already have seen some downsides of this behavior, e.g. when trying to open a document by two users or performing an mvn clean or whatever.


The web container will feel this pain, too. Due to the nature of the JRE, resources are not immediately freed when an application is undeployed - they are just candidates to garbage collection now. So when the application's classloader is de-referenced due to application shutdown, resources such as file system handles may stay open for a while, until our friend GC comes along. If things turn out badly, this will cause the described interference with our redeployment process, since files with open handles cannot be deleted.


There are a couple of things you can do:
  • ditch Windows - seriously, you're doing server side stuff!! Grab any Linux, Solaris, *BSD (including MacOS) or whateverNIX and enjoy...
  • get help from my friends at Zeroturnaround and check out LiveRebel, their new magical tool for rolling out seemlessly
  • or: add the following listener to your servlet application


/**
* ServletContextCleanupListener uses a little hack to get rid of undeployment issues under Windows.
* Just in case you may ask: Free under Apache Software License
*
* @author Rene Gielen
*/
public class ServletContextCleanupListener implements ServletContextListener {

@Override
public void contextInitialized( ServletContextEvent sce ) {
// nothing to do
}

@Override
public void contextDestroyed( ServletContextEvent sce ) {
System.gc(); // No excuse - gc NOW
try {
Thread.sleep(1000); // ease, dude...
} catch ( InterruptedException ex ) {
// Intentionally left blank
}
}
}


My client is really happy now, since it solved all his problems. Actually it did not help me to convince him to ditch Windows *sigh*



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.


Friday, February 12, 2010

Create and Run a JEE6 Client Application with Netbeans 6.8 and Glassfish V3 - Part 1: Creating a Basic Application

While there are lots of examples around on how to create web based EE6 applications, it is a little harder to find a concise tutorial for developing and deploying EE application clients. This is part one of a two part article aiming to share some experiences on that topic.

Assuming you have a copy of Netbeans 6.8 with Glassfish V3 integration already installed and working, let's start with creating a new Enterprise Application project:


In the next dialog, we name the project "GlitterEA" and stay pretty much with the default options. After clicking next, we configure the application to use the default Glassfish 3 domain and to attach both an EJB and an application client module, the latter one with a suitable main class:


Next up, we want to get our EJB module set up to do something useful. For the example, our domain model is a very simple microblog service, to which users can publish their messages and read what others have written. We will create a single entity, accompanied by a stateless session bean exposing the needed services.

We start bottom up by creating a new JavaDB database from within the Netbeans Services tab as described here in the Netbeans documentation. We name it glitter, which will be also the username and the password, and stay with the default location.

Next we create a suitable connection pool as well as a matching JDBC resource for our application. Right click on the Glitter-ejb project and select New > Other... > Glassfish > JDBC Connection Pool:


We name the pool glitterPool and chose our newly created database for the connection:


In the next dialog, we add something like Glitter Microblogging as description. We leave the connection pool properties as suggested and proceed with the Next button. Since we don't have to change any optional connection pool properties as presented in dialog step 4, we chose to short circuit by clicking Finish.

Now we want to add a JDBC resource to which we can refer in our application. Right click on the Glitter-ejb project and select New > Other... > Glassfish > JDBC Resource. Chose glitterPool as the pool to use, and name the resource jdbc:/glitterDS. We are safe to click finish now since we don't want to provide additional properties.


Now we are ready to actually work on our EJB module. First off, we add an appropriate persistence unit. Right click on the Glitter-ejb project and select New > Persistence Unit. Configure it as seen here:


Note: Please check the generated sun-resources.xml file in the Server Resources folder. After adding the JDBC resource, you might experience an empty <property /> element in there. Remove the line, since Glassfish will give you a terribly long exception stack when parsing an property element without name attribute during resource setup at deploy time.

Let's get to coding. Create a new source package in the Glitter-ejb module, for example net.itneering.glitter.ejb. Right click on the newly created package and chose New > Entity Class. Name it GlitterPost and stay with the Long primary key type. Two more properties need to be added in the resulting Java class, username and content. In addition, a named query for selecting the posting timeline is put in place. Slightly shortened, this will be the resulting code:


@Entity
@NamedQuery(name="findAllPosts",
            query="SELECT p FROM GlitterPost p ORDER BY p.id DESC")
public class GlitterPost implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    String username;
    
    @Column(length = 2000)
    private String content;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

}

To expose some useful services for the client application, a simple stateless session bean is added by right clicking on the same source package and choosing New > Session Bean. It is called GitterPostEJB and will also need an remote interface:


Some basic CRUD methods are added to GlitterPostEJB, as well as the EntityManager reference to be injected with an EntityManager instance for the GlitterPU persistence unit:


@Stateless
public class GlitterPostEJB implements GlitterPostEJBRemote {

    @PersistenceContext(unitName = "GlitterPU")
    private EntityManager em;

    public GlitterPost createPost(GlitterPost post) {
        em.persist(post);
        return post;
    }

    public void deletePost(GlitterPost post) {
        em.remove(em.merge(post));
    }

    public GlitterPost updatePost(GlitterPost post) {
        return em.merge(post);
    }

    public List<GlitterPost> findPosts() {
        Query query = em.createNamedQuery("findAllPosts");
        return query.getResultList();
    }

    public GlitterPost findPostById(Long id) {
        return em.find(GlitterPost.class, id);
    }
}

Two of these methods we will need for our application client, so let's expose them in the GlitterEJBRemote interface:

@Remote
public interface GlitterPostEJBRemote {
    public List<GlitterPost> findPosts();
    public GlitterPost createPost(GlitterPost post);
}

That's pretty much it for the EJB module. Now it's time to check if the client application will work as expected. We will check both the findPosts and the createPost methods with a simple call sequence and some printing to standard out. Modify the Main class of the Glitter-app-client module as follows:

public class Main {
    @EJB
    private static GlitterPostEJBRemote glitterPostEJB;

    public static void main(String[] args) {
        List<GlitterPost> list = glitterPostEJB.findPosts();
        System.out.println(list);
        glitterPostEJB.createPost(new GlitterPost());
        // Now the list should contain the post we just created
        list = glitterPostEJB.findPosts();
        System.out.println(list);
    }
}

Save the file and right click the GlitterEA project. Select Run to start the application. If everything worked out well, the following output will be shown in the GlitterEA console:

Copying 1 file to /Users/rene/NetBeansProjects/GlitterEA/dist
Copying 4 files to /Users/rene/NetBeansProjects/GlitterEA/dist/GlitterEAClient
Feb 12, 2010 10:25:34 PM com.sun.enterprise.transaction.JavaEETransactionManagerSimplified initDelegates
INFO: Using com.sun.enterprise.transaction.jts.JavaEETransactionManagerJTSDelegate as the delegate
[]
[net.itneering.glitter.ejb.GlitterPost[id=1]]

In the second part of this article we will add a simple JFrame based Swing form to enable users to post messages and to check the central timeline. It will also cover how to deploy to a standalone server and run the client both with the appclient tool and with Java WebStart. The final source code of the project will then be published as well.


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)