Tomcat is Dead, Long Live Glassfish!
December 26th, 2009 by SamSUN finished off 2009 with a release of Glassfish v3 - a high visibility Open Source implementation of Java Enterprise 6 - and the NetBeans 6.8 IDE.
Combined, these releases significantly reduce the barrier to entry for writing and deploying Java Enterprise applications. However, the documentation is sparse at best, and misleading at worst (some cases in point). This post documents getting Glassfish running with sensible parameters - unlike the defaults - covering:-
- Admin panel with secure connection and password
- mod-jk delegation from Apache
- Enabling the Security Manager
- Registering a PostgreSQL JDBC connection through JNDI
- Hibernate to access the JNDI via JPA, whilst allowing persistence in J2SE
mainmethods and tests.
Glassfish is much easier to configure than the perplexing Servlet Container, Apache Tomcat. With support for Ruby on Rails and PHP Web Applications, there is no good reason why anybody should still be using Tomcat - if anything, you should be asking yourself why you’re still using Apache HTTPD!
Installing on Ubuntu
The J2EE version of NetBeans comes with Glassfish and JavaDB bundled. Installation is therefore trivial on the development side. This focuses on installing Glassfish on a server machine, such as Ubuntu Hardy. Using elsewhere and elsewhere as a benchmark, the short version is to download the ZIP version of Glassfish v3 and unextract it into /opt/. Then create an executable script at /etc/init.d/glassfish containing the following
#!/bin/bash
GLASSFISH_AS_ADMIN="/opt/glassfishv3/bin/asadmin --secure=true" # might need to use "false" on first start
case $1 in
start)
$GLASSFISH_AS_ADMIN start-domain domain1
;;
stop)
$GLASSFISH_AS_ADMIN stop-domain domain1
;;
restart)
$0 stop
$0 start
;;
esac
exit 0
which allows the Glassfish server to start up or shutdown with /etc/init.d/glassfish start and /etc/init.d/glassfish stop respectively. The following command ensures that Glassfish starts up from reboots.
update-rc.d glassfish defaults 90 10
Securing Glassfish
By default, Glassfish allows unauthorised users to log on to an unencrypted port 4848 and upload applications that run with full root privileges. I consider this to be a major security hold and my first instinct was to get SSL, reboot, then install an admin password. Point your browser to port 4848 of your new Glassfish server and navigate to
Configuration -> Network Config -> Protocols -> admin-listener -> Check “Security Enabled”
restart the server and point your browser to the same location, this time using https. Then navigate to
Enterprise Server -> Administrator Password -> Enter “New Password”
then
Configuration -> Security -> Check “Security Manager”
and restart.
You should do these steps on a local installation of Glassfish, bundle up the binaries, and then send to your server - to avoid a race condition where the whole world has root access to your server. Alternatively, ensure that port 4848 is not world visible during these steps.
Delegation from Apache
mod_jk allows Apache to forward requests on the standard HTTP and HTTPS ports (80 and 443 respectively) to Glassfish, which might be running on any port. Clients never send requests to anything other than the standard ports - essential for bypassing over-zealous home or corporate firewalls.
I already had mod_jk forwarding requests to a Tomcat instance, so the details here are a little light on setting up the Apache-side configuration. They should be the same as for an Apache -> Tomcat bridge, luckily many Quick Start Guides exist. On Ubuntu, this amounts to typing
a2enmod jk
creating a /etc/apache2/workers.properties file containing something like
worker.list=worker1
worker.worker1.port=8009
worker.worker1.host=localhost
worker.worker1.type=ajp13
worker.worker1.lbfactor=1
adding the following to your /etc/apache2/sites-available/default (right up at the top, before any VirtualHost declarations)
JkWorkersFile /etc/apache2/workers.properties
and then in each virtual host, you add lines similar to
JkLogFile /var/log/apache2/HOSTNAME-mod_jk.log
JkLogLevel info
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkMount /MyJ2eeWebApp|/* worker1
to forward all requests beginning “/MyJ2eeWebApp.*” to the worker1 thread.
Go to the Glassfish admin panel and create a jk-listener through
Configuration -> Network Config -> New. enter name, e.g. “jk-listener” and select port number (8009 to agree with
worker1above) and tick “JK Listener”
Then restart/reload Apache.
Note that you need to enable each Web Application individually through mod_jk - it’s not possible to forward a directory (e.g. everything starting /j2ee/) to the base of the J2EE Web Applications. Which is unfortunate.
JNDI Access of JDBC Data Sources
Glassfish comes with built-in support for accessing the Apache Derby database - but it would be a stretch of the imagination to call this a deployment quality database. It’s very useful as a development database.
My preferred database is PostgreSQL, which has decent JDBC 4 support. Download the JDBC 4 driver and place it in the Glassfish /opt/glassfishv3/glassfish/domains/domain1/lib/ folder, then restart Glassfish.
To add a PostgreSQL JDBC source, use the Glassfish admin panel
Resources -> JDBC -> Connection Pools -> New
or
Common Tasks -> Create New JDBC Connection Pool
Use a descriptive CamelCaseName for your connection pool selecting javax.sql.DataSource as Resource Type and Postgresql as Vendor. In the next screen, go straight to the bottom and enter at least the following properties, depending on your database setup
databaseName = mydb
user = myusername
password = mypassword
portNumber = 5432
URL = jdbc:postgresql://localhost:5432/mydb
You might also want to tune the connection pool parameters, although you can always do that later.
Once done, click ping up at the top to confirm that the connection works. Then go to “JDBC Resources” and create a new resource using the naming convention of jdbc/your_db_name, select the newly created pool.
This JDBC connection is now available to any Application that requests it! You might want to further investigate the possibility of using a Security Policy for access to the JDBC connections.
JPA JNDI with Hibernate
For an introduction to JPA, see the Archive for the ‘JPA’ Category.
There are two options for using hibernate, either bundle with your apps or go to
Update Tool -> Available Add-Ons -> hibernate
Be careful about choosing the site-wide installation - SUN are currently shipping the “3.5 beta” release of Hibernate, which has a few bugs in it, but is an attempt at JPA 2 compliance - make sure this release of Hibernate plays nicely with your codebase and database providers. Removing Add-Ons is very complicated.
It is disappointing that the security policy is not set automatically. To allow hibernate to function, add the following to server.policy
grant {
permission java.util.PropertyPermission "*", "read";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
If anybody knows how to restrict this to just the Hibernate classes, please respond in the comments. So that you know what you’re enabling, see ReflectPermission. Security permissions can also be set on a per-application basis by editing granted.policy. A SUN blog claims “During deployment, the Glasfish policy provider translates security-contraints, method-permissions and common security annotations into grant statements and writes them to a file called granted.policy”, although I have yet to see an example of this working. Again, please comment below if you have an example.
This allows you to use whatever JDBC resource you like on your development or test environments - e.g. HSQLDB, Derby, PostgreSQL, MySQL - but provides you with access to your more stable database on deployment, without any changes to your persistence.xml. Note that because you’re not embedding your JDBC driver with your application, you have more freedom to use GPL drivers such as MySQL Connector-J.
A disadvantage of using the JDBC/JNDI approach is that you will need to be within a Container to access the database - and remember that the @PersistenceUnit annotation allows injection on Container managed classes such as Servlets
@PersistenceUnit(unitName="MyPU")
private EntityManagerFactory emf;
But this means that main applications and junit tests will fail to obtain a connection. It is possible to programmatically reset the JNDI data source and supply the URL of a database connection when obtaining an EntityManagerFactory
// properties are read from a hibernate.properties file - similar for other vendors
properties.put("javax.persistence.jtaDataSource", "");
properties.put("javax.persistence.nonJtaDataSource", "");
emf = Persistence.createEntityManagerFactory("MyPU", properties);
So try to write your code so that DAOs and other database-managing code take in the EntityManagerFactory instances so you know where the persistence units are coming from.
Alexis MP wrote:
December 27th, 2009 at 6:22 pm