10 April 2014

How to set up a cluster with Tomcat 8, Apache and mod_jk

PART 1   |   PART 2   |   PART 3

This is the first in a series of blogs on Tomcat, including basic set-up and clustering, configuration and testing and finally performance tuning and monitoring.



Despite the popularity of Tomcat, it seems to have something of a reputation for being a developer’s application server because of how apparently simple and “no-frills” it seems to be, and therefore suited only to the most lightweight of deployments. In reality, many of the features that aren’t included in Tomcat are those that most businesses will never miss (and for those that will, projects like TomEE bring together all the necessaries for a full Java EE profile).

In this blog post, I’ll go through a very common scenario for a small production environment – a single tier, load balanced application server cluster.

One of the most fundamental concepts in high availability is load balancing work across multiple server instances. The specifics of exactly how that is achieved varies a lot depending on whether you want to scale upadd more server instances to a host – or scale out – add more hosts with server instances on.

3 April 2014

Getting the most out of WLDF Part 2: Watches

Read Part 1: What is the WLDF? here

In this post, I'll be looking at using watches in WLDF.

What is a watch?
A watch, at its most basic, is simply a way to monitor one of three things:
  • MBeans
  • A server log
  • Instrumentation (event) data
To configure an instrumentation watch, you first need to know what instrumentation is, and how to instrument applications or servers, so we’ll put that to one side for now.

A server log watch is exactly that – a watch to monitor the server log for anything you want! For example, all Critical severity log entries, entries which mention a particular server or particular log message IDs.

An MBean watch relies on the Harvester to collect server runtime MBean metrics which does not need to be configured separately for your watch to work, but do bear in mind that the data gathered will not be archived unless you configure the Harvester properly:

Note:
If you define a watch rule to monitor an MBean (or MBean attributes) that the Harvester is not configured to harvest, the watch will work. The Harvester will "implicitly" harvest values to satisfy the requirements set in the defined watch rules. However, data harvested in this way (that is, implicitly for a watch) will not be archived. See Chapter 7, "Configuring the Harvester for Metric Collection," for more information about the Harvester.

25 March 2014

JBoss Data Grid: Monitoring using JON

Overview

There are multiple ways and tools which we can use to monitor JDG including using the JDG Listener API when cache entries are removed and added to specific cachess, exposing the jmx cache statistics however we will focus on using the JBoss Operations Network (JON) to monitor JDG. We will use JON 3.2 and JDG 6.2 in this article. We will use |JON to monitor the distributed Hotrod cache which was deployed to a JDG cluster. The details to set up a JDG cluster which hosts a distributed cache instance can be found here. We will discuss firstly how to setup JON to monitor JDG using the relevant plugins and then demonstrate some of the monitoring capabilities within JON. In this blog, we will use the acronyms RHQ and JON interchangeability as JON is the supported version of RHQ which is open-source.

JON Installation and Configuration

Before installing JON, we need to firstly download JON 3.2 from the Redhat site along with the relevant JON plugins for JDG. We should select "Red Hat JBoss Operations Network 3.2.0 Base Distribution" and the plugin packs to allow for JON to monitor the  JDG cluster. The plugin pack names are: "Data Grid Plugin Pack for Red Hat JBoss Operations Network 3.2.0" and "Application Platform Plugin Pack for Red Hat JBoss Operations Network 3.2.0"



Now that we have downloaded the JON installation package, there are a number of steps which we need to follow to configure JON. JON 3.2 supports Oracle and PostgreSQL as a database backend. We will be using Oracle XE 11.2 to host the RHQ schema objects created at installation time. Furthermore, we have installed JON 3.2 on a single host machine using JDK1.7.0_45. For a list of supported configurations please view this page: https://access.redhat.com/site/articles/112523

We followed these steps to setup and configure JON:

1) Before running the JON installer scripts, we need to setup a user/schema in the Oracle database which will be used to store JON server configuration details and metrics data. I have set up a user named "RHQADMIN" for this purpose.




2) Unzip the JON installation package we downloaded earlier and configure the JON server properties file named rhq-server.properties located in the <JON_HOME>\bin directory before running the installation script.
3) There are a few notable sections which need to configure in the rhq-server.properties file to configure JON to run on a specific machine and against the Oracle database we preconfigured in step 2 above. These sections are noted below.

a) Provide the name of the database server name, port, database name, username and password where the RHQ schema objects will be hosted. You should provide the encoded user password for the "rhq.server.database.password" property. This is generated using the rhq-encode script located in the <RHQ_SERVER_HOME>/bin directory. For example, below are the configuration details for Oracle XE 11.2.

rhq.server.database.connection-url=jdbc:oracle:thin:@<db_hostname>:1521:xe
rhq.server.database.user-name=rhqadmin
rhq.server.database.password=xxxxxx
rhq.server.database.type-mapping=Oracle11g
rhq.server.database.server-name=unused
rhq.server.database.port=unused
rhq.server.database.db-name=unused
hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
rhq.server.quartz.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate

b) Configure the properties "jboss.bind.address" and "jboss.bind.address.management" to the ip address or hostname were the server will be installed.

c) Configure these 5 installer properties appropriately were the properties "rhq.autoinstall.enabled" and "rhq.autoinstall.database" should be set to "true" and "auto" respectively :

rhq.autoinstall.enabled=true
rhq.autoinstall.database=auto
rhq.autoinstall.public-endpoint-address=<server_ip_address>
rhq.server.management.password=xxxxxx
rhq.storage.nodes=<server_hostname>

Now that we have configured the rhq-server.properties file, we now need to install the rhq-server, rhq-storage server and rhq-agent. I have installed all 3 on my local windows machine and since I am installing on windows these will be installed as services. To install the 3 JON/RHQ components above, we use the 'rhqctl' command. Execute the command rhqctl install from the console window which will install by default the 3 JON components aforementioned. The installer should take some minutes to install. Once the RHQ Server, storage engine and agent has been installed, we now can start these services using windows services explorer and navigate to http://<server-name>:7080 in the browser window. We should note I have only chosen to start the rhq storage and rhq server service as before we can start the rhq-agent, we firstly need to configure agent which we will discuss in the next section.

 


JON Agent/Plugin Configuration and JDG Instance Detection

The 3 node JDG cluster which we had set up previously referenced here runs on the same machine as the JDG server and the agent which we will now configure. The role of the RHQ agent is to send monitoring updates to the RHQ Server which can be then viewed in the RHQ dashboard console. We need to firstly configure the RHQ agent to the correct RHQ server and also provide the agent with the correct plugin packages to allow for this. The following steps should be completed to achieve this:

1) Open up a console window and navigate to the "bin" directory were RHQ has been installed and execute the batch script rhq-agent. The first time this command is run, the user is prompted for the agent name, agent hostname, server hostname and port. If you need to re-configure the agent at any time execute rhq-agent --fullcleanconfig. Providing the configuration details are correct, the agent should be registered with the RHQ server successfully.

2) The next step to configure the agent is to install the relevant plugins to allow the RHQ server to monitor the running JDG instances via the RHQ agent. We need to install the two plugin packs which we downloaded earlier. We will install these using the RHQ server console however you can also deploy them directly into the RHQ Server plugins directory located at <RHQ_SERVER_HOME>/plugins.

3) To install the two plugins previously mentioned, unzip the two plugin installer zip files into a directory on your file system. Navigate to the "Administration" tab in the RHQ server web console, click on the "server plugin"s menu option and now click on the "choose file" button beside the upload plugin label in this screen. The two plugins have been uploaded to the server and we now want for these plugins to be downloaded to the RHQ agent which can be achieved by either restarting the rhq-agent or by clicking on the "Agent Plugins" menu option and then by pressing the "scan for updates" button which should trigger the copying of the JDG plugins over to the agent "plugins" directory. Providing the agent has been updated with the two previously uploaded plugins, these should be visible in your <RHQ_AGENT_HOME>/plugins directory like in the screenshot below.






RHQ Server JDG Resource Configuration and Monitoring Setup

Now that the RHQ server, agent and JDG plugins have bee installed, the last part to setup monitoring of the cache instances running on the JDG cluster is to configure the RHQ Server using the RHQ server web console to indicate what JDG servers we wish to monitor and what monitoring metrics we wish to gather on the distributed cache instance.

