Current Articles | RSS Feed
In this tutorial we'll update you on the world of Java EE 6 with the help of a Twitter-like demo application we've code-named wallfriend. The demo application contains JSF 2.0, PrimeFaces, CDI and Weld as well as Hibernate Validator frameworks.
Our tutorial assumes that you're familiar with the following technologies:
You'll also need to install the following applications in order to build the demo application from scratch, or to run it on your local machine:
Java EE 6 specification was finalized in December of 2009, bringing new and updated features to the world of enterprise application development. It introduces the profile approach, meant to focus both developers and applications on particular parts of the Java EE 6 platform. The first profile defined by the expert group is the Java EE 6 web profile, which attempts to specify the minimal configuration targeted for the development of typical web applications. Here are the elements of the web profile, with a few that we've chosen to explain in detail.
There are currently two application servers that are compatible with the implementation of Java EE 6: GlassFish Enterprise Server v3 and TMAX JEUS 7. We’ve chosen to stick with GlassFish v3.
PrimeFaces is an open source JSF component suite that bundles over 70 components with built-in Ajax support. It’s based on the YUI and jQuery javascripting libraries. It has a simple, lightweight design that is fully compatible with other JSF component libraries. PrimeFaces also supports Ajax Push with a Comet framework, and it has a mobile UI kit known as TouchFaces. Currently, PrimeFaces supports JSF 2.0 with its 2.0.0.RC and 2.0.0-SNAPSHOT releases.
The ability of Java EE 6 to merge web.xml fragments that originate from third-party frameworks makes it unnecessary (in the context of Java EE 6) to do servlet and mapping configurations for PrimeFaces. Primefaces ships with its own web-fragment.xml.For more information, visit www.primefaces.org.
As stated in Java Specification Request JSR-299, the purpose of this specification is to unify the JSF-managed bean component model with the EJB component model, resulting in a significantly simplified programming model for web-based applications. CDI also makes it possible for JEE elements to interact with each other using the observer pattern, making it a lot easier to work with enterprise beans and transactional support, among other things.
JSR 330 is also a part of Java EE 6, offering a set of standard annotations that can be used for dependency injection. In our demo application we'll use some of these annotations, such as @Named, @Inject, @Qualifier and others.
Weld is the reference implementation of JSR-299, which is abbreviated as CDI. Weld provides a complete SPI, allowing Java EE containers to use Weld as their built-in CDI implementation. GlassFish 3 (which we’ll use in our demo) ships with Weld.
The Bean Validation, JSR 303, defines a metadata model and an API for JavaBean validation. The Hibernate Validator is the reference implementation for this specification request. Hibernate Validator's latest version adds some nice features -- things like validation grouping, native integration with JPA v.2 and JSF v.2, an extended annotation set and more.
Let’s start by creating the project. We’ll do it using the Maven archetype command. It has an interactive mode, so see below for the user input data (in bold).
mvn archetype:generate -DarchetypeCatalog=http://anonsvn.jboss.org /repos/weld/archetypes/tags/1.0.0-BETA1
DEV$ mvn archetype:generate -DarchetypeCatalog=http://anonsvn.jboss.org /repos/weld/archetypes/tags/1.0.0-BETA1[INFO] Scanning for projects...[INFO] Searching repository for plugin with prefix: 'archetype'.[INFO] ------------------------------------------------------------------[INFO] Building Maven Default Project[INFO] task-segment: [archetype:generate] (aggregator-style)[INFO] ------------------------------------------------------------------[INFO] Preparing archetype:generate[INFO] No goals needed for project - skipping[INFO] Setting property: classpath.resource.loader.class =>'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.[INFO] Setting property: velocimacro.messages.on => 'false'.[INFO] Setting property: resource.loader => 'classpath'.[INFO] Setting property: resource.manager.logwhenfound => 'false'.[INFO] [archetype:generate][INFO] Generating project in Interactive mode[INFO] No archetype defined. Using maven-archetype-quickstart(org.apache.maven.archetypes:maven-archetype-quickstart:1.0)Choose archetype:1: remote -> weld-jsf-servlet-minimal (Weld archetype for creating anapplication using JSF 2.0 and CDI 1.0 for Servlet Containers(Tomcat 6 / Jetty 6))2: remote -> weld-jsf-jee-minimal (Weld archetype for creating a minimalJava EE 6 application using JSF 2.0, CDI 1.0 and EJB 3.1 (persistence unitnot included))3: remote -> weld-jsf-jee (Weld archetype for creating a Java EE 6application using JSF 2.0, CDI 1.0, EJB 3.1 and JPA 2.0 (persistenceunit included))Choose a number: (1/2/3): 2Here enter 2, for weld-jsf-jee-minimal. And then specify thegroupId-artifactId-packaging for the project.Define value for groupId: : com.openlogic.waziDefine value for artifactId: : wallfriendDefine value for package: : warConfirm properties configuration:version: 1.0.0-SNAPSHOTgroupId: com.openlogic.waziartifactId: wallfriendpackage: war Y: : Y[INFO] -------------------------------------------------------------------[INFO] BUILD SUCCESSFUL[INFO] -------------------------------------------------------------------[INFO] Total time: 19 seconds[INFO] Finished at: Tue Jan 12 21:58:35 EET 2010 [INFO]Final Memory: 12M/79M [INFO]-------------------------------------------------------------------
DEV$ mvn package embedded-glassfish:run[INFO] Scanning for projects...[INFO] Searching repository for plugin with prefix: 'embedded-glassfish'.[INFO] org.apache.maven.plugins: checking for updates from glassfish[INFO] org.codehaus.mojo: checking for updates from glassfish[INFO] -------------------------------------------------------------------[INFO] Building wallfriend[INFO] task-segment: [package, embedded-glassfish:run][INFO] -------------------------------------------------------------------[INFO] [resources:resources][INFO] Using default encoding to copy filtered resources.[INFO] [compiler:compile][INFO] Compiling 1 source file to /DEV/wallfriend/target/classes[INFO] [resources:testResources][INFO] Using default encoding to copy filtered resources.[INFO] [compiler:testCompile][INFO] Compiling 1 source file to /DEV/wallfriend/target/test-classes[INFO] [surefire:test][INFO] Surefire report directory: /DEV/wallfriend/target/surefire-reports------------------------------------------------------- T E S T S-------------------------------------------------------Running TestSuiteTests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.369 secResults :Tests run: 1, Failures: 0, Errors: 0, Skipped: 0[INFO] [war:war][INFO] Packaging webapp[INFO] Assembling webapp[wallfriend] in [/DEV/wallfriend/target/wallfriend][INFO] Processing war project[INFO] Webapp assembled in[162 msecs][INFO] Building war: /DEV/wallfriend/target/wallfriend.war[INFO] [embedded-glassfish:run][WARNING] Attempting to build MavenProject instance for Artifact(org.codehaus.mojo:jboss-maven-plugin:3.0) of type: maven-plugin;constructing POM artifact instead.Downloading: http://repository.jboss.org/maven2/org/codehaus/mojo/jboss-maven-plugin/3.0/jboss-maven-plugin-3.0.pomDownloading: http://repo1.maven.org/maven2/org/codehaus/mojo/jboss-maven-plugin/3.0/jboss-maven-plugin-3.0.pom[WARNING] Attempting to build MavenProject instance for Artifact(org.apache.maven.plugins:maven-eclipse-plugin:3.0) of type:maven-plugin; constructing POM artifact instead.Downloading: http://repository.jboss.org/maven2/org/apache/maven/plugins/maven-eclipse-plugin/3.0/maven-eclipse-plugin-3.0.pomDownloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-eclipse-plugin/3.0/maven-eclipse-plugin-3.0.pomJan 13, 2010 10:36:39 PM com.sun.enterprise.v3.server.AppServerStartup runINFO: GlassFish v3 (74.2) startup time : Embedded(1228ms)startup services(1317ms) total(2545ms)Jan 13, 2010 10:36:39 PM com.sun.enterprise.transaction.JavaEETransactionManagerSimplified initDelegatesINFO: Using com.sun.enterprise.transaction.jts.JavaEETransactionManagerJTSDelegate as the delegateJan 13, 2010 10:36:40 PM org.glassfish.admin.mbeanserver.JMXStartupService$JMXConnectorsStarterThread runINFO: JMXStartupService: JMXConnector system is disabled, skipping.Jan 13, 2010 10:36:40 PM AppServerStartup runINFO: [Thread[GlassFish Kernel Main Thread,5,main]] startedJan 13, 2010 10:36:40 PM org.hibernate.validator.util.VersionINFO: Hibernate Validator nullJan 13, 2010 10:36:40 PM org.hibernate.validator.engine.resolver.DefaultTraversableResolver detectJPAINFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.Jan 13, 2010 10:36:41 PM com.sun.enterprise.v3.services.impl.GrizzlyProxy$2$1 onReadyINFO: Grizzly Framework 1.9.18-k started in: 434ms listening on port 7070Jan 13, 2010 10:36:58 PM com.sun.common.util.logging.LoggingConfigImpl openPropFileINFO: Cannot read logging.properties file.Jan 13, 2010 10:36:58 PM com.sun.enterprise.web.WebContainercreateHttpListenerINFO: Created HTTP listener embedded-listener on port 7070Jan 13, 2010 10:36:58 PM com.sun.enterprise.web.WebContainerconfigureHttpServicePropertiesWARNING: pewebcontainer.invalid_http_service_propertyJan 13, 2010 10:36:59 PM com.sun.enterprise.web.WebContainer createHostsINFO: Created virtual server serverJan 13, 2010 10:36:59 PM com.sun.enterprise.web.WebContainerloadSystemDefaultWebModulesINFO: Virtual server server loaded system default web module^[[BJan 13, 2010 10:37:08 PM com.sun.enterprise.security.SecurityLifecycleINFO: security.secmgroffJan 13, 2010 10:37:09 PM com.sun.enterprise.security.ssl.SSLUtilscheckCertificateDatesSEVERE: java_security.expired_certificateJan 13, 2010 10:37:09 PM com.sun.enterprise.security.SecurityLifecycleonInitializationINFO: Security startup service calledJan 13, 2010 10:37:09 PM com.sun.enterprise.security.PolicyLoaderloadPolicyINFO: policy.loadingJan 13, 2010 10:37:09 PM com.sun.enterprise.security.auth.realm.RealmdoInstantiateINFO: Realm admin-realm of classtype com.sun.enterprise.security.auth.realm.file.FileRealm successfully created.Jan 13, 2010 10:37:09 PM com.sun.enterprise.security.auth.realm.RealmdoInstantiateINFO: Realm file of classtype com.sun.enterprise.security.auth.realm.file.FileRealm successfully created.Jan 13, 2010 10:37:09 PM com.sun.enterprise.security.auth.realm.RealmdoInstantiateINFO: Realm certificate of classtype com.sun.enterprise.security.auth.realm.certificate.CertificateRealm successfully created.Jan 13, 2010 10:37:09 PM com.sun.enterprise.security.SecurityLifecycleonInitializationINFO: Security service(s) started successfully....classLoader = WebappClassLoader (delegate=true; repositories=WEB-INF/classes/)SharedSecrets.getJavaNetAccess()=java.net.URLClassLoader$7@2d205042Jan 13, 2010 10:37:09 PM org.jboss.weld.bootstrap.WeldBootstrapINFO: WELD-000900 SNAPSHOTJan 13, 2010 10:37:09 PM org.hibernate.validator.engine.resolver.DefaultTraversableResolver detectJPAINFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.nullID: /DEV/wallfriend/gfembed6764346819525137279tmp/applications/wallfriend/ CLASSES: [class war.HelloWorld]Jan 13, 2010 10:37:10 PM com.sun.faces.config.ConfigureListenercontextInitializedINFO: Initializing Mojarra 2.0.2 (FCS b10) for context '/wallfriend'Jan 13, 2010 10:37:14 PM com.sun.enterprise.web.WebApplication startINFO: Loading application wallfriend at /wallfriendHit ENTER to redeploy, X to exit
Once you see the line Hit ENTER to redeploy, X to exit, make a request for http://localhost:7070/wallfriend on your browser. You should get a first look at the archetype application like the one below:
Now, let’s open the project inside NetBeans 6.8. Open NetBeans and click File > New Project and then select Maven / Maven Project with Existing POM from the resulting wizard. This should put the Open Project menu on your screen. Select wallfriend from here and you should see the project in the projects tab:To run wallfriend inside NetBeans 6.8, you need to make sure that you have Java 1.6 defined as a Java platform, and be sure that wallfriend is also using it. Also, from the Tools > Servers menu, you need to define the Java 1.6 executable for your GlassFish. Netbeans also comes with a Maven 3.0-SNAPSHOT version. So, if you want to use your own external Maven, you must declare it to the IDE from Preferences > Miscellaneous > Maven. After configuring it all, just make a request for http://localhost:8080/wallfriend on your browser. You should see the very same page as you did when you ran the project with the embedded GlassFish.
In order to use the JSF components of PrimeFaces, we first have to add the repo and dependency definitions to the pom.xml of the project. Go ahead and open Project Files > pom.xml in NetBeans and add the following snippets, respectively:
<repository> <id>prime-repo</id> <name>Prime Technology Maven Repository</name> <url>http://repository.prime.com.tr</url> <layout>default</layout></repository><dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>2.0.0-SNAPSHOT</version></dependency>
Now namespace can be added inside the xhtml’s files for PrimeFaces, xmlns:p="http://primefaces.prime.com.tr/ui". As mentioned above, there is no configuration needed in web.xml since PrimeFaces ships with its own web fragment.
Wallfriend – The ImplementationAs we said before, wallfriend is a simple write-to-wall application with a basic domain, managed beans, and some xhtml pages. You can check out the source from the Google Code project at http://wallfriend.googlecode.com/svn/trunk/wallfriend. A follow the wall mechanism as well as a restful expose of the wall will be added to the project in the near future.Since the application was not created from scratch, we have some clean-up to do on the archetype-created application. Go ahead and delete the following folders, because they won’t be used:
Now let’s go through the parts of the project: The Model, The Managed Beans, and The Views.
The ModelFor the domain, we have 3 classes: Wall, Brick and WallFriendContext. Wall and Brick are for defining a master-detail relationship between the posts and the wall. WallFriendContext is the application-scoped bean for storing created walls. It's marked with the javax.enterprise.context.ApplicationScoped bean.Wall.java
package com.openlogic.wazi.beans;import java.util.LinkedList;import java.util.List;public class Wall { String wallName; List bricks = new LinkedList(); public Wall(String wallName) { this.wallName = wallName; } public void addBrick(String graffiti) { bricks.add(0, new Brick(graffiti)); } public String getWallName() { return wallName; } public List getBricks() { return bricks; }}
package com.openlogic.wazi.beans;import java.util.Date;public class Brick { private String graffiti; private Date publishDate; public Brick(String graffiti) { this.graffiti = graffiti; this.publishDate = new Date(); } public void init() { } public String getGraffiti() { return graffiti; } public void setGraffiti(String graffiti) { this.graffiti = graffiti; } public Date getPublishDate() { return publishDate; } public void setPublishDate(Date publishDate) { this.publishDate = publishDate; }}
package com.openlogic.wazi.beans;import java.util.HashMap;import java.util.Map;import javax.enterprise.context.ApplicationScoped;@ApplicationScopedpublic class WallFriendContext { private Map walls = new HashMap(); public void addWall(Wall wall) { walls.put(wall.getWallName(), wall); } public Map getWalls() { return walls; }}
The Managed Beans (a.k.a. Contextual Beans)The managed bean classes are defined by the CDI and implemented by Weld, which ships with the GlassFish server. CDI also needs an empty beans.xml file under the WEB-INF folder, since we’re going to use annotations to define our beans. That's right -- that means they can also be configured with good old fashioned XML.
LoginView is the managed bean of choice for handling wall management and creation/accessing. The annotation javax.enterprise.inject.Model identifies the LoginView as a bean of the model layer, as stated in the MVC pattern. We use javax.inject.Inject to identify injectable constructors, while methods and fields. org.hibernate.validator.constraints.NotEmpty is a validator annotation that specifies that the field wallName cannot be empty.
package com.openlogic.wazi.view;import com.openlogic.wazi.beans.Wall;import com.openlogic.wazi.beans.WallFriendContext;import javax.enterprise.inject.Model;import javax.faces.context.FacesContext;import javax.inject.Inject;import org.hibernate.validator.constraints.NotEmpty;@Modelpublic class LoginView { @Inject private WallFriendContext wallFriendContext; @NotEmpty(message="Wall Name cannot be empty") private String wallName; public String doLogin() { Wall wall; if (wallFriendContext.getWalls().containsKey(wallName)) { wall = wallFriendContext.getWalls().get(wallName); } else { wall = new Wall(wallName); wallFriendContext.addWall(wall); } FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("wall", wall); return "myWall"; } public String getWallName() { return wallName; } public void setWallName(String wallName) { this.wallName = wallName; }}
MyWallView is the managed bean for handling the paint-a-graffiti on the wall action. The annotation javax.inject.Named, used here, allows you to access the bean using the bean name, with the first letter in lowercase. We use javax.annotation.PostConstruct to mark a method to be invoked after the Dependency Injection is done.
package com.openlogic.wazi.view;import com.openlogic.wazi.beans.Wall;import java.io.Serializable;import javax.annotation.PostConstruct;import javax.enterprise.context.SessionScoped;import javax.faces.context.FacesContext;import javax.inject.Named;import org.hibernate.validator.constraints.NotEmpty;@Named@SessionScopedpublic class MyWallView implements Serializable { private Wall wall; @PostConstruct public void init() { wall = (Wall) FacesContext.getCurrentInstance() .getExternalContext().getRequestMap().get("wall"); } @NotEmpty(message="Graffiti cannot be empty") private String graffiti; public String paint() { wall.addBrick(graffiti); graffiti = ""; return null; } public Wall getWall() { return wall; } public void setWall(Wall wall) { this.wall = wall; } public String getGraffiti() { return graffiti; } public void setGraffiti(String graffiti) { this.graffiti = graffiti; }}
The PagesFacelets, JSF 2.0, and PrimeFaces projects are used for the development of views. JSF tags are also commonly used. One different component could be p:growl, which is for viewing the FacesMessages in a Mac-like growl. Also, there is no defined navigation-rule in the faces-config.xml file for navigating from login.xhtml to myWall.xhtml. This is with the implicit navigation mechanism that comes with JSF 2.0. The return string of LoginView#doLogin() method matches the name of the myWall.xhtml view.
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.prime.com.tr/ui"> <h:head> <title>WallFriend - Java EE 6 Starter Application</title> </h:head> <h:body> <h:form> <p:growl showDetail="true" /> <p:panel header="Access to your wall" style="width:400px"> <h:outputLabel value="Wall Name : " for="wallname" /> <h:inputText id="wallname" value="#{loginView.wallName}" /> <h:commandButton value="Paint it Now, Paint it Black" action="#{loginView.doLogin}" /> </p:panel> </h:form> </h:body></html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.prime.com.tr/ui"> <h:head> <title>WallFriend - Java EE 6 Starter Application</title> </h:head> <h:body> <h:form> <p:growl showDetail="true" /> <p:panel header="#{myWallView.wall.wallName}'s WALL" style="width:600px"> <h:panelGrid columns="1"> <h:panelGroup> <h:inputTextarea value="#{myWallView.graffiti}" cols="50" rows="3" /> <h:commandButton value="Paint" action="#{myWallView.paint}" /> </h:panelGroup> <p:dataTable value="#{myWallView.wall.bricks}" var="brick"> <p:column> #{brick.graffiti} <br/> <h:outputText value="#{brick.publishDate}"> <f:convertDateTime dateStyle="default" type="both" pattern="dd.MM.yyyy HH:mm:ss" /> </h:outputText> </p:column> </p:dataTable> </h:panelGrid> </p:panel> </h:form> </h:body></html>
Java EE 6 is hot, new, and pretty darn cool. In our opinion, as users begin to employ it for upcoming projects, the number of blogposts, samples, and other resources will eventually increase. And with its adoption by the Java Community, we'll for sure see more Java EE 6-compliant application servers around. Java EE 6 really eases development with its "standardized" features, and the zero-configuration approach apparent in every part of the implementation is really nice, lending an out-of-the-box feeling that's similar to the .NET environment. It's not just another java framework!
Allowed tags: <a> link, <b> bold, <i> italics