Glassfish v3 Engineers Guide

Rev 0.3.5
Jerome Dochez


Jspwiki style: center

This document is basically a brain dump of how V3 is organized today with some insights on how it could be re-architected along the V3 engineering effort.

Change History

Version Comments Owner Wiki Revisions
0.1 Initial version Jerome Dochez 1
0.2 Additional sections added Jerome Dochez 1
0.3 Included feedback from community. Minor formatting changes. Additional hyperlinks. Paul Sterk 2-11
0.35 Included new subversion repository information Jerome Dochez 6-11

1 Modules

GlassFish v3 is built around a Module subsystem specified by the Hundred Kilobyte Kernel (HK2) project. Subsystem functionalities are declared through a Contract/Service implementation paradigm. HK2 Contracts identify and describe the building blocks or the extension points of an application. HK2 Services implement the Contracts. See HK2 Componentsfor more details.

1.1 What is a Module?

A Module is an encapsulated definition of reusable code. It offers Services, declares a Modules's dependencies on other Services, has public APIs, and a private set of classes implementing these APIs. To summarize, a Module :

  • is a set of java classes
  • offers Services or a public API or both
  • implements those public interfaces with a set of private classes.
  • requires other Modules (dependencies)

1.2 How to define a Module?

Defining a Module is not always easy and will in most cases be an iterative process. Answering the following questions help to define a Module:

  • Is my code offering very different kind of services?
  • Is my code offering some services independently of other services it supports?
  • Is my code used by more than one Module?

If you answer 'yes' to any of the above questions, the code should be encapsulated in a Module.

The easiest starting point is to check if your code offers more than one service. For instance, the current connector container offers 2 services to GlassFish v2: the JDBC driver container and the Java EE resource adapter container. These services could be defined as two Modules so they can be used independently.

From there, you also need to look into other services that your "code" offers to GlassFish. Don't create a Module just for the fun of it. One should create a Module only if it contains reusable code that can be used independently by other components (or just like above to make things more encapsulated/efficient).

1.3 Module definition

Once you have determined a set of classes that you want to offer as a Module, you need to start thinking about its definition. The definition is a name and a version that will be used by other modules to identify their dependency on your module.

The next aspect of modularization is to figure out the exact dependencies that your modules have. For instance, you may depend on the com.sun.enterprise:config-api. Note: the name of the module is constructed from a maven pom.xml using a group id and artifact id). What else ?

It is quite important to understand those dependencies, not only to successfully compile your Module(s), but also to understand what runtime Services are necessary for your module to function properly.

So, here are suggested steps on how to define code into a Module:

  • look at how many Modules you want to split your code into using the following criteria:
    • re-usability
    • isolation (can I use a feature without the others?)
    • efficiency (should I load 3Mb of jar files when only 100K of classes is used 95% of the time?)
  • figure out the exact dependencies for each identified Module

Once you have that information, even in an initial raw format, you can start thinking about refactoring the code or reduce the dependency trail and so on.

2 Modules Management

2.1 Glassfish Distributions

GlassFish V3 is built as a distribution artifact. A distribution (distro) is a collection of Modules, and an artifact is the file that contains the distro. There will be various distributions of GlassFish V3 each providing a unique set of features. For example, there will be a distro of just the core Modules, currently called Nucleus, that will be targeted at OEMs. Also planned are Web, J2EE and other distros.

Elements of a distribution are integrated using maven2 repositories. So, adding a Module to a GlassFish v3 distribution requires three steps:

  1. compile the Module and create the jar file with the necessary hk2 manifest entries
  2. publish the Module artifacts to a maven repository.
  3. add the Module's identification to the distribution list.

Distributions are constructed from binary files procured from a maven repository. There is a complete separation between how to produce a particular Module versus how this Module is integrated into a distribution.

2.2 Building a module

Each Module can be integrated in various distributions. Hence, there cannot be any distribution specific knowledge introduced during the Module's build.