To allow the server to detect and monitor the JDG instances, we need to complete the following steps:

1) Start up all JDG instances which we wish to monitor and now navigate to the "Inventory" tab and then click on the menu option named "Discovery Queue" in the RHQ server web console. You should now view the 3 running JDG instances which should be selected before clicking on the "Import" button at the bottom of the screen to import these resources into the RHQ Server configuration for monitoring.

2) Now click the "Servers" menu option in the "Inventory" window and you should be able to view the newly imported JDG instances. We now need to enter the password details for a user configured under management realm for each JDG instance. To set the password, click on each JDG instance then the"Connection Settings" tab.


Providing there are no issues with the RHQ server and agent configuration details, the server should be marked as available in the "Child Resources" screen under the "Inventory"  tab( A Green Tick should be visible under the Availability Column).

The last part will be to specify what metrics we wish to monitor and to view on either your own dashbaord or just to add to the default dashboard in the RHQ server console. To add new monitoring metrics to the RHQ server dashboard, click on the JDG instance, navigate to the "Child Resources" window, click on the "infinispan" resource and navigate to the cache instance we wish to monitor on the JDG instance. We wish to monitor the distributed cache named "directory-dist-cache" to our JDG cluster as mentioned in the previous blog . Now right click on the cache name and select the "Measurements" dropdown option and we are now presented with a number of cache metrics which we can choose from. We can view an example of various metrics available based on the screenshot below. We are provided with the option here to add these metrics to the default or to are own custom dashboard.


For further details on using JON to monitor JDG, please have a look at the webinar below. We also briefly introduce testing of Data Grid applications using RadarGun.

Webinar: Testing and Monitoring Your JBoss Data Grid

In the last part of the webinar series we will cover the introduction to tools we can use to performance test JBoss Data Grid; we will look at the different tools we can use to monitor JBoss Data Grid in production; we will also provide a brief demo using specific tools used for both testing and monitoring a JBoss Data Grid.






24 March 2014

JBoss Data Grid: Installation and Development

In this blog, we will discuss one particular data grid platform from Redhat namely JBoss Data Grid (JDG). We will firstly cover how to access and install this data grid platform and then we will demonstrate how to develop and deploy a simple remote client/server data grid application which utilises the HotRod protocol. We will be using the latest release JDG 6.2 from Redhat in this article.

Installation Overview

To start using JDG, firstly log on to the redhat site https://access.redhat.com/home and download the software from the Downloads section of the site. We wish to download JDG 6.2 server by clicking on the appropriate links in the Downloads section. For future reference, it is also useful to download the quickstart and maven repository zip files. To install JDG, we simply unzip the JDG server package into an appropriate directory in your environment.






















JDG Overview

In this section, we will provide a brief overview of the contents of the JDG installation package and the most notable configuration options available to users. Out of the box, users are provided with two runtime options either to run JDG in standalone or clustered mode. We can start JDG in either mode by invoking the stanadalone or clustered start up scripts in the <JDG_HOME>/ bin directory. To configure the JDG in either mode we need to configure the files standalone.xml and clustered.xml. In our case we will creating a distributed cache which will run on 3 node JDG cluster so we will be utilizing the clustered startup script.

In order to set up and add new cache instances to JDG, we modify the infinispan subsystems in the appropriate xml configuration file above. We should also note the principal difference between the standalone and clustered configuration file is that in the clustered configuration file there is a JGroups subsystem configured element which allows for communication and messaging between configured cache instances running in a JDG cluster.

Development Environment Setup and Configuration

In this section, we will detail how to develop and configure a simple datagrid application which will be deployed to a 3 node JDG cluster. We will demonstrate how to configure and deploy a distributed cache in JDG and also show how to develop a HotRod Java client application which will be used to insert, update and display entries in the distributed cache. We will firstly discuss setting a new distributed cache on a 3 node JDG cluster. In this example, we will run our JDG cluster on a single machine by running each JDG instance on different ports.

Firstly, we will create 3 instances of JDG by creating 3 directories (server1, server2, server3) on our host machine and unzipping each JDG installation into each directory.



We will now configure each node in our cluster by copying and renaming the clustered.xml configuration file in the <JDG_HOME>\server1\jboss-datagrid-6.2.0-server\standalone\configuration directory. We will name each of the cluster configuration files as "clustered1.xml", "clustered2.xml" and "clustered3.xml" for the JDG instances denoted by "server1", "server2" and "server3" respectively. We will now set up a new distributed cache on our JDG cluster by modifying the infinispan subsystem element in each clustered<n>.xml file. We will demonstrate this for the node denoted "server1" here by modifying the file "clustered1.xml". The cache configuration shown here will be the same across all 3 nodes.

To setup a new distributed cache named "directory-dist-cache", we configure the following elements in the file named "clustered1.xml".

<subsystem xmlns="urn:infinispan:server:endpoint:6.0">
        <hotrod-connector socket-binding="hotrod"  cache-container="clusteredcache">
         <topology-state-transfer lazy-retrieval="false" lock-timeout="1000" replication-timeout="5000"/>
        </hotrod-connector>
        .........
      <subsystem xmlns="urn:infinispan:server:core:6.0" default-cache-container="clusteredcache">
                   <cache-container name="clusteredcache" default-cache="default" statistics="true">
                       <transport executor="infinispan-transport" lock-timeout="60000"/>
                    ......
               <distributed-cache name="directory-dist-cache" mode="SYNC" owners="2" remote-                   timeout="30000" start="EAGER">
              <locking isolation="READ_COMMITTED" acquire-timeout="30000" striping="false"/>
              <eviction strategy="LRU" max-entries="20" />
              <transaction mode="NONE"/>
              </distributed-cache>
             ..............
  </cache-container>
     

</subsystem>

 <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
......
<socket-binding name="hotrod" interface="management" port="11222"/>
......
/socket-binding-group>

</server>


We will discuss the key elements and attributes relating to the configuration above.

  • In the infinispan endpoint subsystem, we will configure hotrod clients to connect to the JDG server instance on socket 11222. 
  • The name of the cache container to host each of the cache instances will be held in the container named "clusteredcache".
  • We have configured the infinispan core subsystem to the default cache container named "clusteredcacahe" whereby we will allow for jmx statistics to be collected relating the configured cache entries i.e statistics="true"
  • We have created a new distributed cache named "directory-dist-cache" whereby there will be two copies of each cache entry held on two of the 3 cluster nodes. 
  • We have also set up an eviction policy whereby should there be more than 20 entries in our cache then cache entries will be removed using the LRU algorithm
  • We should have configured nodes "server2" and "server3" to start up with a port offset of 100 and 200 respectively by configuring the socketing binding group element appropriately. Please view the socket bindings noted below.

To set the socket binding element with a port offset of 100 on "server2", we configure "clustered2.xml" with the following entry:

<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:100}">
......
<socket-binding name="hotrod" interface="management" port="11222"/>
......
/socket-binding-group>


To set the socket binding element with a port offset of 200 on "server3", we configure "clustered3.xml" with the following entry:

<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:200}">
......
<socket-binding name="hotrod" interface="management" port="11222"/>
......
/socket-binding-group>

Before discussing the setup and configuration of our Hotrod client which will be used to interact with our JDG clustered HotRod server, we will start up each server instance to ensure our newly configured JDG distributed cache starts up correctly.

Open up 3 Windows or Linux consoles and execute the following start up commands:

Console 1:

1) Navigate to <JDG_HOME>\server1\jboss-datagrid-6.2.0-server\bin

2) Execute this command to start the first instance of our JDG cluster denoted "server1": clustered -c=clustered1.xml -Djboss.node.name=server1

Console 2:

1) Navigate to <JDG_HOME>\server2\jboss-datagrid-6.2.0-server\bin

2) Execute this command to start the second instance of our JDG cluster denoted "server2": clustered -c=clustered2.xml -Djboss.node.name=server2

Console 3:

1) Navigate to <JDG_HOME>\server3\jboss-datagrid-6.2.0-server\bin

2) Execute this command to start the third instance of our JDG cluster denoted "server3": clustered -c=clustered3.xml -Djboss.node.name=server3

Providing all 3 JDG instances have started up correctly, you should see output in the console window whereby we can see there are 3 JDG instances in the JGroups view:




