GlassFish Embedded Reloaded, an appserver in your pocket

It wasn't enough for GlassFish v3 to be broken into 200+ OSGi bundles executable on different OSGi implementations such as Felix or Equinox (or even without OSGi, i.e. in "Static" mode), we also had to make it embeddable (in-process, using an API).

In a previous entry, I discussed EJBContainer.createEJBContainer() (a standard EJB 3.1 API) which is really a specific use-case of the more generic case of using the GlassFish Embedded API. The latter is the topic of this newer post and whichever you decide to use, you should remember that this is all one code-base offering different facets with as many entry points.

Definition

GlassFish embedded is in-process integration of the GlassFish v3 features (not just the web container) using an API to start/stop/configure the server and its containers and to deploy/undeploy applications.

While this definition and the use-cases (testing, shipping shrink-wrapped apps, ...) has not changed since GlassFish v3 Prelude which shipped a year ago, the API has substantially evolved (up to promoted build 65 in late September I believe) as you can read below and can now be considered stable. As you'll see later in this post, the deployment can be trivial.

An overview of the API

Main classes are :
    org.glassfish.api.embedded.Server
    org.glassfish.api.embedded.EmbeddedFileSystem
    org.glassfish.api.embedded.ContainerBuilder
    org.glassfish.api.embedded.EmbeddedDeployer
    org.glassfish.api.deployment.DeployCommandParameters

Update: you'll find the entire API for Java EE 6 and GlassFish v3 here.
Update 2: make sure you read the formal "Embedded Server Guide" documentation now available for GlassFish v3

The API offer a flexible inner-class Builder pattern :
     EmbeddedFileSystem.Builder efsb = new EmbeddedFileSystem.Builder();
     efsb.installRoot(EmbeddedServerUtils.getServerLocation());

Simple Hello world

Let me walk you through a simple example which deploys an existing WAR from a main() which in turn would let you ship and start the entire app using a JAR (full source here). I'll leave it as a simple exercise to the reader to adapt it to the testing use-case.

First the logic :
     foo.Embedded myGlassFish = new foo.Embedded("myArchive.war"); // init with the archive name
     myGlassFish.start();
     boolean deployed = myGlassFish.deploy();
     if (deployed) {
         // TODO: do something  useful  like wait for a shutdown order
        
     }
     myGlassFish.undeployAndStop(); // stops and exits the JVM

The startup process :
     public void start() throws IOException {
         Server.Builder builder = new Server.Builder("testBuilder");
        
         // get the builder for EmbeddedFileSystem
         EmbeddedFileSystem.Builder efsb = new EmbeddedFileSystem.Builder();
         EmbeddedFileSystem efs = efsb.build();
         builder.embeddedFileSystem(efs);
    
         // Start the embedded server (should take no more than a few of seconds)
         server = builder.build();
    
         // Add a WEB container (other containers include ejb, jpa, all, ...)
         ContainerBuilder containerBuilder = server.createConfig(ContainerBuilder.Type.web);
         server.addContainer(containerBuilder);
         containerBuilder.create(server);
         server.createPort(port); // Starts grizzly on the given port
     }

The deployment :
     public boolean deploy() {
         // Setup machinery to deploy
         deployer = server.getDeployer(); // type is EmbeddedDeployer
         DeployCommandParameters deployParams = new DeployCommandParameters();
         deployParams.name = "myApplication"; // needed for undeploy
         deployParams.contextroot = context; // overrides whatever the WAR contains
        
         // Creates default virtual server, web listener, does the deploy and
         // returns the applicationName as a String (null means something went wrong)
         // duration depends on application size and nature. Heavy lifting done here.
         File archive = new File(archiveName);
         applicationName = deployer.deploy(archive, deployParams);
         return (applicationName == null) ? false : true;
     }

... and the cleaning up :
     public void undeployAndStop() throws LifecycleException {
         deployer.undeploy(applicationName, null); // Could have undeploy params like cascade, ...
         server.stop(); // May take a little while to clean everything up
         System.exit(0); // to kill any threads left running
     }

The above example is only scratching the surface. You can deploy exploded archives (check out the org.glassfish.api.embedded.ScatteredArchive API) or reuse an existing domain.xml configuration file for instance. I'd like to encourage you to look around the various Embedded tests to find out more about the richness of the API.

As little as one JAR

There are two modes for running GlassFish Embedded :

implanted: this uses an existing GlassFish installation and requires having glassfish/lib/embedded/glassfish-embedded-static-shell.jar in your classpath. The JAR itself is an empty shell with relative references to all the JARs in the GlassFish v3 distribution. This is approach taken by NetBeans project tests for example.

autonomous: for easier distribution an all-in-one JAR file is available in two flavors: full profile (40 MB) and web profile (30 MB). Not bad for a full-blown app server! The complete application+runtime bundle can then be deployed using Maven, an installer (such as IzPack), a jar file (eventually wrapped in an .exe) or even via Java Web Start.

Still early days

Whether you're using the implanted or autonomous mode (using the uber-jar), you'll be running the same code, simply using different entry paths. Because of the different packaging and the temporary filesystem layout the autonomous mode uses, differences are always possible. Many issues were fixed in the past couple of months thanks, including some by users themselves.

Note that there is no OSGi involved in the embedded mode (I don't think this is a limitation, but it's certainly an important data point). It is much like running in static mode (same classloader hierarchy). There are also some limitations such as TimerEJB not being supported for the time being. But other than that, a non-trivial application like Hudson deploys to GlassFish embedded like a charm.

If this sounds interesting to you, please use a recent promoted build (b73 and above) or wait (a few weeks) for the GlassFish v3 final release in December (2009) and certainly ask questions on the USERS mailing list (or forum), and share your experience via blogs, tweets, etc...

Comments:

This is just so awesome.

I can not make unit tests so simple
No more Jetty , yay.

Posted by Richard Kolb on décembre 03, 2009 at 05:56 AM CET #

Jetty is still a nice product, but GlassFish does provide a complete Java EE 6 runtime.

Posted by Alexis MP on décembre 03, 2009 at 07:59 AM CET #

Will the Maven plugin support an embedded glassfish:run goal?

All our development in Maven is based around embedded Jetty via the jetty:run goal, which saves us the time required to build and deploy a WAR.

Without equivalent functionality. GFv3 would not be an option for us.

Posted by jacek on décembre 18, 2009 at 02:52 PM CET #

@jacek, the maven plugin has the following goals:
glassfish:run
glassfish:start
glassfish:deploy
glassfish:undeploy
glassfish:stop
glassfish:admin

Check out http://docs.sun.com/source/821-1208/index.html#gijhs

Posted by Alexis MP on décembre 19, 2009 at 06:17 AM CET #

Post a Comment:
Comments are closed for this entry.
About

This blog has moved

Alexis Moussine-Pouchkine's Weblog

GlassFish - Stay Connected

Search

Archives
« avril 2014
lun.mar.mer.jeu.ven.sam.dim.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today
Blogroll

No bookmarks in folder

News

No bookmarks in folder