Although a Module could be potentially built with other tools, it is highly recommended that a Module be built with maven2. The Maven2 build environment gives us the ability to run a number of maven plugins that can do some of the boiler plate activities such as HK2 manifest entries, components definition and so on.

A Module's source is usually comprised of the following artifacts (note: the directories shown below conform to the Maven Standard Directory Layout :

  • source code usually located in src/main/java
  • resources usually located in src/main/resources
  • a maven 2 pom.xml defining the Module's compilation process and the dependencies.

Although it is helpful to know more about the Maven2 pom.xml file, in most cases, it is not necessary to understand all the features of Maven to build a Module.

2.3 pom.xml structure

The basic structure of a pom.xml is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/maven-v4_0_0.xsd">

    <parent>
        <artifactId>bootstrap</artifactId>
        <groupId>com.sun.enterprise.glassfish</groupId>
        <version>10.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.jvnet.glassfish</groupId>
    <artifactId>glassfish-api</artifactId>
    <packaging>hk2-jar</packaging>
    <version>${project.parent.version}</version>
    <name>Public APIs of Glassfish V3</name>

    <developers>
	<!-- information on the module's developers -->
    </developers>
    <dependencies>
	<!-- Dependencies on other modules/jars -->
    </dependencies>
    <!-- Note: glassfish/bootstrap has java sources
         at src/java. Include these elements to
         comform to the Maven Standard Directory Layout -->
    <build>
      <sourceDirectory>src/main/java</sourceDirectory>
    </build>
</project>

The parent definition is important as it includes all the system wide properties like version identification, compilation and packaging rules for your Module.

Other important information :

  1. the name of your Module is the Maven2 groupId:artifactId tuple, here org.jvnet.glassfish:glassfish-api.
  2. the version is coming from the parent pom.xml which in this case is 10.0
  3. packaging is hk2-jar which makes this created bundle an HK2 jar with the right manifest entries and components definition.

2.3.1 adding a developer

Adding a developer to the module is defined at pom.xml:developers, but here is an example of adding myself as the Module owner (lead) and developer.

<developers>
    <developer>
        <id>dochez</id>
        <name>Jerome Dochez</name>
        <url>http://blogs.oracle.com/dochez</url>
        <organization>Sun Microsystems, Inc.</organization>
        <roles>
            <role>lead</role>
            <role>developer</role>
        </roles>
    </developer>
</developers>

2.3.2 Adding a dependency

Once your Module uses other Modules to compile properly, you need to add a dependency declaration to the pom.xml

<dependencies>
    <dependency>
        <groupId>com.sun.enterprise</groupId>
        <artifactId>hk2</artifactId>
        <version>${hk2.version}</version>
    </dependency>
</dependencies>

In the example above you can see that the module is using some HK2 core APIs. Whether you depend on a Module (hk2-jar) or a normal jar file does not change how you declare a dependency. The system will figure out the complete lists of dependencies.

2.4 Licenses

Modules inherit the parent Module's licenses information, but if your Module is not part of GlassFish's source license agreements, you should add the following declaration to your pom.xml

<licenses>
  <license>
    <name>Apache 2</name>
    <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
    <distribution>repo</distribution>
    <comments>A business-friendly OSS license</comments>
  </license>
</licenses>

2.5 Source code management

Each Module has a high degree of freedom on where to host its source code. The only condition for a Module to be included in a GlassFish distribution is to publish the Module binaries to a maven repository. If a Module is hosted by a different java.net project than glassfish.java.net, its pom.xml should include a source code management entry and a issue tracker management entry like this:

<scm>
        <connection>scm:hg:http://mercurial.sfbay.sun.com/glassfish_v3</connection>
    </scm>
    <issueManagement>
        <system>IssueTracker</system>
        <url>https://glassfish.java.net/servlets/ProjectIssues</url>
    </issueManagement>

2.6 Build magic

2.6.1 Maven plugins

A number of maven plugins have been developed to help the task of building Modules. These plugins will use the pom.xml or the annotated classes to generate the metadata associated with a module like its HK2 manifest entries as well as its components definition. These plugins are declared in the GlassFish bootstrap pom.xml (used as a parent for each module pom.xml) therefore relieving the module owner from having to call the plugins themselves or create the metadata by hand.