HotRod Client Development Setup

Now that the Hotrod server is up and running, we need to develop a Hotrod Java client which will interact with the clustered server application. The development environment consists of the following tools.

1) JDK Hotspot 1.7.0_45
2) IDE - Eclipse Kepler Build id:  20130919-0819

The HotRod client application is a simple application consisting of two Java classes. The application allows users to retrieve a reference to the distributed cache from the JDG server and then perform these actions:

a) add new cinema objects.
b) add and remove shows to each cinema object.
c) print the list of all cinemas and shows stored in our distributed cache.

The source code can be downloaded from github @ https://github.com/davewinters/JDG. We could use maven here to build and execute our application by configuring the maven settings.xml to point to the maven repository files we downloaded earlier and set up a maven project file (pom.xml) to build and execute the client application.

In this article we will build our application using the Eclipse IDE and run the client application on the command line. To create a HotRod client application and execute the sample application, one should complete the following steps:

1) Create a new Java Project in Eclipse
2) Create a new package named uk.co.c2b2.jdg.hotrod and import the source code that has been downloaded from Github mentioned previously.
3) Now we need to configure the build path in Eclipse to contain the appropriate JDG client jar files which are required to compile the application. You should include all the client jar files in the project build path. These jar files are contained in the JDG installation zip file. For example on my machine these jar files are located in the directory: <JDG_HOME>\server1\jboss-datagrid-6.2.0-server\client\hotrod\java
4. Providing the Eclipse build path has been configured appropriately, the application source should compile without issue.
5. We will need to execute the Hotrod application by opening the console window and executing the following command. Note the path specified here will differ depending on where the JDG client jar files and application class files are located in your environment:

java -classpath ".;C:\Users\David\Installs\jbossdatagrids62\server1\jboss-datagrid-6.2.0-server\client\hotrod\java\commons-pool-1.6-redhat-4.jar;C:\Users\David\Installs\jbossdatagrids62\server1\jboss-datagrid-6.2.0-server\client\hotrod\java\infinispan-client-hotrod-6.0.1.Final-redhat-2.jar;C:\Users\David\Installs\jbossdatagrids62\server1\jboss-datagrid-6.2.0-server\client\hotrod\java\infinispan-commons-6.0.1.Final-redhat-2.jar;C:\Users\David\Installs\jbossdatagrids62\server1\jboss-datagrid-6.2.0-server\client\hotrod\java\infinispan-query-dsl-6.0.1.Final-redhat-2.jar;C:\Users\David\Installs\jbossdatagrids62\server1\jboss-datagrid-6.2.0-server\client\hotrod\java\infinispan-remote-query-client-6.0.1.Final-redhat-2.jar;C:\Users\David\Installs\jbossdatagrids62\server1\jboss-datagrid-6.2.0-server\client\hotrod\java\jboss-logging-3.1.2.GA-redhat-1.jar;C:\Users\David\Installs\jbossdatagrids62\server1\jboss-datagrid-6.2.0-server\client\hotrod\java\jboss-marshalling-1.4.2.Final-redhat-2.jar;C:\Users\David\Installs\jbossdatagrids62\server1\jboss-datagrid-6.2.0-server\client\hotrod\java\jboss-marshalling-river-1.4.2.Final-redhat-2.jar;C:\Users\David\Installs\jbossdatagrids62\server1\jboss-datagrid-6.2.0-server\client\hotrod\java\protobuf-java-2.5.0.jar;C:\Users\David\Installs\jbossdatagrids62\server1\jboss-datagrid-6.2.0-server\client\hotrod\java\protostream-1.0.0.CR1-redhat-1.jar" uk/co/c2b2/jdg/hotrod/CinemaDirectory

6. The Hotrod client at runtime provides the end user with a number of different options to interact with the distributed cache as we can view from the console window below.




Client Application Principal API Details

We will not provide a detailed overview of the Hotrod application code however we will describe the principal API and code details briefly.

In order to interact with the distributed cache on the JDG cluster using the Hotrod protocol, we will use the RemoteCacheManager Object which will allow us to retrieve a remote reference to the distributed cache. We have initialised a Properties object with the list of JDG instances and the associated with HotRod server port on each instance. We can add Cinema objects into the distributed cache using the RemoteCache.put() method.

 private RemoteCacheManager cacheManager;
 private RemoteCache<String, Object> cache;
.....
Properties properties = new Properties();
 properties.setProperty(ConfigurationProperties.SERVER_LIST, "127.0.0.1:11222;127.0.0.1:11322;127.0.0.1:11422");
cacheManager = new RemoteCacheManager(properties);
cache = cacheManager.getCache("directory-dist-cache");
.....
cache.put(cinemaKey, cinemalist);

In the webinar below, I describe in further detail how to set up a JDG cluster and how to develop and run the JDG application discussed above. For further details on JDG please visit: http://www.redhat.com/products/jbossenterprisemiddleware/data-grid/


Webinar: Introduction to JBoss Data Grid -- Installation, Configuration and Development

 

In this webinar we will look at the basics of setting up JBoss Data Grid covering installation, configuration and development. We will look at practical examples of storing data, viewing the data in the cache and removing it. We will also take a look at the different clustered modes and what effect these have on the storage of your data:






20 March 2014

MIDDLEWARE INSIGHT - C2B2 Newsletter Issue 15

            

 

MIDDLEWARE INSIGHT

At the Hub of the Middleware Industry

 


FEATURED NEWS


WildFly 8 is Now Available! - read more
Swiss Java Knife - A useful tool to add to your diagnostic tool-kit? - read more



JAVA / OPEN SOURCE

Java 8
Java 8 Launch Webcast, 25th of March, register here
JDK 8: General Availability, read the post by Mark Reinhold  
Java 8 is going live today - here's your crib sheet, read more on Jaxenter.com 
JAX Magazine goes Java 8 crazy this March, see the magazine here  


GlassFish
An Introduction to Connection Pools in Glassfish, read the post by Andy Overton 
GlassFish v4 Management, Automation and Monitoring by Adam Bien - watch the video here
Commercial GlassFish Support Is Back - read Adam Bien's Interview with Steve Millidge 
Writing and Deploying a Simple Web Application to GlassFish, read more here 
 
 
Other
Java EE 8 : What does the community want? Find out more 
Swiss Java Knife - A useful tool to add to your diagnostic tool-kit?, read more on the C2B2 Blog 
Apache httpd 2.2 and not so sticky sessions, read the post by Jaromir Hamala
Oh, you think Java sucks? How refreshing - read the article by Lucy Carey
Web Socket Implementation in Tomcat 7 and Jaggery, read more on Madhuka's blog
Abandon Fish! Migrating from GlassFish to JBoss or TomEE, read more by Simon Maple 
JPA 2.1 Entity Graphs, find out more on The Aquarium blog   

ORACLE

Getting the most out of WebLogic Diagnostic Framework Part 1: What is the WLDF? Read the article by Mike Croft
How to start multiple WebLogic managed servers, find out more on Zemian Blog  
Migrating from GlassFish to WebLogic: The Beauty of Java EE, read more on The Aquarium
How to create MySQL DataSource in WebLogic Server, read more here 
Common WebLogic Problems by Steve Millidge, read more on the WebLogic Community Blog
Deploying Jenkins to a WebLogic Server, read the article by Peter Lorenzen
C2B2 Wins the WebLogic Partner Community Award 2014, read more here 

JBOSS & RED HAT

WildFly 8
WildFly 8 is now available! read more on Arun Gupta's Blog
Wildfly 8.0.0.Final is Released, read an overview by Mark Addy 
WildFly 8.0 joins roster of certified Java EE7 apps, read more on Jaxenter.com 
WildFly 8 versus TomEE versus WebLogic, and other matters, read more on Jaxenter.com
Taking WildFly 8 for a test drive, read the article by Bernhard Lowenstein

Other

Red Hat drops "unique" business process management suite, read more on Jaxenter.com 
Handling Deployments When Provisioning JBoss domain.xml (With Ansible), read more on The Holy Java Blog
Red Hat officially announces release of JBoss BPM Suite 6 and JBoss BRMS 6, read more on Eric Schabell's Blog 
Red Hat JBoss BPM Suite - access GIT project using SSH, read more on Eric Schabell's Blog  
Infinispan Map/Reduce parallel execution, read more on the Infinispan Blog  
Fabric8, JBoss Fuse and Apache Karaf versions, read more on James Strachan's Blog  

 DATA GRIDS

