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
Related posts:- TOTD #128: EJBContainer.createEJBContainer: Embedded EJB using GlassFish v3
- Oracle at Jazoon 2010 – Java SE, Java FX, Java EE 6, GlassFish, JPA 2.0, JSF 2, Servlets 3.0, OSGi, Cloud, HTML 5, Open DS, …
- TOTD #120: Deployment Descriptor-free Java EE 6 application using JSF 2.0 + EJB 3.1 + Servlets 3.0
- TOTD #133: JPA2 (JPQL & Criteria), JavaDB, and embedded GlassFish – perfect recipe for testing
- TOTD #139: Asynchronous Request Processing using Servlets 3.0 and Java EE 6
Hey, if GlassFish embedded is now "usable", I’ll have to add support to it in my Wembed project: http://projectkenai.com/projects/wembed/pages/Home
Last time I checked, it was still in early beta so I’m happy to hear it is now polished enough so I can test it.
I’m using embedded servlet containers to test applications, using HtmlUnit integration tests, against different containers inside Ant.
That, and as a simple way of installing demos as using Wembed is double click and you get a nice status window and a log console, using the container of your choice.
GF would make the 4th container, so the more, the merrier.
Thanks for the info
Comment by GreenEyed — May 7, 2010 @ 3:42 am
Greeneyed,
See another related entry for a slightly more advanced sample:
http://blogs.sun.com/arungupta/entry/totd_133_jpa2_jpql_criteria
Let me know once you’ve added support for GlassFish in Wembed, would love to publicize it.
Comment by Arun Gupta — May 7, 2010 @ 8:50 am
Ummm, I almost got it to work. I can start the server and deploy the web application, but trying to execute a JSP produces tons of "PWC6199: Generated servlet error" about packages and classes not being found, but the packages are the one like javax.servlet, org.glassfish.jsp.api etc. and the classes are HttpServletRequest…
And those classes are obvioulsy inside the glassfish-embedded-all jar… so it seems as if the JPS compiler is not using this jar… weird.
Unless I have to add that jar myself to the web application libraries, I don’t get it.
S!
Comment by GreenEyed — May 7, 2010 @ 1:35 pm
Hi Arun,
I was finally able to add GlassFish support to Wembed.
However, given that there is currently no support for descriptor-specified datasources in GlassFish-embedded, it is really not that useful.
S!
Comment by GreenEyed — May 16, 2010 @ 10:37 am
Scratch my last comment , I have been able to get it to work thanks to the new Java EE 6 features and some tweaks to the classpath.
So, in the end it was not that bad that I suggested Java EE 6 to add the feature of defining datasources from the application through a standard descriptor .
I’ll refine and check everything and I’ll pack a release with GlassFish support. Yes!!
S!
Comment by GreenEyed — May 16, 2010 @ 12:05 pm
@GreenEyed, did your JSP Compilation issues got resolved?
Comment by Siraj — May 20, 2010 @ 3:35 pm
Hi Siraj,
Yes, they did. It was a strange classpath problem due to the way I was building the jar and adding libraries to the classpath.
GlassFish was the only one giving me such problems, but it might be caused byt the packaging of the glassfish-all jar file.
In any case, I changed the way I launch the embedded containers and it worked,
I still have some issues regarding the temporary directory that gets created that sometimes it’s not removed, but other than that, it works.
S!
Comment by GreenEyed — May 21, 2010 @ 11:49 pm