2.6.2 ant

It is still sometimes useful to call ant tasks while building your Module, here is an example on how to do that :

<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
        <execution>
            <phase>process-sources</phase>
            <configuration>
                <tasks>
                    <copy file="jsp-api.mf"
                          toFile="${project.build.directory}/manifest.mf">
                         <filterset>
                             <filter token="VERSION" value="${jsp.spec.version}"/>
                         </filterset>
                    </copy>
                </tasks>
            </configuration>
            <goals>
               <goal>run</goal>
            </goals>
        </execution>
    </executions>
</plugin>

2.6.3 javadoc

Javadocs can be automatically created by calling mvn javadoc:javadoc. You can also influence how the javadoc will be created by customizing the plugin that calls the javadoc tool.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <executions>
        <execution>
            <phase>javadoc</phase>
            <goals>
                <goal>javadoc</goal>
            </goals>
            <configuration>
                <groups>
                    <group>
                        <title>JavaServer Pages API Documentation</title>
                        <packages>javax.servlet.jsp</packages>
                    </group>
                </groups>
                <bottom>Portions Copyright &amp;copy; 1999-2002 The Apache Software Foundation.
                        All Rights Reserved. Portions Copyright &amp;copy; 2005-2006 Sun Microsystems Inc.
                        All Rights Reserve
                </bottom>
            </configuration>
        </execution>
    </executions>
</plugin>

2.7 Distribution Dashboard

Each distribution will have a dashboard wiki page (see pe-10.0-SNAPSHOT for instance) which will extract information from all the Modules of the distribution. The information in the pom.xml of each module is used to create the dashboard hence it is important to keep the information as up to date and complete as possible.

2.8 Contributors Dashboard

Each distribution will have a contributors dashboard where all contributors per module will be present. The information will be extracted from the pom.xml information as specified in 2.3.1.

3 Runtime

3.1 Startup sequence

GlassFish is now an HK2 executable. This means:

  • it has no main() or Main class
  • it is implemented as a set of Modules.
  • the first code to be executed (often referenced as the bootstrap module) is a small jar file called glassfish-{Version}.jar

The bootstrap module (not an HK2 Module since it is loaded by the application class loader) has the following responsibilities :

  1. identify the first HK2 Module that will be loaded by the Module subsystem. That Module must be an HK2 Module and must have a ModuleStartup interface implementation. This module is identified as the unique import of the bootstrap module, therefore the bootstrap module cannot have more than one dependency declared in its manifest.
  2. optionally set up the parent class loader of all the Modules loaded by the HK2 module subsystem.

Once the bootstrap jar has identified, the first Glassfish V3 module called com.sun.enterprise:v3-core, the Module will be loaded and the ModuleStartup contract implementation will be instantiated and constructed according to HK2 component model.

When embedded, GlassFish V3 startup sequence is essentially unchanged. The outer Java environment decides with which classloader the V3 bootstrap module should be loaded, essentially defining the parent classloader for V3.

At the end of this startup sequence, this is how the classloader hierarchy is established in V3 :

Classloader Classes Loaded
System Class Loader JDK classes
Application Class Loader all jar files present in the cp parameter during the jvm invocation, or, in the embedded case, the classloader used to load the glassfish{version}.jar file.
MaskingClassLoader Parent classloader for all V3 modules, initialized by the glassfish-{version}.jar, its main responsibility is to mask the jdk classes. This means newer implementations of JDK bundled versions can be used without mechanisms such as the endorsed directories.
com.sun.enterprise:v3-core class loader  

3.2 Services

3.2.1 Services defined

Although programming with Modules can be challenging, GlassFish cannot run efficiently based on user's actions alone. For example, if all the Modules forming a GlassFish distribution referenced each other, the entire set of Modules would be loaded at startup. This erases all the potential advantages of modularization.