Hazelcast & Websockets, read more on the C2B2 Blog 
JBoss Data Grid Webinar Series - watch the videos here
Steve Millidge for JaxMagazine - Processing on the Grid, read more here  
GridGain Goes Open Source Under Apache v2.0, read more on DZone  

CONFERENCES & CALLS FOR PAPERS

Devoxx UK - 12 & 13 June 2014 - find out more and get your tickets here 
JAX London 2014, Call for Papers is now open until the 4th of April, find out more 
JavaOne, Call for Papers is now open until the 15th of April, find out more  
JavaZone, Call for Papers is now open until the 28th of April, find out more 

19 March 2014

Getting the most out of WLDF Part 1: What is the WLDF?

The WebLogic Diagnostic Framework (WLDF) is an often overlooked feature of WebLogic which can be very powerful when configured properly.

If it’s so great, then why aren’t more people using it?

I can’t give a firm answer to that, but I suspect that the answer is likely because WLDF is so large, so comprehensive, and so terrifying to the uninitiated! There are a lot of concepts to get your head round before you can make good use of it, such that people frequently don’t bother. After all, where do you start with something so big?

In this blog, I hope to remedy that feeling a little, by pointing out some of the low-hanging fruit so you can get to know enough of the basics that you’ll be able to make use of some of the features, while having enough of a knowledge of the framework to take things further yourself.

12 March 2014

Swiss Java Knife - A useful tool to add to your diagnostic tool-kit?

Introduction

As a support consultant I am always looking for handy tools that may be able to help me or my team in diagnosing our customers middleware issues. So, when I came across a project called Swiss Java Knife promising tools for 'JVM monitoring, profiling and tuning' I figured I should take a look. It's basically a single jar file that allows you to run a number of tools most of which are similar to the ones that come bundled with the JDK.

If you're interested in those tools my colleague Matt Brasier did a good introductory webinar which is available here:

http://www.c2b2.co.uk/jvm_webinar_video

Downloading

Firstly I downloaded the latest jar file from github:

https://github.com/aragozin/jvm-tools

The source code is also available but for the purposes of this look into what it can offer the jar will suffice.

What does it offer?

Swiss Java Knife offers a number of commands:

jps - Similar to the jps tool that comes with the JDK.
ttop - Similar to the linux top command.
hh - Similar to running the jmap tool that comes with the JDK with the -histo option.
gc - Reports information about GC in real time.
mx - Allows you to do basic operations with MBeans from the command line.
mxdump - Dumps all MBeans of the target java process to JSON.

Testing

In order to test out the commands that are available I set up a Weblogic server and deployed an app containing a number of servlets that have known issues. These are then called via JMeter to show certain server behaviour:
  • excessive Garbage Collection
  • high CPU usage
  • a memory leak

Finding the process ID

Normally to find the process ID I'd use the jps command that comes with the JDK.

Swiss Java Knife has it's own version of the jps command so I tried that instead.

Running the command:

java -jar sjk-plus-0.1-2013-09-06.jar jps

gives the following output:

5402 org.apache.derby.drda.NetworkServerControl start
3250 weblogic.Server
4032 ./ApacheJMeter.jar
3172 weblogic.NodeManager -v
5427 weblogic.Server
6523 sjk-plus-0.1-2013-09-06.jar jps

Which is basically the same as running the jps command with the -l option.

There are a couple of additions where you can add filter options allowing you to pass in wild cards to match process descriptions or JVM system properties but overall it adds very little to the standard jps tool.
jps -lv will generally give you everything you need.

OK, so now we've got the process ID of our server we can start to look at what is going on. First of all, lets check garbage collection.

Checking garbage collection

OK. Now this one looks more promising. Swiss Java Knife has a command for collecting real time GC statistics. Let's give it a go.

So, running the following command without my dodgy servlet running should give us a 'standard' reading:

java -jar sjk-plus-0.1-2013-09-06.jar gc -p 3016

