This Tip Of The Day (TOTD) is a refresh of Embeddable GlassFish in Action – Servlet in a Maven Project.
GlassFish v3 runs easily in embedded mode – no download, installation, or configuration – every thing done programmatically within a JVM. This blog shows how to deploy a simple Servlet using these APIs and then write a simple test to invoke it – all within the same VM.
Lets get started!
- Lets create our Maven project:
mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes \ -DgroupId=org.glassfish.embedded.samples -DartifactId=webtier2
- Add the following <repository>, <dependency>, and <plugin> to the generated "pom.xml:
<repositories> <repository> <id>glassfish-repository</id> <name>Java.net Repository for Glassfish</name> <url>http://download.java.net/maven/glassfish</url> </repository> </repositories> . . . <dependencies> . . . <dependency> <groupId>org.glassfish.extras</groupId> <artifactId>glassfish-embedded-all</artifactId> <version>3.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build>
Read Setting the Class Path for more discussions on the different JAR files that are available. The version may be changed form "3.0" to "3.1-SNAPSHOT" to pick the latest bug fixes and improvements.
- Change the generated "src/main/java/org/glassfish/embedded/samples/App.java" to:
package org.glassfish.embedded.samples; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Hello world! */ @WebServlet(name="app", urlPatterns={"/app"}) public class App extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("Hello Duke"); } }
This is using "@WebServlet" annotation, a new feature in Servlets 3.0, to mark a POJO as a Servlet. Notice the servlet is hosted at "/app" URL. No "web.xml" will be required in this case.
- Edit the generated "src/test/java/org/glassfish/embedded/samples/AppTest.java" and add the following method:
public void testServlet() throws IOException, LifecycleException { // Build a server Server.Builder builder = new Server.Builder("server"); Server server = builder.build(); // Specify the port server.createPort(8080); // Add the Web container server.addContainer(ContainerBuilder.Type.web); // Create the WAR file ScatteredArchive.Builder saBuilder = new ScatteredArchive.Builder("test", Collections.singleton(new File("target/classes").toURI().toURL())); ScatteredArchive archive = saBuilder.buildWar(); // Deploy the WAR file EmbeddedDeployer deployer = server.getDeployer(); deployer.deploy(archive, null); // Read the response from the servlet hosted at "/app" URL url = new URL("http://localhost:8080/test/app"); BufferedReader br = new BufferedReader( new InputStreamReader( url.openConnection().getInputStream())); // ... and assert assertEquals("Hello Duke", br.readLine()); }
This method is well commented and where all the magic is happening.
The updated import statements look like:
import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.util.Collections; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.glassfish.api.deployment.DeployCommandParameters; import org.glassfish.api.embedded.ContainerBuilder; import org.glassfish.api.embedded.EmbeddedDeployer; import org.glassfish.api.embedded.LifecycleException; import org.glassfish.api.embedded.ScatteredArchive; import org.glassfish.api.embedded.Server;
- And now fire the following command:
mvn test
and see the output as:
Running org.glassfish.embedded.samples.AppTest Apr 30, 2010 10:49:55 AM com.sun.enterprise.v3.server.AppServerStartup run INFO: GlassFish v3 (74.2) startup time : Embedded(498ms) startup services(433ms) total(931ms) Apr 30, 2010 10:49:55 AM com.sun.enterprise.transaction.JavaEETransactionManagerSimplified initDelegates INFO: Using com.sun.enterprise.transaction.jts.JavaEETransactionManagerJTSDelegate as the delegate Apr 30, 2010 10:49:55 AM org.glassfish.admin.mbeanserver.JMXStartupService$JMXConnectorsStarterThread run INFO: JMXStartupService: JMXConnector system is disabled, skipping. Apr 30, 2010 10:49:55 AM AppServerStartup run INFO: [Thread[GlassFish Kernel Main Thread,5,main]] started Apr 30, 2010 10:49:55 AM org.hibernate.validator.util.Version INFO: Hibernate Validator null Apr 30, 2010 10:49:55 AM org.hibernate.validator.engine.resolver.DefaultTraversableResolver detectJPA INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver. Apr 30, 2010 10:49:56 AM com.sun.enterprise.v3.services.impl.GrizzlyProxy$2$1 onReady INFO: Grizzly Framework 1.9.18-k started in: 154ms listening on port 8080 Apr 30, 2010 10:50:00 AM com.sun.common.util.logging.LoggingConfigImpl openPropFile INFO: Cannot read logging.properties file. Apr 30, 2010 10:50:00 AM com.sun.enterprise.web.WebContainer createHttpListener INFO: Created HTTP listener embedded-listener on port 8080 Apr 30, 2010 10:50:00 AM com.sun.enterprise.web.WebContainer configureHttpServiceProperties WARNING: pewebcontainer.invalid_http_service_property Apr 30, 2010 10:50:00 AM com.sun.enterprise.web.WebContainer createHosts INFO: Created virtual server server Apr 30, 2010 10:50:00 AM com.sun.enterprise.web.WebContainer loadSystemDefaultWebModules INFO: Virtual server server loaded system default web module Apr 30, 2010 10:50:02 AM com.sun.enterprise.security.SecurityLifecycle INFO: security.secmgroff Apr 30, 2010 10:50:03 AM com.sun.enterprise.security.ssl.SSLUtils checkCertificateDates SEVERE: java_security.expired_certificate Apr 30, 2010 10:50:03 AM com.sun.enterprise.security.SecurityLifecycle onInitialization INFO: Security startup service called Apr 30, 2010 10:50:03 AM com.sun.enterprise.security.PolicyLoader loadPolicy INFO: policy.loading Apr 30, 2010 10:50:03 AM com.sun.enterprise.security.auth.realm.Realm doInstantiate INFO: Realm admin-realm of classtype com.sun.enterprise.security.auth.realm.file.FileRealm successfully created. Apr 30, 2010 10:50:03 AM com.sun.enterprise.security.auth.realm.Realm doInstantiate INFO: Realm file of classtype com.sun.enterprise.security.auth.realm.file.FileRealm successfully created. Apr 30, 2010 10:50:03 AM com.sun.enterprise.security.auth.realm.Realm doInstantiate INFO: Realm certificate of classtype com.sun.enterprise.security.auth.realm.certificate.CertificateRealm successfully created. Apr 30, 2010 10:50:03 AM com.sun.enterprise.security.SecurityLifecycle onInitialization INFO: Security service(s) started successfully.... classLoader = WebappClassLoader (delegate=true; repositories=WEB-INF/classes/) SharedSecrets.getJavaNetAccess()=java.net.URLClassLoader$7@71e13a2c Apr 30, 2010 10:50:03 AM com.sun.enterprise.web.WebApplication start INFO: Loading application test at /test Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 9.845 sec Results : Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
The key messages in the log are highlighted in bold.
As you can see embedded GlassFish started in less than a second … neat! It also shows a message that HTTP listener is starting on port 8080. And finally the 2 tests passed – one is the default one generated by Maven and other is the new one that we added!
A future blog will show how to create JDBC resource using these APIs and use the JPA 2 APIs to query an in-memory database.
Alternatively, you can also use the Maven plug-in or EJB 3.1 Embeddable API. Always refer to the GlassFish v3 Embedded Server Guide for the definitive documentation. The latest javadocs are available here.
How are you using embeddable GlassFish ?
Technorati: totd glassfish v3 javaee embedded servlet