To isolate the engineers from programming with Modules directly, there is a concept of Services in glassfish. These services are usually Plain Old Java Objects (POJOs) implementing an interface. At runtime, glassfish relies on a Services implementation lookup to find the Services for a particular interface (called a Contract).

Let's take an example. The com.sun.enterprise:appserv-api Module contains all GlassFish V3 public APIs. It contains an interface called Startup. That interface defines code that must be run when GlassFish is started (somewhat equivalent to the Lifecycle implementations in V2). Any Modules in the GlassFish distribution can have one-to-many implementations of the Startup interfaces called startup services.

When glassfish is started, the Startup implementation code from the com.sun.enterprise:v3-core Module described earlier will do the following HK2 lookup :

Collection<Startup> startups = habitat.getAllByContract(Startup.class);

Even if v3-core Module does not directly import the Modules implementing the startup Services, the collection returned by the above code will contain those implementations. This is an implicit import of instances from one Module to another while the classloaders are not directly referencing each other.

Each Module containing one-to-many Startup implementations can also bring up other Modules through the dependency mechanisms. For instance the HttpService module which contains a Startup service can declare its dependency on the Grizzly Module. Once the Startup services have run successfully, this is how the classloader hierarchy will look like.



Figure 1

In the example above, please note the following :

  • v3-core imports admin-cli and logger Modules.
  • This is a direct dependency from v3-core to those Modules because v3-core uses directly classes that are packaged in these modules

v3-core does not imports HttpService or DeploymentService Modules

  • At runtime, v3-core just looks up the Startup implementations. HttpService and DeploymentServices both offers Startup services implementation which are looked up by HK2 component manager, instantiated, injected and returned to the v3-core.
  • All modules have the same parent class loader.

appserv-api module defines the Startup interface which is the contract for the service and is imported by both the v3-core and the modules containing a Startup implementation.

3.2.2 Add a new type of Contract

A new type of Service or Contract is just a plain java interface annotated with the @Contract interface.

@Contract
public interface Startup {
}

Remember that @Contract annotated classes must be accessible from the Modules implementing the Contract (Service providers) as well as the Modules looking up such implementations. In the example above, the Startup interface is defined in the appserv-api module and is imported by both the v3-core module which requests all Startup implementations and by the modules defining the implementations (HttpService module)

3.2.3 Add a new Service implementation

Adding a new Service is as easy as defining a new POJO that implements a Contract and is annotated with the @Service interface.

@Service
public class RandomService implements Startup, PostConstruct {

	public void postConstruct() {
		logger.info("I am not that useful yet");
	}
}

The above example shows how to implement a Service by implementing the PostConstruct ejb interface. Service implementations can be located in any module packaged in the distribution.

3.2.4 Configuration

Configuration of a Service can come from either the configuration file (domain.xml) or other component implementations. When a Service needs to be configured from the domain.xml, it should declare itself with the @Configured interface.
The combination of @Attribute and @Element to bind to xml attributes and elements can be used to denote which information should be fetched from the configuration file.

@Configured
public class HttpService
        implements Serializable {

    @Element
    protected AccessLog accessLog;
    @Element(required=true)
    protected List<HttpListener> httpListener = new ArrayList();
...
}

Although it could be conceivable that an annotated @Configured class is also a Service implementation, this sort of converged @Configured plus @Service component is discouraged. Most @Configured objects need to be available and be configured without an associated runtime (so the admin-gui can configure the http-service in the example used above without necessarily starting the http service). It is therefore recommended to split the configuration from the behavior into two POJOs and implement the following pattern using @ConfiguredBy:

@Service
@ConfiguredBy(HttpService.class)
public void GrizzlyService implements Startup {

	@Inject
	private HttpService config;

...
}

3.2.5 Existing services

A subset of services have already been identified and added to the org.jvnet.glassfish:appserv-api Module which represents the public APIs of the GlassFish implementation. Below is a brief introduction of these services. See later sections for more details:

Service Description
Startup services which are run upon GlassFish startup.
Sniffer services responsible for identifying deployment artifacts and setting up associated containers.
ArchiveHandler services that recognize application bundle types (WAR, EAR...)
Deployer services responsible for deploying artifacts to a particular container
AdminCommand services which represent a CLI administrative command

