The new Java EE specification MVC 1.0 (JSR 371) and it’s reference implementation Ozark brings action-based MVC for Java EE 8 platform.
MVC 1.0 is a good friend for me because I always thought why can’t we return a view from Jax-RS resources when I develop RESTful Web Services. Thus, Ozark implements this wish by using JAX-RS and CDI together.
MVC 1.0 RI (Ozark) works together with Tomcat and Glassfish seamlessly. If we want to run MVC 1.0 apps on Tomcat, we need to put the following dependencies into our web application.
- MVC 1.0 Spec API
- Includes spec’s interfaces, annotations eg.
- Ozark RI API
- Implements Spec API with CDI and Jax-RS
- Weld
- CDI reference implementation
- Jersey
- Jax-RS reference implementation
However, if we want to run MVC 1.0 apps on Glassfish, we don’t need to put CDI and Jax-RS dependencies into our application archive anymore because Glassfish contains CDI and Jax-RS modules out of the box. So, that is enough to put MVC 1.0 Spec API and Ozark RI into our web application to run it on Glassfish.
However, Glassfish 5 is the reference implementation for Java EE 8 (JSR 366), so MVC 1.0 should be a bundled module in Glassfish 5. This blog is about how to ship MVC 1.0 into Glassfish 5 as a module.
Glassfish uses OSGI for the module system and Apache Felix as an OSGI implementation. So, we should generate an OSGI bundle for MVC 1.0.
OSGI bundle is just a jar file that can bundle one or more packages from different jars together and some metadata in a MANIFEST.MF
file that describes the module details. For example let’s look at an OSGI bundle that I built for MVC 1.0 before going into details;
You can see the above javax.mvc.*
package for MVC 1.0 Spec API and org.glassfish.ozark.*
package for Ozark RI. Then, Let’s look into the MANIFEST.MF
file;
Manifest-Version: 1.0
Bnd-LastModified: 1458465458223
Build-Jdk: 1.8.0_66
Built-By: usta
Bundle-ManifestVersion: 2
Bundle-Name: Ozark 1.0 MVC RI Bundle
Bundle-SymbolicName: org.glassfish.ozark.javax.mvc
Bundle-Version: 1.0.0
Created-By: Apache Maven Bundle Plugin
Export-Package: javax.mvc;uses:="javax.mvc.engine,javax.mvc.security,jav
ax.ws.rs.core";version="1.0.0",javax.mvc.annotation;uses:="javax.enterp
rise.context,javax.ws.rs";version="1.0.0",javax.mvc.binding;uses:="java
x.validation";version="1.0.0",javax.mvc.engine;uses:="javax.mvc,javax.s
ervlet.http,javax.ws.rs.container,javax.ws.rs.core";version="1.0.0",jav
ax.mvc.event;uses:="javax.mvc.engine,javax.ws.rs.container,javax.ws.rs.
core";version="1.0.0",javax.mvc.security;version="1.0.0",org.glassfish.
ozark;uses:="javax.enterprise.context,javax.inject,javax.mvc,javax.mvc.
security,javax.ws.rs.core";version="1.0.0",org.glassfish.ozark.binding;
uses:="javax.enterprise.context,javax.mvc.binding,javax.validation,org.
glassfish.jersey.server.spi";version="1.0.0",org.glassfish.ozark.cdi;us
es:="javax.annotation,javax.enterprise.context,javax.enterprise.context
.spi,javax.enterprise.event,javax.enterprise.inject.spi,javax.mvc.event
";version="1.0.0",org.glassfish.ozark.core;uses:="javax.annotation,java
x.enterprise.context,javax.mvc,javax.mvc.annotation,javax.ws.rs,javax.w
s.rs.container,javax.ws.rs.core,javax.ws.rs.ext";version="1.0.0",org.gl
assfish.ozark.engine;uses:="javax.annotation,javax.enterprise.context,j
avax.inject,javax.mvc,javax.mvc.engine,javax.servlet,javax.servlet.http
,javax.ws.rs.container,javax.ws.rs.core";version="1.0.0",org.glassfish.
ozark.event;uses:="javax.enterprise.context,javax.mvc.engine,javax.mvc.
event,javax.ws.rs.container,javax.ws.rs.core";version="1.0.0",org.glass
fish.ozark.jersey;uses:="javax.annotation,javax.servlet.http,javax.ws.r
s,javax.ws.rs.container,javax.ws.rs.core,org.glassfish.jersey.internal.
spi,org.glassfish.jersey.message.internal,org.glassfish.jersey.server.m
odel";version="1.0.0",org.glassfish.ozark.security;uses:="javax.annotat
ion,javax.enterprise.context,javax.mvc.annotation,javax.mvc.security,ja
vax.ws.rs,javax.ws.rs.container,javax.ws.rs.core,javax.ws.rs.ext";versi
on="1.0.0",org.glassfish.ozark.servlet;uses:="javax.servlet,javax.servl
et.annotation,javax.ws.rs";version="1.0.0",org.glassfish.ozark.util;use
s:="javax.enterprise.context,javax.enterprise.inject.spi,javax.ws.rs.co
re";version="1.0.0"
Import-Package: javax.annotation;version="[1.2,2)",javax.enterprise.cont
ext,javax.enterprise.context.spi,javax.enterprise.event,javax.enterpris
e.inject,javax.enterprise.inject.spi,javax.inject;version="[1.0,2)",jav
ax.mvc,javax.mvc.annotation,javax.mvc.binding,javax.mvc.engine,javax.mv
c.event,javax.mvc.security,javax.servlet,javax.servlet.annotation,javax
.servlet.http,javax.validation;version="[1.1,2)",javax.ws.rs;version="[
2.0,3)",javax.ws.rs.container;version="[2.0,3)",javax.ws.rs.core;versio
n="[2.0,3)",javax.ws.rs.ext;version="[2.0,3)",org.glassfish.jersey.inte
rnal.spi;version="[2.21,3)",org.glassfish.jersey.message.internal;versi
on="[2.21,3)",org.glassfish.jersey.server.model;version="[2.21,3)",org.
glassfish.jersey.server.spi;version="[2.21,3)",org.glassfish.ozark,org.
glassfish.ozark.binding,org.glassfish.ozark.cdi,org.glassfish.ozark.cor
e,org.glassfish.ozark.engine,org.glassfish.ozark.event,org.glassfish.oz
ark.jersey,org.glassfish.ozark.security,org.glassfish.ozark.util
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Tool: Bnd-3.0.0.201509101326
There are some properties for an OSGI bundle that describes the bundle. The values are easily understandable but you may not understand Export-Package
and Import-Package
properties if you have not experience with OSGI.
- Export-Package
- Declares that this bundle includes those listed packages.
- Import-Package
- Declares that this bundle requires those listed packages.
Let me show you how I created a Glassfish Module for MVC 1.0. You can follow up with the same steps for the new Java EE specs to move it into Glassfish.
Step 1: Get MVC 1.0 and Ozark RI source codes
MVC 1.0 Spec APIs and Ozark RI codes are located at java.net.
git clone git://java.net/mvc-spec~git
git clone git://java.net/ozark~sources
When I look at the different Java EE Specs, some of them use a single repository that have Spec API and RI together and some of them use separated repos like MVC 1.0 and Ozark RI. We actually don’t edit MVC Spec API, we will only edit Ozark sources.
Step 2: Package as OSGI bundle
The majority of the Java EE specs use Maven
as a build system. The first step here is to change <packaging>jar</packaging>
to <packaging>bundle</packaging>
in Ozark sources’ pom.xml
because we want to ship our artifacts as an OSGI bundle instead of a classic jar.
Step 3: Enable Maven Bundle Plugin
After we change packaging
type to the bundle
, we must also enable Apache Felix’s bundle plugin in the pom.xml
file.
<plugins>
...
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>
javax.mvc.*,org.glassfish.ozark.* (1)
</Export-Package>
</instructions>
</configuration>
</plugin>
...
</plugins>
1 | maven-bundle-plugin ships javax.mvc and org.glassfish.ozark packages and their sub-packages into the bundle. javax.mvc package is the root package for MVC 1.0 Spec API and org.glassfish.ozark package is for Ozark RI. |
Normally the steps are finished here but we need to do one more step for MVC 1.0;
Ozark RI strongly uses CDI ,but Glassfish doesn’t automatically register CDI beans declared in its modules. So, We need to tell Glassfish to discover CDI beans declared in Ozark by CDI extension mechanism.
Step 4: Help Discovering Ozark’s CDI Beans
Ozark has already a CDI extension named OzarkCdiExtension
under org.glassfish.ozark.cdi
package. This extension currently registers a new RedirectScope
for MVC 1.0. The extension is registered in services/javax.enterprise.inject.spi.Extension
file.
We can use the same OzarkCdiExtension
extension to complete our work. Arjan Tijms gave me a hint to register annotated types in a CDI extension. The following CDIUtils#addAnnotatedTypes
method registers one or more annotated types to discover them by the CDI container.
// org.glassfish.ozark.util.CDIUtils.java
/**
*
* @param beforeBean The BeforeBeanDiscovery.
* @param beanManager The BeanManager.
* @param types annotated types to register
*/
public static void addAnnotatedTypes(BeforeBeanDiscovery bf, BeanManager bm, Class<?>... types) {
for (Class<?> type : types) {
bf.addAnnotatedType(bm.createAnnotatedType(type), null);
}
}
After writing this helper method, we can register Ozark’s annotated types in OzarkCdiExtension
like below.
// org.glassfish.ozark.cdi.OzarkCdiExtension.java
public class OzarkCdiExtension implements Extension {
...
/**
* Registers given annotated types to be scanned during bean discovery
*
* @param beforeBean The BeforeBeanDiscovery
* @param beanManager The BeanManager
*/
public void register(@Observes BeforeBeanDiscovery beforeBean, BeanManager beanManager) {
CdiUtils.addAnnotatedTypes(beforeBean, beanManager,
// .
MvcContextImpl.class,
// binding
BindingResultImpl.class,
BindingInterceptorImpl.class,
// core
Messages.class,
ModelsImpl.class,
ViewableWriter.class,
ViewRequestFilter.class,
ViewResponseFilter.class,
// engine
FaceletsViewEngine.class,
JspViewEngine.class,
ViewEngineFinder.class,
// security
CsrfImpl.class,
CsrfProtectFilter.class,
CsrfValidateInterceptor.class,
EncodersImpl.class,
// util
CdiUtils.class
);
}
...
}
So Let’s bundle Ozark sources after completing Step 4
with mvn clean install -DskipTests
command. We will see the bundle jar in the /target
directory. Now, the generated bundle can be moved to the Glassfish /modules
directory like any bundles moved here before.
The changes that I’ve done for that work can be seen at https://github.com/rahmanusta/ozark/commit/10d4cf610fad1fc90817d473b01d01dab353f38f
The Glassfish module generated with the current MVC 1.0 and Ozark sources is located at https://github.com/rahmanusta/ozark/releases/tag/v1.0. You should manually copy/paste the bundle jar to the Glassfish $GF_HOME/glassfish/modules
directory to run MVC 1.0 applications.
Let’s test the module with a simple MVC 1.0 application.
- Step 1
- Download the latest Glassfish 5 nightly build
- Step 2
- Extract the downloaded zip and copy javax.mvc-1.0.jar module to the
$GF_HOME/glassfish/modules
directory. Change directory to the/bin
directory in terminal and run the followingasadmin
command to start Glassfish 5.asadmin start-domain
- Step 2
- Clone the demo application or download it;
git clone https://github.com/rahmanusta/mvc-demo.git
- Step 3
- Build project with the given Maven command in the
mvc-demo
directory.mvn clean install
- Step 4
- You will see the
mvc.war
file located at themvc-demo/target
directory. Run the following command to deploy demo MVC 1.0 app to the Glassfish 5.asadmin deploy target/mvc.war
If you look into
mvc.jar
file with an archive application (Winrar, 7zip eg.) then you will not see any jar dependency inside it. Because, Glassfish 5 has all required modules anymore. - Step 5
- Browse
http://localhost:8080/mvc/app/person
location and test the application.
Let’s follow the Java EE Guardians. I hope to see you again.