This project demonstrates how to create standalone Java EE MVC
application.
MVC is newly developed Java EE JSR 371: Model-View-Controller (MVC 1.0) Specification.
it is easy to bootstrap and shutdown CDI container:
You can see we also start and stop CDI ApplicationScoped scope.
Important part is registering of Weld Servlet listeners: WeldInitialListener and WeldTerminalListener.
The instance of Jersey ServletContainer is provided as ApplicationScoped bean by custom CdiProducer using CdiClassIntrospecter.
You can see we need to customize "javax.mvc.engine.ViewEngine.viewFolder" property to support standalone application class-path behaviour.
CdiClassIntrospecter implements Undertow ClassIntrospecter interface and just delegates to CDI.
You can see I've chosen to use Mustache template engine, see hello.mustache:
The easiest way how to run the project is:
The application is then available on: http://localhost:8080/resources/hello?user=Libor.
MVC is newly developed Java EE JSR 371: Model-View-Controller (MVC 1.0) Specification.
The MVC API defines an action-oriented Web framework as an alternative to the component-oriented JSF. In an action-oriented framework, developers are responsible for all the controller logic and are given full control of the URI space for their application.
The MVC API is layered on top of JAX-RS over Servlets and integrates with existing EE technologies like CDI and Bean Validation.MVC spec is going to be part of next Java EE 8. MVC reference implementation named Ozark is hosted on java.net. MVC depends on Servlets, JAX-RS and CDI. I've chosen to use Undertow, Jersey and Weld. And DeltaSpike as CDI extension library. Finally, Gradle to build and run the project.
ext { undertowVersion = '1.3.18.Final'
weldVersion = '2.3.3.Final' deltaspikeVersion = '1.5.4' jerseyVersion = '2.22.2' ozarkVersion = '1.0.0-m02' } task wrapper(type: Wrapper) { gradleVersion = '2.12' }
Standalone CDI container
Weld contains module to support Java SE applications. Together with Apache DeltaSpike Java SE & Weld module:dependencies { compile "org.jboss.weld.se:weld-se:$weldVersion" compile "org.apache.deltaspike.cdictrl:deltaspike-cdictrl-weld:$deltaspikeVersion"
it is easy to bootstrap and shutdown CDI container:
import javax.enterprise.context.ApplicationScoped;
import org.apache.deltaspike.cdise.api.CdiContainer; import org.apache.deltaspike.cdise.api.CdiContainerLoader; import org.jboss.weld.servlet.WeldInitialListener; import org.jboss.weld.servlet.WeldTerminalListener; public class Main { static CdiContainer init() throws ServletException, NoSuchMethodException { CdiContainer cdiContainer = CdiContainerLoader.getCdiContainer(); cdiContainer.boot(); cdiContainer.getContextControl().startContext(ApplicationScoped.class); initServlet(); return cdiContainer; } static void destroy(CdiContainer cdiContainer) { cdiContainer.getContextControl().stopContext(ApplicationScoped.class); cdiContainer.shutdown(); } ...
You can see we also start and stop CDI ApplicationScoped scope.
Initialize Servlet
Next we need to register Jersey ServletContainer as Undertow servlet:dependencies { compile "io.undertow:undertow-core:$undertowVersion" compile "io.undertow:undertow-servlet:$undertowVersion" compile "org.glassfish.jersey.core:jersey-server:$jerseyVersion" compile "org.glassfish.jersey.containers:jersey-container-servlet-core:$jerseyVersion" compile "org.glassfish.jersey.ext.cdi:jersey-cdi1x-servlet:$jerseyVersion"
import javax.servlet.Servlet; import javax.servlet.ServletException; import io.undertow.Undertow; import io.undertow.servlet.Servlets; import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.DeploymentManager; import io.undertow.servlet.api.ServletContainer; import io.undertow.servlet.api.ServletInfo; import org.jboss.weld.servlet.WeldInitialListener; import org.jboss.weld.servlet.WeldTerminalListener; public class Main { ... private static void initServlet() throws ServletException, NoSuchMethodException { DeploymentInfo deploymentInfo = new DeploymentInfo() .addListener(Servlets.listener(WeldInitialListener.class)) .addListener(Servlets.listener(WeldTerminalListener.class)) .setContextPath("/") .setDeploymentName("standalone-javax-mvc-app") .addServlets( createServletInfo("/resources/*", "JAX-RS Resources", org.glassfish.jersey.servlet.ServletContainer.class) ) .setClassIntrospecter(CdiClassIntrospecter.INSTANCE) .setAllowNonStandardWrappers(true) .setClassLoader(ClassLoader.getSystemClassLoader()); ServletContainer servletContainer = Servlets.defaultContainer(); DeploymentManager deploymentManager = servletContainer.addDeployment(deploymentInfo); deploymentManager.deploy(); Undertow server = Undertow.builder() .addHttpListener(8080, "0.0.0.0") .setHandler(deploymentManager.start()) .build(); server.start(); } private static ServletInfo createServletInfo(String mapping, String servletName, Class<? extends Servlet> servlet) throws NoSuchMethodException { ServletInfo servletInfo = Servlets .servlet(servletName, servlet) .setAsyncSupported(true) .setLoadOnStartup(1) .addMapping(mapping); servletInfo.setInstanceFactory(CdiClassIntrospecter.INSTANCE.createInstanceFactory(servlet)); return servletInfo; } }
Important part is registering of Weld Servlet listeners: WeldInitialListener and WeldTerminalListener.
The instance of Jersey ServletContainer is provided as ApplicationScoped bean by custom CdiProducer using CdiClassIntrospecter.
import javax.enterprise.inject.Produces; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; @ApplicationScoped public class CdiProducer { private long helloCounter; @Produces @ApplicationScoped public ServletContainer createServletContainer() { final ResourceConfig resourceConfig = new ResourceConfig(); resourceConfig.register(HelloController.class); resourceConfig.property("javax.mvc.engine.ViewEngine.viewFolder", "WEB-INF/views/"); return new ServletContainer(resourceConfig); } ...
You can see we need to customize "javax.mvc.engine.ViewEngine.viewFolder" property to support standalone application class-path behaviour.
CdiClassIntrospecter implements Undertow ClassIntrospecter interface and just delegates to CDI.
MVC
Now you can provide MVC @Controller methods:dependencies { compile "org.glassfish.ozark:ozark:$ozarkVersion" compile "org.glassfish.ozark.ext:ozark-mustache:$ozarkVersion"
import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.mvc.Models; import javax.mvc.annotation.Controller; import javax.mvc.annotation.View; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; @Path("hello") @ApplicationScoped public class HelloController { @Inject private Models models; @GET @Controller @Produces("text/html") @View("hello.mustache") public void hello(@QueryParam("user") @DefaultValue("World") String user) { models.put("user", user); } }
You can see I've chosen to use Mustache template engine, see hello.mustache:
<html> <head> <title>Hello</title> </head> <body> <h1>Hello {{user}}!</h1> </body> </html>
Sources
Complete project sources are available on GitHub, https://github.com/shamoh/standalone-javax-mvc.The easiest way how to run the project is:
gradlew run
The application is then available on: http://localhost:8080/resources/hello?user=Libor.
This comment has been removed by the author.
ReplyDeleteThanks for sharing such a useful article JAVA coding is the best to develop applications
ReplyDeleteVery Useful articlepmp certification in malaysia
ReplyDelete
ReplyDeleteSimply the manner in which I have anticipated. Your site truly is intriguing.
training provider in malaysia
Thank you for excellent article.You made an article that is interesting.
ReplyDeletedata science course gurgaon
nice blog!! i hope you will share a blog on Data Science.
ReplyDeletedata analytics course in yelahanka
great article!! sharing these type of articles is the nice one and i hope you will share an article on data science.By giving a institute like 360DigiTMG.it is one the best institute for doing certified courses
ReplyDeletedata science course in aurangabad