3.3 Application deployment

GlassFish v3 needs to support the convergence model for applications where users can ship application bits targeted to different containers all in the same package. This is a break from how we have traditionally considered application delivery in the Java EE world where each container had a dedicated bundle format. For instance, web containers expect war files, ejb containers expect jar files.

In v3, several types of applications can be co-packaged in the same bundle while still requiring some form of cooperation among the application parts (requiring a single class loader to load the application bits to be shared by all containers). There cannot be an assumption on the format of the bundle where a container can load the application bits from, therefore the containers do not control how the class loader for the applications bits are created, this is handled through another type of deployment service called ArchiveHandler.

There can be only one ArchiveHandler for a particular bundle type. The archive handler implementation will be responsible for creating an appropriate application class loader that can successfully load classes and resources from that bundle type. GlassFish V3 will create a parent classloader to be used by the ArchiveHandler when creating the application class loader. This parent class loader will allow the Glassfish runtime to dynamically add imports to the application (see below). Each Sniffer implementation has the ability to setup their associated containers, if the bundle appears to contain components they support. Once the sniffers have run successfully, all Deployer services currently found by HK2 will have a chance to deploy bits of the bundle to their associated containers.

Deployers will either claim part of the application bits or not. If a particular deployer instance successfully process a deployment request using the class loader created by the ArchiveHandler. the public APIs associated with that container (eg the Java EE APIs) will be added to the parent class loader (create above for that purpose).

Remember that supporting different bundle types is a desired feature. Therefore, power users can have the ability to create/register new ArchiveHandlers. Since ArchiveHandlers are responsible for creating the classloaders, there is no possibility to directly add the container's public API to these classloaders. This is because the ArchiveHandlers are simple java.lang.ClassLoader implementations. This is the reason behind the creation of this dynamic parent class loader.

However, there is a slight limitation to this scheme: the ClassLoader implementation returned by the ArchiveHandler should support the registration of java.lang.instrument.ClassFileTransformer instances. This supports bytecode enhancement dependent technologies like JPA. The EjbClassLoader and WebClassLoader that we ship with V3 both support such a registration.

In the diagram below, we have two containers: one application being deployed to both containers and one random library module used by one of the container. Note the following :

  1. the application bits are loaded from the bundle using the "Application Class Loader". This is created by the ArchiveHandler that handles this bundle type.
  2. the parent class loader of that "Application Class Loader", created by GlassFish v3, is a Module class loader. This loader can import Modules on-the-fly as container's deployers declare their support for part (or the whole) application components.
  3. the private classes of each container are not accessible by the parent class loader (2).
  4. the public API of each container is usually the APIs used by the components (e.g., javax.ejb) plus any other classes that may be required by the generated code (e.g., stubs).

In the second diagram, you will see a simplified version of the first diagram showing the relationships between two applications and the containers into which they are successfully deployed. Note the following :

  1. AppA is deployed to containerX and Y
  2. AppB is deployed to containerY, Z and T
  3. Each application has a class loader (created by the ArchiveHandler) and a parent class loader. The parent loader is a Module class loader created by GlassFish that provides the application with all the necessary public APIs.
  4. Each container is a set of public and private Modules.


Figure 2



Figure 3

4 Persistence

Implementing persistence in V3 involves several challenges due to the following:

  • age and usage patterns of some JDBC classes
  • multiple implementations of the javax.persistence APIs
  • the capacity of these implementations for running in Java SE mode (even embedded in GlassFish) or in Java EE mode.