[GC: PS Scavenge#10471 time: 6ms interval: 113738ms mem: PS Survivor Space: 0k+96k->96k[max:128k,rate:0.84kb/s] PS Old Gen: 78099k+0k->78099k[max:349568k,rate:0.00kb/s] PS Eden Space: 1676k-1676k->0k[max:174464k,rate:-14.74kb/s]]
[GC: PS MarkSweep#10436 time: 192ms interval: 40070ms mem: PS Survivor Space: 96k-96k->0k[max:128k,rate:-2.40kb/s] PS Old Gen: 78099k+7k->78106k[max:349568k,rate:0.19kb/s] PS Eden Space: 0k+0k->0k[max:174400k,rate:0.00kb/s]]

PS Scavenge[ collections: 31 | avg: 0.0057 secs | total: 0.2 secs ]
PS MarkSweep[ collections: 9 | avg: 0.1980 secs | total: 1.8 secs ]

OK. Looks good. Useful to be able to get runtime GC info without having to rely on GC logs which are often not available.

After running my dodgy servlet (containing a number System.gc() calls) we see the following:

[GC: PS Scavenge#9787 time: 5ms interval: 38819ms mem: PS Survivor Space: 0k+64k->64k[max:192k,rate:1.65kb/s] PS Old Gen: 78062k+0k->78062k[max:349568k,rate:0.00kb/s] PS Eden Space: 204k-204k->0k[max:174336k,rate:-5.28kb/s]]
[GC: PS MarkSweep#10200 time: 155ms interval: 112488ms mem: PS Survivor Space: 64k-64k->0k[max:192k,rate:-0.57kb/s] PS Old Gen: 78071k+0k->78071k[max:349568k,rate:0.00kb/s] PS Eden Space: 0k+0k->0k[max:174336k,rate:0.00kb/s]]

PS Scavenge[ collections: 666 | avg: 0.0046 secs | total: 3.1 secs ]
PS MarkSweep[ collections: 689 | avg: 0.1588 secs | total: 109.4 secs ]

A big difference and although not a particularly realistic scenario it's certainly a useful tool for being able to quickly view runtime GC info.

Next up we'll take a look at CPU usage.

Checking CPU usage

Swiss Java Knife has a command that works in a similar way to the linux top command which displays the top CPU processes.

Running the following command should give us the top 10 CPU processes when running normally:

java -jar sjk-plus-0.1-2013-09-06.jar ttop -n 10 -p 5427 -o CPU

2014-03-11T08:56:33.120-0700 Process summary
  process cpu=2.21%
  application cpu=0.67% (user=0.30% sys=0.37%)
  other: cpu=1.54%
  heap allocation rate 245kb/s
[000001] user= 0.00% sys= 0.00% alloc=     0b/s - main
[000002] user= 0.00% sys= 0.00% alloc=     0b/s - Reference Handler
[000003] user= 0.00% sys= 0.00% alloc=     0b/s - Finalizer
[000004] user= 0.00% sys= 0.00% alloc=     0b/s - Signal Dispatcher
[000010] user= 0.00% sys= 0.00% alloc=     0b/s - Timer-0
[000011] user= 0.00% sys= 0.01% alloc=    96b/s - Timer-1
[000012] user= 0.00% sys= 0.01% alloc=    20b/s - [ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'
[000013] user= 0.00% sys= 0.00% alloc=     0b/s - weblogic.time.TimeEventGenerator
[000014] user= 0.00% sys= 0.04% alloc=   245b/s - weblogic.timers.TimerThread
[000017] user= 0.00% sys= 0.00% alloc=     0b/s - Thread-7

So far so good, minimal CPU usage. Now I'll run my dodgy servlet and run it again:

Hmmm, not so good:

Unexpected error: java.lang.IllegalArgumentException: Comparison method violates its general contract!

Try once again and we get the following:

2014-03-11T09:00:10.625-0700 Process summary
  process cpu=199.14%
  application cpu=189.87% (user=181.57% sys=8.30%)
  other: cpu=9.27%
  heap allocation rate 4945kb/s
[000040] user=83.95% sys= 2.82% alloc=     0b/s - [ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'
[000038] user=93.71% sys=-0.44% alloc=     0b/s - [ACTIVE] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'
[000044] user= 3.90% sys= 4.91% alloc= 4855kb/s - RMI TCP Connection(5)-127.0.0.1
[000001] user= 0.00% sys= 0.00% alloc=     0b/s - main
[000002] user= 0.00% sys= 0.00% alloc=     0b/s - Reference Handler
[000003] user= 0.00% sys= 0.00% alloc=     0b/s - Finalizer
[000004] user= 0.00% sys= 0.00% alloc=     0b/s - Signal Dispatcher
[000010] user= 0.00% sys= 0.00% alloc=     0b/s - Timer-0
[000011] user= 0.00% sys= 0.04% alloc=  1124b/s - Timer-1
[000012] user= 0.00% sys= 0.00% alloc=     0b/s - [STANDBY] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'

So, the CPU usage is now through the roof (as expected).

The main issue with this is that similar to the jps command it doesn't really offer much more than the top command. It also threw the exception above many times when trying to run commands ordered by CPU.

Overall, it doesn't really add much to the command already available and unexpected errors are never good.

Finally, we'll take a look at memory usage.

Checking memory usage

For checking memory usage Swiss Java Knife has a tool called hh which it claims is an extended version of jmap -histo. For those not familiar with jmap, it's another of the tools that comes with the JDK which prints shared object memory maps or heap memory details for a process.

So, first of all I run my JMeter test that repeatedly calls my dodgy servlet. This time one that allocates multiple byte arrays each time it's called to simulate a memory leak.

Although it claims to be an extended version of jmap -histo the only real addition is the ability to state how many buckets to view but this can be easily achieved by piping the output of jmap -histo through head. Aside from that the output is virtually identical.

Output from jmap:

 num     #instances         #bytes  class name
----------------------------------------------
   1:         42124      234260776  [B
   2:        161472       24074512  <constMethodKlass>
   3:        161472       21970928  <methodKlass>
   4:         12853       15416848  <constantPoolKlass>
   5:         12853       10250656  <instanceKlassKlass>
   6:         84735        9020400  [C
   7:         10896        8943104  <constantPoolCacheKlass>
   8:         91873        2939936  java.lang.String
   9:         14021        1675576  java.lang.Class
  10:         10311        1563520  [Ljava.lang.Object;

  Output from sjk:

  java -jar sjk-plus-0.1-2013-09-06.jar hh -n 10 -p 5427

    1:         56626      386286072  [B
   2:        161493       24076192  <constMethodKlass>
   3:        161493       21973784  <methodKlass>
   4:         12850       15409912  <constantPoolKlass>
   5:         12850       10249384  <instanceKlassKlass>
   6:         10891        8936672  <constantPoolCacheKlass>
   7:         83336        8577720  [C
   8:         90525        2896800  java.lang.String
   9:         14018        1675264  java.lang.Class
  10:          9819        1579400  [Ljava.lang.Object;
Total        996089      500086120

The only other tools available are the commands mxdump and mx which allow access to MBean attributes and operations.

However, trying to run either of these resulted in a Null pointer exception. 

At this point I would generally download the code and start to poke about but by now I'd seen enough.

Conclusion

Although a nice idea it's very limited in what it offers. Under the covers it uses the Attach API so requires the JDK and not just the JRE in order to run so the majority of tools available are already provided with the standard JDK. There are a few additions to those tools but nothing that really makes it worthwhile using this instead.

The only tool I could see myself using would be the real-time GC data gathering tool but this would only be of use where GC logs were unavailable and no other monitoring tools were available.

The number of errors seen when running basic commands was also a concern, although this is just a project on github not a commercial offering and doesn't appear to be a particularly active project.

So, a useful tool to add to your diagnostic tool-kit? Not in my opinion. It's certainly an interesting idea and with further work could be useful but for now I'd stick with the tools that are already available.







6 March 2014

Writing and Deploying a Simple Web Application to GlassFish

Introduction 
       
            This blog will detail how to create a simple Web Application (Web App) on a Windows 7 64 bit system and deploy it to a GlassFish 4.0 server. The web app will be kept simple, so as to keep the focus of the tutorial on the concepts; as such, the web app will provide a web page prompting the user to enter their name and date of birth, before loading another page that repeats their name back at them with their age. The blog will cover how to set up, code, and deploy the web app using the NetBeans IDE, as well as how to manually deploy it using the Windows command prompt. It should be noted that unless stated otherwise, any additional settings that can be changed but are not noted in the guide should be left as their default.

            This guide was written using the following:
  • Windows 7 
  • GlassFish 4.0
  • Java EE 7 32 bit 
  • JDK 1.7.0_45 32 bit 
  • NetBeans 7.4
             Though just an introductory tutorial, the web app will be designed with good practices in mind, and so will be designed upon the Model View Controller (MVC) pattern to provide good separation of concerns. As such, the web app will have the following structure:

Diagram showing the architecture of the web app

Step 1: Initial Set up and Configuration
       
            This step covers how to install and configure the software that was used in this blog (excluding Windows!).

Installation

Java

            It is possible to download a bundle that contains the Java SDK and JDK, as well as GlassFish.
  • Go to http://www.oracle.com/technetwork/java/javaee/downloads/index.html
  • To download the SDK, JDK, and GlassFish, click on the download link for Java EE 7 SDK with JDK 7 U45 and select Windows (not Windows x64, this guide is using 32 bit Java).
  •  Install to the default location like any other regular program
    • If you decide to install in a different location, you will have to alter any explicit file paths in the guide to correspond to your own installation location.
NetBeans IDE

            NetBeans can be downloaded with support for various technologies, and can come bundled with GlassFish 4.0. Feel free to download NetBeans with everything, but for this tutorial only the Java EE version is required.
  • Go to https://NetBeans.org/downloads/index.html
  • Click on the Download button for Java EE
    •  You may note that this also comes bundled with GlassFish 4.0. Handy, but redundant at this stage if you’ve followed this guide.
  • Install like any other program, to the default location
    • You can configure it not to reinstall GlassFish, or simply leave it as default; reinstalling GlassFish with NetBeans has the positive outcome of NetBeans auto-configuring a default GlassFish Server for you to deploy the web app to, though it does default to a different install location, potentially letting you install GlassFish twice.
Configuration

Set Java Environment Variables
            Only really necessary if you are using the command prompt, setting the Java environment variables allows Windows to automatically know where to look for Java and its libraries. Doing this saves you having to explicitly type out the path name to Java whenever you want to use it.
  •  Click on Start, and then right click on Computer and select Properties
  •  Select Advanced System Settings from the list on the left of the window.
  •  Click on Environment Variables
  • Select the Path variable under System Variables, and click on Edit
  •  Add the path for the JDK bin – on a default installation that is: C:\Program Files (x86)\Java\jdk 1.7.0_45\bin
    • Ensure there is a semi colon separating out the extra path directory from the previous directory
It is also prudent to add the JAVA_HOME environment variable whilst here.
  • Click New under System Variables
  •  Enter JAVA_HOME as the variable name
  • Enter the file path of the JDK – on a default installation that is: C:\Program Files (x86)\Java\jdk 1.7.0_45
GlassFish
            As previously noted, the NetBeans IDE can come bundled with the GlassFish server. This is the simplest method to install and configure GlassFish, as it will automatically set up a default server for us to use. Given that we already have GlassFish installed however, it is possible to add our existing GlassFish server to NetBeans (though if you run into trouble at this step, you could just reinstall NetBeans with the bundled GlassFish).
  • Select Tools, then Servers from the NetBeans toolbar.
  • Select Add Server, on the bottom left of the pop up window.
  • Select GlassFish Server, and press Next.
    • You can leave the Name as the default “GlassFish Server”.
  • Browse to where GlassFish is installed and accept the license agreement before clicking Next.
  • If you let the Java installer install GlassFish, you should find it at: C:\glassfish4
  • Leave the domain location at “Register Local Domain”, and the Domain Name as “domain1”.
  • Enter “admin” as the user name, and a password if you want, before finally clicking Finish.
    • Note – If you let NetBeans set up the server, then when you first start up the server it will set a random String as the password with a username of admin. NetBeans won’t leave you in the dark though, it will auto fill in the password for you when it asks for it.
      • If you want to look at the username or password, you can find them by clicking Tools, then Servers, and selecting the server from the list.
Setting GlassFish Environment Variables

            If you intend to run GlassFish from the command prompt, it is recommended to alter the path environment variable to prevent having to move to the GlassFish directory or state the file path whenever you want to use it. This is done using the same method as setting the Java environment variable:
  • Click on Start, and then right click on Computer and select Properties
  • Select Advanced System Settings from the list on the left of the window.
  •  Click on Environment Variables
  • Select the Path variable under System Variables, and click on Edit
  • Enter the file path of the GlassFish bin folder
    • NetBeans Install: C:\Program Files (x86)\glassfish-4.0\bin
    • Java Install: C:\glassfish4\bin
  • Enter the file path of the GlassFish server
    • NetBeans Install: C:\Program Files (x86)\glassfish-4.0\glassfish
    • Java Install: C:\glassfish4\glassfish
Creating a NetBeans Project
            Before we begin writing any code, we must create a project in which to store and organise our files.
  • Click on File, then New Project.
    • Alternatively, use the keyboard shortcut Ctrl + Shift + N, or click on the New Project icon.
  • From within the popup window, select Java Web from the Categories list, and then Web Application from the Projects list.
  • Give your project a name, you can leave it as the default or give it your own name. For this blog, I will be naming it SimpleWebApp.
  • Once you have entered a name, click Next.
  • Select GlassFish Server and Java EE 7 Web as the Server and Java EE version respectively, before clicking Finish.

        If all is well, the project should be successfully created and will appear in the Projects pane on the left hand side of the IDE. An html file called index will also be created and opened in the main IDE view ready for editing, though we will leave this for now.

Step 2: Writing the Application Body
       
            This steps covers and explains the code that provides the workings for our web app.

The Person Class
       
            This class is a JavaBean, a Java class designed to enable easy reuse that conforms to a specific standard: It has a constructor that takes no arguments, properties that are accessed through Getters and Setters, and is Serializable. In our web app, the class is used to store information about the user, and allows other classes and pages to update and get information from it through Getter and Setter methods. To begin, we need to create the class for the code to go into:
  • Right click on the project, SimpleWebApp, hover over New to expand the list, and select Java Class.
  • Enter Person as the class name, and enter org.mypackage.models as the package.
  • Click Finish to create the class.
            To conform to the JavaBean standard, we need the class to implement Serializable, so add implements Serializable after the class declaration.
 public class Person implements Serializable  
            NetBeans will display that Serializable is causing an error. This is because we haven’t imported the interface, or specified its path. We can get NetBeans to do this for us by clicking on the offending line, pressing Alt and Enter together, and selecting to add the import for java.io.Serializable.

            Now that we have a class to work with, we can begin filling out the code:
  • Declare private variables of the following:
    • A String called name – This will be used to store the name of the user
    • A byte called age – This will be used to store the age of the user once it has been calculated. Unless filling in an obscure date of birth, a person is not realistically going to be over 127 years old, so only a byte is needed.
    • A String called dateOfBirth – This will be the String representation of the user given date of birth.
    • A Calendar called birthday – This will be the Calendar representation of the user’s date of birth, a more workable format for a date of birth.
    • A DateFormat called birthdateFormat – The accepted format of the user’s date of birth.
    • A Date called birthdate – This is the date of birth in a Date Format, used for converting the date of birth from a String to a Calendar.
    • A Calendar called todaysDate – Stores today’s date, used for calculating the age of the user.
       
            At this time the Calendar, DateFormat, and Date will be underlined with a red line signifying an error. This is, again, because we haven’t imported the classes or specified their paths. Add the imports for java.util.Calendar, java.text.java.text.DateFormat, and java.util.Date respectively.
  • Create a constructor with no arguments, initialising the variables as:
 name = "";  
 age = 0;       
 birthday = GregorianCalendar.getInstance();  
 birthdateFormat = new SimpleDateFormat("yyyy-MM-dd");  
 dateOfBirth = birthdateFormat.format(new Date());  
 birthdate = new Date();  
 todaysDate = GregorianCalendar.getInstance();  
            Errors will be thrown up for SimpleDateFormat and GregorianCalendar, import the classes java.text.SimpleDateFormat and java.util.GregorianCalendar in the same way as before to resolve these errors. We now need to create the Getter and Setter methods to allow access to the class properties, and NetBeans provides us with a handy way to generate these to save us typing it out:
    Window showing the settings for encapsulating the fields
  • Right click on the name variable in the Source Editor in the bottom left of NetBeans, expand the Refactor list, and click on Encapsulate Fields. This window displays the variables in the class that can be encapsulated, providing the means to generate Getter and Setter methods for variables, and to automatically set the visibility of said variables, Getter, and Setter methods. We can leave the default settings, but with two additions:
    • Create a Getter for age – We don’t need a Setter as this is calculated inside the class, not set by an external controller.
    • Create a Setter for dateOfBirth – We don’t need a Getter within the scope of this tutorial, as we don’t have any pages that will access this attribute.
  • Click Refactor to generate the code. Were our variables not already declared as private, the selection of private for the Field Visibility would have declared them as such for us. This will also have added JavaDoc annotations, metadata, for the Getter and Setter methods. 

            The code so far should look like this (minus the comments):
 package org.mypackage.models;  
   
 import java.io.Serializable;  
 import java.text.DateFormat;  
 import java.text.SimpleDateFormat;  
 import java.util.Calendar;  
 import java.util.Date;  
 import java.util.GregorianCalendar;  
   
   
 public class Person implements Serializable  
 {  
     private String name;  // The name of the user  
     private byte age;  // The age of the user  
     private String dateOfBirth; // The date of birth of the user  
     private Calendar birthday; // The birthday of the user  
     private DateFormat birthdateFormat; // The format of the birth date  
     private Date birthdate; // The dateOfBirth in a Date format  
     private Calendar todaysDate;  // Todays date  
        
     // Initialise any variables with default values  
     public Person()  
     {  
         name = "";  
         age = 0;       
         birthday = GregorianCalendar.getInstance();  
         birthdateFormat = new SimpleDateFormat("yyyy-MM-dd");  
         dateOfBirth = birthdateFormat.format(new Date());  
         birthdate = new Date();  
         todaysDate = GregorianCalendar.getInstance();  
     }  
   
     // The Getter method for the name  
     public String getName()   
     {  
         return name;  
     }  
   
     // The Setter method for the name  
     public void setName(String name)   
     {  
         this.name = name;  
     }  
   
     // The Getter method for the age  
     public int getAge()   
     {          
         return age;  
     }  
   
     // The Setter method for the date of birth  
     public void setDateOfBirth(String dateOfBirth)   
     {  
         this.dateOfBirth = dateOfBirth;  
     }  
 } 

            As noted previously, as the age attribute is not set by a servlet, we need to provide a method to calculate the age of the user from their supplied date of birth.
  • Create a private void method calculateAge().
  • Create a try clause – as we are parsing from a String to a Date, we need to catch a Parse Exception if one is thrown.
  • Within the try clause:
    • Parse the dateOfBirth String in the format of birthdateFormat, and set this as birthdate
 birthdate = birthdateFormat.parse(dateOfBirth);  
    • Use the setTime method of Calendar to set the birthday variable as the formatted Date value of birthdate
 birthday.setTime(birthdate);  
  • End the try clause and catch the exception with a basic message (bad practice as exceptions should not just be ignored like this, but for this demo we can get away with it).
     catch (ParseException ex)   
     {  
       System.out.println("Parse Exception when parsing the dateOfBirth");  
     }  
    
                With the String now parsed to a Calendar, we can make use of the Calendar methods to extract the year from the birthday and today’s date to calculate the user’s age.
    • Subtract the year of the user’s date of birth from today’s year to get the difference in years, before then casting it as a byte. Set the age variable as this value.
     age = (byte)(todaysDate.get(Calendar.YEAR) - birthday.get(Calendar.YEAR));  
    
                To accurately give the user’s age we need to take into account the day and month, else with the current method it is possible to give the user’s age as a year too high.
    • Add the age variable, currently representing the difference in years, to the user’s date of birth, the birthday variable, to get the user’s birthday for this year.
     birthday.add(Calendar.YEAR, age);  
    
    • Compare today’s date against the user’s birthday this year, using the todaysDate and birthday variables respectively, to see if today’s date is before the user’s birthday, decrementing age if it is.
     if (todaysDate.before(birthday))  
     {  
       age --;  
     }  
    
      The method should now look like this:
    private void calculateAge()  
    {  
           try   
           {  
              // Convert the user supplied date of birth String to a Date in the specified format  
              birthdate = birthdateFormat.parse(dateOfBirth);  
           
              // Cast the Date value to a Calendar to allow easier use  
              birthday.setTime(birthdate);  
           } 
      
           catch (ParseException ex)   
           {  
              System.out.println("Parse Exception when parsing the dateOfBirth");  
           }  
       
           // Calculate the age  
           age = (byte)(todaysDate.get(Calendar.YEAR) - birthday.get(Calendar.YEAR));  
           
           // Get the date of the user's birthday this year  
           birthday.add(Calendar.YEAR, age);  
           
           // Check if the user's birthday has passed this year  
           if (todaysDate.before(birthday))  
           {  
              // Reduce the age by one if it hasn't  
              age --;  
           }  
    }  
    

                Only one final thing remains to complete the Person class:
    • Add in the method call for calculateAge before the return statement in the getAge() method.
     calculateAge();  
    
                The final code for this class should look like this:
     package org.mypackage.models;  
       
     import java.io.Serializable;  
     import java.text.DateFormat;  
     import java.text.ParseException;  
     import java.text.SimpleDateFormat;  
     import java.util.Calendar;  
     import java.util.Date;  
     import java.util.GregorianCalendar;  
       
       
     public class Person implements Serializable  
     {  
         private String name;  // The name of the user  
         private byte age;  // The age of the user  
         private String dateOfBirth; // The date of birth of the user  
         private Calendar birthday; // The birthday of the user  
         private DateFormat birthdateFormat; // The format of the birth date  
         private Date birthdate; // The dateOfBirth in a Date format  
         private Calendar todaysDate;  // Todays date  
            
         // Initialise any variables with default values  
         public Person()  
         {  
             name = "";  
             age = 0;       
             birthday = GregorianCalendar.getInstance();  
             birthdateFormat = new SimpleDateFormat("yyyy-MM-dd");  
             dateOfBirth = birthdateFormat.format(new Date());  
             birthdate = new Date();  
             todaysDate = GregorianCalendar.getInstance();  
         }  
       
         // The Getter method for the name  
         public String getName()   
         {  
             return name;  
         }  
       
         // The Setter method for the name  
         public void setName(String name)   
         {  
             this.name = name;  
         }  
       
         // The Getter method for the age  
         public int getAge()   
         {      
             // Call the method to calculate the age before returning it  
             calculateAge();  
           
             return age;  
         }  
       
         // The Setter method for the date of birth  
         public void setDateOfBirth(String dateOfBirth)   
         {  
             this.dateOfBirth = dateOfBirth;  
         }  
         
         // The method that calculates the user's age from their date of birth  
         private void calculateAge()  
         {   
             try   
             {  
                // Convert the user supplied date of birth String to a Date in the specified format  
                birthdate = birthdateFormat.parse(dateOfBirth);  
           
                // Cast the Date value to a Calendar to allow easier use  
                birthday.setTime(birthdate);  
             }
        
             catch (ParseException ex)   
             {  
                System.out.println("Parse Exception when parsing the dateOfBirth");  
             }  
       
             // Calculate the age  
             age = (byte)(todaysDate.get(Calendar.YEAR) - birthday.get(Calendar.YEAR));  
           
             // Get the date of the user's birthday this year  
             birthday.add(Calendar.YEAR, age);  
           
             // Check if the user's birthday has passed this year  
             if (todaysDate.before(birthday))  
             {  
                // Reduce the age by one if it hasn't  
                age --;  
             }  
         }  
     }  
    

    The PersonServlet Class

    A servlet is, like a JavaServer Page, a means of enabling dynamic content in a web application. The servlet in our application takes the user input from the HTML index page and updates the attributes of a Person object, before loading a new web page to display the response.
    • Right click on the Project in the Projects pane, expand the New list, and select Servlet.
    • Provide a Class Name of PersonServlet, a Package of org.mypackage.controllers, and click Next
    • Check the box to Add information to deployment descriptor to generate the XML code providing the means of accessing the servlet from the index page.
                Click finish to create our servlet and generate default methods and imports. The processRequest method will be filled with default out statements from a PrintWriter, which you should delete as we don’t need them. This method takes the requests, wrapped as objects, from HTTP GET and POST methods as a parameter, thus allowing us to process them before giving a response.
    • Declare the private variables for the servlet to take in from the index page, name and dateOfBirth.
      • Declare and initialise the private variable to be used to identify what will be our Person object when passed to another page, personID.
       private String name;  // The user's name  
       private String dateOfBirth; // The user's date of birth  
       private String personID = "personBean";  // The ID of the Person object  
      
                  As you can read from the generated JavaDoc for the processRequest method, it processes requests for both the GET and POST HTTP methods, so let’s process what will be a GET request from our index page.
      • Initialise the name and dateOfBirth variables as the parameters of the same name from the HTTP request, with the getParameter method (be sure to put the parameters between ""!).
       name = request.getParameter("name");  
       dateOfBirth = request.getParameter("dateOfBirth");  
      
                    Initialise a Person object for use by the servlet. If you’re sharp you’ll remember having put it in another package, so be sure to provide the full path or import the package.
          import org.mypackage.models.Person; 

          Person person = new Person();  
          
          • With the Person object initialised, utilise its Setter methods to update the name and dateOfBirth attributes with those supplied by the user.
           person.setName(name);  
           person.setDateOfBirth(dateOfBirth);  
          
                      With the attributes set, we need to pass control to another page to load the response for this specific Person object. To accomplish this, we set our person object and its identifier, personID, as attributes of the request, and pass control to the new page.
          • Set personID and person as attributes of the request.
           request.setAttribute(personID, person);  
          
          • Pass control to what will be our responding page, userAgeResponse.jsp, and forward the request and response parameters to it.
           RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/userAgeResponse.jsp");  
           dispatcher.forward(request, response);  
          
                      The final code for the PersonServlet (excluding the unchanged default methods) should look like this:

           package org.mypackage.controllers; 
            
           import java.io.IOException; 
           import javax.servlet.RequestDispatcher; 
           import javax.servlet.ServletException; 
           import javax.servlet.annotation.WebServlet; 
           import javax.servlet.http.HttpServlet; 
           import javax.servlet.http.HttpServletRequest; 
           import javax.servlet.http.HttpServletResponse;
           import org.mypackage.models.Person 
            
           // Specify the name of the servlet and the URL for it 
           @WebServlet(name = "PersonServlet", urlPatterns = {"/PersonServlet"}) 
           public class PersonServlet extends HttpServlet { 
            
               private String name;  // The user's name 
               private String dateOfBirth; // The user's date of birth 
               private String personID = "personBean";  // The ID of the Person object 
               
               /** 
                * Processes requests for both HTTP <code>GET</code> and <code>POST</code> 
                * methods. 
                * 
                * @param request servlet request 
                * @param response servlet response 
                * @throws ServletException if a servlet-specific error occurs 
                * @throws IOException if an I/O error occurs 
                */ 
               protected void processRequest(HttpServletRequest request, HttpServletResponse response) 
                    throws ServletException, IOException  
               { 
                   // Retrieve the user input values from the Welcome Page 
                   name = request.getParameter("name"); 
                   dateOfBirth = request.getParameter("dateOfBirth"); 
                
                   // Initialise a new Person object 
                   Person person = new Person(); 
               
                   // Update the default values in the Person object with the user supplied values 
                   person.setName(name); 
                   person.setDateOfBirth(dateOfBirth); 
               
                   // Set the person object and its identifier as attributes of the request 
                   request.setAttribute(personID, person); 
                
                   // Load the userAgeResponse Page 
                   RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/userAgeResponse.jsp"); 
                   dispatcher.forward(request, response); 
               }
           
            // … Default HttpServlet methods … 
          
           } 
          

          Step 3: Configuring the Web Pages
                 
                      Now that we have our classes that store the inputted attributes and control our web app, we need to configure the web pages that will use them!

          Creating and Configuring the userAgeResponse Page

                      The userAgeResponse page will be the page that is loaded once the user has submitted their name and date of birth, displaying in turn the user’s name back at them with their age. We begin, as usual, by creating a new file for our project:
          • Right click the SimpleWebApp node in the Projects window, expand the New list, and click on JSP, short for JavaServer Page.
          • Name the JSP userAgeResponse, leave the other settings as default, and click Finish.
          This creates the JSP and opens it in the editor for us to tinker with. Feel free to give the page a title, though it doesn’t actually affect the functionality at all. NetBeans allows us to generate HTML and other useful web content functions by dragging them from a window called the Palette into the editor at the point we want them generated. We will make use of this to save us typing out the code to utilise the JavaBean we created earlier:
          • Open the palette by clicking on Window from the NetBeans toolbar, expand the IDE Tools list, and select Palette
            • This can also be done with the keyboard shortcut Ctrl + Shift + 8
            Window showing the settings for inserting a Use Bean
          • Expand the JSP tab, and drag a Use Bean into the editor above the HTML tags of the page. A window will appear, enter personBean as the ID, org.mypackage.models.Person as the Class, and set the Scope to request. This will be used to access, as you may be able to tell from the parameters, the Person class, and the Get and Set methods within it. It will in particular be accessing the person object we created and sent to the page from our servlet, utilising the ID of personBean, which was the value of personID passed to it from the servlet.

           <jsp:useBean id="personBean" scope="request" class="org.mypackage.models.Person" />  
          
          • Drag two Get Bean Propertys between the body tags with the Bean Name for both set to personBean, and the Property Name set as name for one, and age for the other. This calls the Getter method, for the name and age attributes respectively, from the class of the object with the ID specified in the Use Bean, person.  
          Window showing the settings for creating a Get Bean Property
          Window showing the settings for creating a Get Bean Property
           <jsp:getProperty name="personBean" property="name" />  
           <jsp:getProperty name="personBean" property="age" />  
          
          • Add some friendly text and a line break between the two Get Bean Properties for ease of reading to finish off the page.
           Hello <jsp:getProperty name="personBean" property="name" />!  
                 
           <br>  
                 
           You are <jsp:getProperty name="personBean" property="age" /> years old!  
          
          And with that, we have completed the userAgeResponse page, and it should look like this:

           <%@page contentType="text/html" pageEncoding="UTF-8"%>  
           <!DOCTYPE html>  
             
           <!--  
           Gain access to the person object  
           -->  
           <jsp:useBean id="personBean" scope="request" class="org.mypackage.models.Person" />  
             
           <html>  
             <head>  
               <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
               <title>Your Age</title>  
             </head>  
             <body>  
                 
                <!--  
                Pull the name and age of the user from the Person object 
                -->  
                Hello <jsp:getProperty name="personBean" property="name" />!  
                 
                <br>  
                 
                You are <jsp:getProperty name="personBean" property="age" /> years old!  
                 
             </body>  
           </html>  
             
          

          Configuring the Index Page
                 
                      With a page that responds to the user, we need to finish our web app by configuring our front web page, the index page, to allow user input. Navigate to the index page in the IDE, and again feel free to supply the page with a title. NetBeans can help us out again by providing means of generating much of the code to supply user input for us:
            Window showing the settings for creating an input form
          • Open up the Palette if it isn’t already open, and expand the HTML Forms menu. Remove any default text inside of the body of the code, before pulling a Form into the body from the Palette. Set our servlet, PersonServlet, as the Action, GET as the Method, and give it a Name of inputForm. This specifies that the inputs from this form will be sent to our servlet via the HTTP GET method.
           <form name=“Input Form” action=“PersonServlet”>  
          

          Window showing the settings for creating a text input field
          • Make some space between the form tags, and place a Text Input item inside. Give the input a Name of name, and hit OK, leaving the other fields as default. The Name field in this instance is giving the variable name to be passed, so is the same name parameter extracted from the HTTPServletRequest request in our servlet.

             <input type=“text” name=“name” value=“” />  
            

                        You may remember that we took in two parameters from the HTTPServletRequest in our servlet, the other being dateOfBirth.
            • Create another Text Input with the name of dateOfBirth to satisfy this foresight of ours. Once generated, alter the type from text to date, providing some input validation, and provide it a default date value of the format yyyy-mm-dd to give the user a visual cue of the input format if the browser does not support providing automatic formatting for the HTML date tag. 
             <input type=“date” name=“dateOfBirth” value=“2014-01-29” />  
            
            • Type in some descriptive text before the text inputs to give the input fields a label for the user to see, and place a line break between the fields to improve readability.
             Enter Your Name: <input type="text" name="name" value="" />  
                     
             <br>  
                     
             Enter Your Date of Birth: <input type="date" name="dateOfBirth" value="2014-01-29" />  
            
              Window showing the settings for creating a submit button
            • Finally, place another line break after the text inputs and drag a Button in, giving it a Label of Submit, leaving the Type as Submit, and a Name of submitButton.
             <input type=”submit” value=”OK” />  
            

                        With that, our index page, and our web app, are done! See below for what the code of the index page should look like:

             <!DOCTYPE html>  
             <html>  
               <head>  
                 <title>Welcome Page</title>  
                 <meta charset="UTF-8">  
                 <meta name="viewport" content="width=device-width">  
               </head>  
               <body>  
                   
                   <!--   
                   Create an input form to take in the user's name and date of birth  
                   and send them to the servlet  
                   -->  
                   <form name="Input Form" action="PersonServlet">  
                 
                     <!--  
                     Provide a label for the user to read and input fields,  
                     passing on the name and date of birth  
                     -->  
                     Enter Your Name: <input type="text"   
                                  name="name"   
                                  value="" />  
                     
                     <br>  
                     
                     Enter Your Date of Birth: <input type="date"   
                                       name="dateOfBirth"   
                                       value="2014-01-29" />  
                     
                     <br>  
                     
                     <!--  
                     Provide a button as a means of submitting the user's data  
                     -->  
                     <input type="submit" value="Submit" name="Submit Button"/>  
                     
                  </form>  
               </body>  
             </html>  
            

            Step 4: Deploying the Web App
                   
                        This section will be split into two sections detailing two methods of deploying the application: the “manual” method, utilising the command prompt, and the “IDE” method, utilising NetBeans.

            IDE
                   
                        To deploy the web app to the GlassFish server, simply press the Run button. This starts up the GlassFish server and deploys the web app to the server using directory deployment before opening your web browser at the index page. Directory deployment is deploying a web app to the GlassFish server by utilising a structured directory instead of a web archive file (WAR). Alternatively:

            • Right click on the project in the Projects pane, and click on deploy. This will start the GlassFish server, if it isn’t already running, undeploy any current version of the web app already deployed, and deploy the web app to the server.
            • Click on the Run button, and the web app will now load in your browser.
            Manual
                   
                        To begin with, we need to build the project, creating a WAR file. A WAR file is a type of Java Archive file (JAR) containing a packaged web application; it is an archive composed of the JSP, HTML and other files of the web application, as well as a runtime deployment descriptor (XML file) describing to the application server how to run the web app.
            • In NetBeans, right click on the project in the Projects window and click on Clean and Build.
                        This creates the WAR file by default in a new folder, dist, under the project folder in NetBeansProjects, found in Documents. Open up the command prompt and, assuming you have set the GlassFish path environment variables, the following steps should start the server and deploy the web app. Note, you may need to run the command prompt as an administrator to get the server to start.
            • Enter the command asadmin start-domain. The asadmin command is a GlassFish utility that lets you run administrative tasks, such as starting and stopping servers. As we are using the default GlassFish server, domain1, we do not need to enter a domain name.
            • Navigate to the dist folder containing the SimpleWebApp.war file.
              • Alternatively you can type out the file path to SimpleWebApp.war each time it is used.
            • Type the command asadmin deploy SimpleWebApp.war.
              • If the SimpleWebApp is already deployed, you can force a redeploy using the following command - asadmin deploy --force=true SimpleWebApp.war.
            • Open your browser and navigate to http://localhost:8080/SimpleWebApp  
             Done!

                        And with that, you have created a web app and (hopefully!) seen the satisfying "Command deploy executed successfully" message, signifying that you have just deployed your hard work to a GlassFish application server!