Typical users of GlassFish use GlassFish in a separate process and they start GlassFish by using commands like the following:

java -jar glassfish.jar
                 or
asadmin start-domain

The above commands first launch an OSGi framework and then deploy the necessary bundles. What if you want toembed GlassFish in an existing OSGi runtime? The bootstrapping code was slightly complicated IMO. Recently when Apache Camel committer Charles Moulliard asked me some questions around embedding GlassFish v3 in an OSGi runtime, I decided to revisit the bootstrap module in order tosimplify it so that I had less explaining to do. I recently did exactly that. In this blog, I show how using a simple BundleActivator, one can embed GlassFish in an OSGi runtime. In the use case below, I first start an instance ofEquinox (plain vanilla Equinox runtime) anddeploy a test bundle which controls life cycle of GlassFish. You can use other launchers like karaf as well.

/tmp/equinox-3.5.1$ java -jar org.eclipse.osgi_3.5.1.R35x_v20090827.jar -console

osgi> install file:///tmp/embeddedgf-1.0-SNAPSHOT.jar
Bundle id is 1

osgi> start 1 
// The above command will start glassfish. You shall some output indicating the same.
// After GlassFish is started, you can use all regular GlassFish commands.
// e.g., to deploy an app, you can run "asadmin deploy ..."

osgi> stop 1
// This will stop GlassFish server. To start again, "start bundle #1"

What is this embeddedgf-1.0-SNAPSHOT.jar?

That's a tiny sample bundle I developed to embed GlassFish. It has a single class called GFActivator. This bundle activator does the following in the start() method:

1. Goes through glassfish modules directory and installs all bundles.

2. It then configures a configuration object with service PIDcom.sun.enterprise.glassfish.bootstrap.GlassFish. This is the PID for the <strong>ManagedService</strong> registered by GlassFish.  The PID name is subject to change. It then updates the configuration object with the following properties:

com.sun.aas.installRoot = /space/ss141213/WS/gf/v3/publish/glassfishv3/glassfish/
com.sun.aas.instanceRoot =  /space/ss141213/WS/gf/v3/publish/glassfishv3/glassfish/domains/domain1/

These two properties are enough for GlassFish to start.

3. It then locates GlassFish main bundle and starts it.

When I stop this bundle, it stops GlassFish server by stopping the main GlassFish bundle. Of course, you canrestart the bundle and GlassFish will be restarted. The java source and pom.xml are all part of this zip file.

GFActivator.java

package sahoo.embeddedgf;

import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.Configuration;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;

/**
 * Activator that starts and stops GlassFish.
 * To start glassfish, it does the following:
 * 1. Installs all bundles located in glassfish modules directory.
 * 2. Creates a configuration with a couple of properties:
 * com.sun.aas.installRoot and com.sun.aas.instanceRoot.
 * The former one refers to the directory where glassfish is installed.
 * (e.g., /tmp/glassfishv3/glassfish)
 * The latter one refers to the domain directory - this is a directory containing
 * configuration information and deployed applications, etc.
 * 3. Starts the main bundle of GlassFish. Main bundle is identified by Bundle-SymbolicName
 * org.glassfish.core.glassfish. This main bundle then is used to start any necessary bundle.
 *
 * In order to stop glassfish, we just stop the main bundle.
 *
 * @author Sanjeeb.Sahoo@Sun.COM
 */
public class GFActivator implements BundleActivator
{
    private BundleContext bundleContext;
    // I have hardcoded the glassfish path as this is just an example bundle.
    private String installRoot = "/space/ss141213/WS/gf/v3/publish/glassfishv3/glassfish/";
    private String instanceRoot = "/space/ss141213/WS/gf/v3/publish/glassfishv3/glassfish/domains/domain1/";
    private Bundle mainBundle;
    private static final String mainBundleName = "org.glassfish.core.glassfish";
    private static final String gfpid = "com.sun.enterprise.glassfish.bootstrap.GlassFish";
    private static final String JAR_EXT = ".jar";

    public void start(BundleContext bundleContext) throws Exception
    {
        this.bundleContext = bundleContext;
        // Install all gf bundles
        installBundles();
        configureBundles();
        startBundles();
    }

    public void stop(BundleContext bundleContext) throws Exception
    {
        if (mainBundle != null) {
            mainBundle.stop(Bundle.STOP_TRANSIENT);
        }
    }

    /**
     * Install all bundles located in modules directory and subdirectories under that.
     */
    private void installBundles() {
        for (File jar : findJars()) {
            try {
                bundleContext.installBundle(jar.toURI().toString());
            } catch (BundleException e) {
                // continue processing after logging the exception
                e.printStackTrace();
            }
        }
    }

    /**
     * Returns a list of jar files found in modules directory and subdirectories under that.
     * Any file with extension .jar is considered as a jar file.
     * @return a list of jar files
     */
    private List<File> findJars() {
        File modulesDir = new File(installRoot, "modules/");
        final List<File> jars = new ArrayList<File>();
        modulesDir.listFiles(new FileFilter(){
            public boolean accept(File pathname) {
                if (pathname.isDirectory()) {
                    pathname.listFiles(this);
                } else if (pathname.getName().endsWith(JAR_EXT)){
                    jars.add(pathname);
                }
                return false;
            }
        });
        return jars;
    }

    private void configureBundles() {
        final Properties props = new Properties();
        props.setProperty("com.sun.aas.installRoot", installRoot);
        props.setProperty("com.sun.aas.instanceRoot", instanceRoot);
        ServiceTracker tracker = new ServiceTracker(bundleContext, ConfigurationAdmin.class.getName(), null) {
            @Override
            public Object addingService(ServiceReference reference) {
                ConfigurationAdmin ca = ConfigurationAdmin.class.cast(bundleContext.getService(reference));
                try {
                    Configuration c = ca.getConfiguration(gfpid, null);
                    c.update(props);
                    close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return super.addingService(reference); //TODO(Sahoo): Not Yet Implemented
            }
        };
        tracker.open();
    }

    /**
     * Starts GlassFish primordial bundle
     */
    private void startBundles() {
        for (Bundle b : bundleContext.getBundles()) {
            if (mainBundleName.equals(b.getSymbolicName())) {
                mainBundle = b;
                try {
                    b.start(Bundle.START_TRANSIENT);
                } catch (BundleException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
 

Happy GlassFish-ing.

Statutory Warning: The code shown here is all sample code.