The following patterns have been identified :

  1. Applications can do a Class.forName() call to load a JDBC driver and make direct calls through the JDBC APIs to the underlying database. Applications do not need to identify special interest in such drivers. There is also no indication they will use such low level access APIs.
  2. Applications can decide to use the default JPA provider, letting GlassFish choose which one to use.
  3. In Java SE mode, appplications can use the PersistenceProvider.createEntityManagerFactory() call to get a specific persistence provider (name extracted from the peristence.xml).
  4. In Java EE mode, GlassFish is responsible for loading the persistence.xml file, and looking up the expected persistence provider according the its settings (potentially defaulting the provider name).
  5. In Java EE mode, GlassFish is responsible for identifying the connection pool to be used with the entity manager. This resource adapter is retrieved at deployment time from the JNDI name space and wired up with the persistence provider to create the entity manager.

The Stranger pattern is not necessarily supported by the JPA or Java EE specs.

  1. A Java EE application can co-bundle a persistence provider. This is usually done for applications targeted to Tomcat, and therefore it is quite possible to find such packaging.
  2. Some Java EE components like entity beans can be installed in shared environment that should be accessible by all deployed applications.

To resolve the above problems, a shared library Module will be introduced. This Module will load all jar files located in the glassfish/lib and glassfish/javadb/lib directories (remember that v3 modules and jars will be relocated somewhere else). This shared library will have access to the JDBC drivers as well as javadb runtime.

The solution described above is illustrated by Figure 4 below. The number in parentheses indicates which class loader relationship that will satisfy the requirement.

4.1 Java SE Mode

4.1.1 case 1

Applications can load JDBC drivers using the Class.forName() API. The parent class loader of the application class loader (named the application container class loader) will include the shared library class loader. It also will give access to the public APIs of an application (1)

4.1.2 case 2 and 3

In Java SE mode, applications use javax.persistence.PersistenceProvider.createEntityManagerFactory() API to create an entity manager. Applications use a persistenceUnitName parameter to identify the provider in the persistence.xml file. HK2 will make the META-INF/services resolution for the PersistenceProvider.java implementation and JPA will be loaded like any other HK2 service.

The JDBC driver is provided by some non-portable persistence.xml properties and is loaded directly by the persistence provider (2)

4.2 Java EE mode

In Java EE, there is a need to add ClassFileTransformers to the application class loader. This is a bit tricky as we don't necessarily provide the class loader for the application bits (see Deployment above). JPA infrastructure will have a Deployer implementation, therefore the prepare phase should be used by the JPADeployer to pre-load classes that may require bytecode enhancements. During the prepare phase, the JPADeployer should also add some java.lang.intrument.ClassFileTransformers) instances to the DeploymentContext. The Deployment backend will then recreate a new class loader, register all installed ClassFileTransformers in this new class loader instances and will invoke the load phase with the new classloader.

4.2.1 case 4

Normal HK2 Service resolution should suffice to resolve the JPA provider based on the META-INF/services entries.

4.2.2 case 5

Naming Service will be available though the HK2 Service Resolution Mechanism, from which the connection pool can be looked up. After wiring up the connection pool with the JPA provider, the entity manager can be created by the deployment code and injected in the application code.

4.2.3 case 6,7

Normal class loading delegation should be enough to support such use cases.



Figure 4

5 Container pluggability

Containers are entities that can run applications (e.e., web container, ejb, etc.). Since such containers can be installed or removed from a GlassFish V3 installation, there is no special code referencing different application containers like Switch.java in V2.

Containers have the ability to install themselves in an existing GlassFish installation with the following Services implementations :

  • Sniffer : Invoked during a deployment operation (or server restart). Sniffers will have the ability to recognize part (or whole) application bundles. Once a sniffer has positively identified parts of the application, its Setup method will be called to have a chance to setup the container for usage during that server instance lifetime.
  • ContainerProvider: Called each time a container is started or stopped. A container is started once when the first application using it is deployed. It will remain started until it is stopped when the last application using it was undeployed or stopped.
  • Deployer: Called to deploy/undeploy applications to a container
  • AdminCommand : Containers can come with special set of CLI commands that should only be available once the container has been successfully installed in a GlassFish V3 installation. These commands should be used to configure the container's features.
  • TBD : there will also be a AdminGUI pluggability layer but it has not been designed yet

6 Admin CLI

Like everything in V3, we rely on HK2 components to identify administrative commands. So, in this case, the AdminCommand interface is annotated with @Contract. As a result, to add a new command to GlassFish V3 is to create a Service implementing the AdminCommand interface and the runtime will find it :

package com.foo.bar;

@Service(name="super")
public class MySuperCommand implements AdminCommand {
...
}

Now this is nice but we can do better. Since admin commands are Services, we can use injection. So, if you want to have access to the domain configuration, you do the following:

@Inject
Domain domain;

and the domain information will be injected in the instance field before the command execute() is invoked. That's nice, but why not extend this to the command parameters. Too many times, I have seen command implementation code just ensure that all mandatory parameters to the command are present, values are correct, and extraction from the String[] representation.

This is where the new annotation @Param becomes useful. It can annotate any instance field of the command implementation with the @Param annotation to make it a command parameter. So for instance adding the following:

@Param
String name

adds a name parameter to the command. Of course, parameters can be optional

@Param(optional=true)
String myoptionalparam

or the default parameter (but there can only be one of course)

@Param(default=true)
String path

so you can now do :

asadmin deploy --path foo.war

or

asadmin deploy foo.war

Also, the @Param tag is automatically linked to the required LocalStrings.properties resource file of your classloader. So, when you add the

com.sun.foo.bar.mysupercommand=Some random super command
com.sun.foo.bar.mysupercommand.path=path to the file the command applies to.

strings to your LocalStrings.properties, the system will find them and use it for any type of error checking or help :

$prompt>asadmin super
FAILURE : super command requires the path parameter : path to the file the command applies to.

$prompt>asadmin super --help
Some random super command

Parameters :
	path : path to the file the command applies to.

The above behaviours are completely handled by the system. The command will not be executed as long as all mandatory parameters are provided by the users. There is more to do, of course, like automatic help page and localized page creation. Also, there should be some maven 2 plugins developed to automate page creation and ensure that all strings are properly localized.

7 Building

Although this information will most likely change and is not entirely implemented, this is an introduction to how we will organize the source code in V3.

The bootstrap directory is not going to be moved forward, but we will use a directory layout to separate and represent modules segments. Functionalities linked to packaging are moved to the distribution modules.

7.1 Source code management

Source code is managed using Subversion for now. However, we plan to move to mercurial at some point. The Subversion workspace is organized to follow the module infrastructure that we will be using in V3.

To checkout the entire glassfish workspace that are not yet used by the V3 runtime (and therefore were not moved to a corresponding module directory), you can do the following :

svn checkout https://svn.java.net/svn/glassfish-svn/trunk/v2

However, unless you plan to move code from the old modules to the new structure, you do not need to checkout the entire workspace, in general, you can just check out the code currently used in V3 by doing :

svn checkout https://svn.java.net/svn/glassfish-svn/trunk/v3

To subscribe to the svn notifications for the changes, send an e-mail to commits-subscribe@glassfish-svn.java.net

7.2 Modules

Modules are organized following the maven best practice pattern.

Although each module can use a dedicated scm repository, it is important to follow that structure for consistency and tool support.

See V3 module structure for a complete description. However, for the most simple cases, it should be the following files/directories:

File Description
pom.xml maven build file
src/main/java module's sources
src/main/resources module's resources like localized strings, xml...
src/tests/... module's unit tests

7.3 Functional Areas

In V2, the workspace was organized with sub-modules, each sub-module could be independently checked out or if you wanted to checkout the entire workspace, you would do so from the bootstrap module. For instance this is a simplified view of the V2 CVS workspace

Module Description
bootstrap contains all project wide settings, main build scripts etc.
appserv-commons contains code shared by the different GlassFish sub components (Web Container, Deployment, EJB container...)
admin-core/config-api contains the domain.xml binding classes generated from schema2beans
ejb-api EJB 3.0 javax.ejb API sources

In the current V3 workspace, the sources which are currently used by the V3 runtime have been moved to a new location that reflect the module in which the .class files are packaged. The workspace is also organized in a tree like structure (as opposed to mainly flat like in V2 with all modules at the top-level).

Modules will be grouped into functional areas and moved under specific directories. A user that wishes to checkout the entire V3 workspace should do so by issuing the command described in IV.1. However, developers that wish to only work in a specific area should checkout the set of Modules that are identified in that area.

The following areas have been already identified. This will evolve over time:

Directory Description
v3/web web related technologies (jsp, jsf...)
v3/ejb ejb related technologies
v3/core v3 core infrastructures
v3/admin administration related modules
v3/extras adminGUI and other tools
v3/api Java EE APIS
v3/build Build related tools like maven plugins

For instance, under glassfish_v3/web, you will find subdirectories for each module that are part of our web profile. Now, let's say you need to move some code from appserv-core to the new V3 module structure (in say web/appserv-webtier module), you could only checkout the appropriate modules :

svn checkout https://svn.java.net/svn/glassfish-svn/trunk/v3/appserv-core
svn checkout https://svn.java.net/svn/glassfish-svn/trunk/v3/web/appserv-webtier

Once we will complete the switch to Mercurial, such tree based organization does not support checking out part of the tree. So, we will most likely move each sub-directory under glassfish_v3 to a new Hg repository.

Modules are grouped using a groupId as defined in the module's pom.xml. All GlassFish module should follow this consistent naming and directory structure

Main groupId Function Area Module name Resulting maven Id source location
org.glassfish web appserv-webtier org.glassfish.web:appserv-webtier v3/web/appserv-webtier
org.glassfish admin config-api org.glassfish.admin:config-api v3/admin/config-api
org.glassfish core kernel org.glassfish.core:kernel v3/core/kernel

7.4 Building

Basic understanding of maven and maven repositories is necessary to build V3. Also, at each level, users are able to do a mvn command to build a Module, create a functional set of Modules, or the entire V3 workspace.

Command Description
mvn clean cleans the binary outputs (.class, and .jar files) from the module target directory. Does not remove the Module artifact from the local maven repository.
mvn install builds and install the binary artifact in the local maven repository.
mvn javadoc:javadoc creates javadoc

So for instance if I run mvn install from the v3 directory, I will build the entire GlassFish V3, if I build under v3/web I will build all the web related modules, if I build v3/web/appserv-webtier, I only build the appserv-webtier module.

Artifacts cannot be published directly to the global HTTP maven repositories because a certain number of integration tests need to happen. When a developer feels confident that his code is robust and has made enough integration tests on his local machine (by building a distribution and running tests), he will check in the sources. Hudson, the continuous building system, will monitor checkins and will trigger a build/test/publish cycle each time a developer checks in a change set.

7.5 Moving code

One of the big activity of V3 will be to move code from their current module to a new directory that reflect the runtime module in which the .class will be packaged. How can you move files without loosing history :

svn checkout https://svn.java.net/svn/glassfish-svn/trunk/v2/appserv-core
svn checkout https://svn.java.net/svn/glassfish-svn/trunk/v3/web/appserv-webtier

assuming you are located in your home directory, you now have 2 subdirectories, appserv-core and v3

cd ~/v3/web/appserv-webtier/src/main/java/com/sun/entreprise
svn mv ~/v2/appserv-core/src/java/com/sun/enterprise/FooBar.java .

and commit to have the old file deleted from appserv-core and the new addition to v3/web/appserv-webtier without loosing the commit history. You can also move entire directories following the same pattern as above. Do not do svn rm and svn add as you would loose the SCM history associated with the file you are trying to move.

7.6 Distributions

Distributions are created by assembling jars and other artifacts. There is a flexible distribution description mechanism based on maven pom file for binary dependencies and ant scripts for the other types of artifacts. For more details about this process, refer to V3DistributionAssembly

7.7 HK2

HK2, the java.net project for our module subsystem and lightweight component model, has a separate java.net project located at hk2.java.net.

7.7.1 sources

HK2 sources are stored in a Subversion repository, so checking out sources is usually done with

svn checkout https://hk2.java.net/svn/hk2/trunk

7.7.2 Module Subsystem documentation

TBD