Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Magnificent Java EE 7 in WildFly-O-Rama

The Magnificent Java EE 7 in WildFly-O-Rama

My Hands on for Java EE 7
You can grab the code on github: https://github.com/antoinesd/magnificent-java-ee7

Antoine Sabot-Durand

January 22, 2014
Tweet

More Decks by Antoine Sabot-Durand

Other Decks in Programming

Transcript

  1. The Magnificent Java EE 7 in Wildfly-O-Rama Antoine Sabot-Durand Java

    EE Expert Senior Software Developer @ Red Hat @antoine_sd
  2. Antoine Sabot-Durand Senior Software Developer at Red Hat Architect and

    Tech consultant 16 years in IT Java & OSS : CDI co-spec lead CDI community development Agorava technical leader @antoine_sd
  3. What’s in there ? Short Java EE 7 Intro Java

    EE History Java EE 7 main features Java EE 7 Content WildFly WildFly Roadmap Java EE 7 in action
  4. Java EE History 1998 1999 2000 2001 2002 2003 2004

    2005 2006 2007 2008 2009 2010 2011 2012 2013
  5. Java EE History 1998 1999 2000 2001 2002 2003 2004

    2005 2006 2007 2008 2009 2010 2011 Java Professional Edition Mai 1998 2012 2013
  6. Java EE History 1998 1999 2000 2001 2002 2003 2004

    2005 2006 2007 2008 2009 2010 2011 Java Professional Edition Mai 1998 J2EE 1.2 12/12/1999 2012 2013
  7. Java EE History 1998 1999 2000 2001 2002 2003 2004

    2005 2006 2007 2008 2009 2010 2011 Java Professional Edition Mai 1998 J2EE 1.2 12/12/1999 J2EE 1.3 09/24/2001 2012 2013
  8. Java EE History 1998 1999 2000 2001 2002 2003 2004

    2005 2006 2007 2008 2009 2010 2011 Java Professional Edition Mai 1998 J2EE 1.2 12/12/1999 J2EE 1.3 09/24/2001 J2EE 1.4 11/11/2003 2012 2013
  9. Java EE History 1998 1999 2000 2001 2002 2003 2004

    2005 2006 2007 2008 2009 2010 2011 Java Professional Edition Mai 1998 J2EE 1.2 12/12/1999 J2EE 1.3 09/24/2001 J2EE 1.4 11/11/2003 Java EE 5 05/11/2006 2012 2013
  10. Java EE History 1998 1999 2000 2001 2002 2003 2004

    2005 2006 2007 2008 2009 2010 2011 Java Professional Edition Mai 1998 J2EE 1.2 12/12/1999 J2EE 1.3 09/24/2001 J2EE 1.4 11/11/2003 Java EE 5 05/11/2006 Java EE 6 12/10/2009 2012 2013
  11. Java EE History 1998 1999 2000 2001 2002 2003 2004

    2005 2006 2007 2008 2009 2010 2011 Java Professional Edition Mai 1998 J2EE 1.2 12/12/1999 J2EE 1.3 09/24/2001 J2EE 1.4 11/11/2003 Java EE 5 05/11/2006 Java EE 6 12/10/2009 2012 2013 Java EE 7 06/22/2013
  12. WebSocket client/server endpoints Batch Applications JSON Processing Concurrency Utilities Simplified

    JMS API @Transactional and @TransactionScoped JAX-RS Client API Pervasive CDI More annotated POJOs Faces Flow Java EE 7 Main Features
  13. Java EE 7 JSR EJB 3.2 Servlet 3.1 CDI Extensions

    Bean Validation 1.1 Batch 1.0 Web Fragments JCA 1.7 JMS 2.0 JPA 2.1 Managed Beans 1.0 Concurrency 1.0 Common Annotations 1.1 Interceptors
 1.2, JTA 1.2 CDI 1.1 JSF 2.2,
 JSP 2.3,
 EL 3.0 JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0
  14. Java EE 7 JSR EJB 3.2 Servlet 3.1 CDI Extensions

    Bean Validation 1.1 Batch 1.0 Web Fragments JCA 1.7 JMS 2.0 JPA 2.1 Managed Beans 1.0 Concurrency 1.0 Common Annotations 1.1 Interceptors
 1.2, JTA 1.2 CDI 1.1 JSF 2.2,
 JSP 2.3,
 EL 3.0 JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0
  15. Java EE 7 JSR EJB 3.2 Servlet 3.1 CDI Extensions

    Bean Validation 1.1 Batch 1.0 Web Fragments JCA 1.7 JMS 2.0 JPA 2.1 Managed Beans 1.0 Concurrency 1.0 Common Annotations 1.1 Interceptors
 1.2, JTA 1.2 CDI 1.1 JSF 2.2,
 JSP 2.3,
 EL 3.0 JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0
  16. Java EE 7 JSR EJB 3.2 Servlet 3.1 CDI Extensions

    Bean Validation 1.1 Batch 1.0 Web Fragments JCA 1.7 JMS 2.0 JPA 2.1 Managed Beans 1.0 Concurrency 1.0 Common Annotations 1.1 Interceptors
 1.2, JTA 1.2 CDI 1.1 JSF 2.2,
 JSP 2.3,
 EL 3.0 JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0
  17. Java EE 7 JSR EJB 3.2 Servlet 3.1 CDI Extensions

    Bean Validation 1.1 Batch 1.0 Web Fragments JCA 1.7 JMS 2.0 JPA 2.1 Managed Beans 1.0 Concurrency 1.0 Common Annotations 1.1 Interceptors
 1.2, JTA 1.2 CDI 1.1 JSF 2.2,
 JSP 2.3,
 EL 3.0 JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0
  18. Java EE 7 JSR EJB 3.2 Servlet 3.1 CDI Extensions

    Bean Validation 1.1 Batch 1.0 Web Fragments JCA 1.7 JMS 2.0 JPA 2.1 Managed Beans 1.0 Concurrency 1.0 Common Annotations 1.1 Interceptors
 1.2, JTA 1.2 CDI 1.1 JSF 2.2,
 JSP 2.3,
 EL 3.0 JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0
  19. Java EE 7 JSR EJB 3.2 Servlet 3.1 CDI Extensions

    Bean Validation 1.1 Batch 1.0 Web Fragments JCA 1.7 JMS 2.0 JPA 2.1 Managed Beans 1.0 Concurrency 1.0 Common Annotations 1.1 Interceptors
 1.2, JTA 1.2 CDI 1.1 JSF 2.2,
 JSP 2.3,
 EL 3.0 JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0
  20. Java EE 7 JSR EJB 3.2 Servlet 3.1 CDI Extensions

    Bean Validation 1.1 Batch 1.0 Web Fragments JCA 1.7 JMS 2.0 JPA 2.1 Managed Beans 1.0 Concurrency 1.0 Common Annotations 1.1 Interceptors
 1.2, JTA 1.2 CDI 1.1 JSF 2.2,
 JSP 2.3,
 EL 3.0 JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0
  21. Java EE 7 JSR EJB 3.2 Servlet 3.1 CDI Extensions

    Bean Validation 1.1 Batch 1.0 Web Fragments JCA 1.7 JMS 2.0 JPA 2.1 Managed Beans 1.0 Concurrency 1.0 Common Annotations 1.1 Interceptors
 1.2, JTA 1.2 CDI 1.1 JSF 2.2,
 JSP 2.3,
 EL 3.0 JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0
  22. Java EE 7 JSR EJB 3.2 Servlet 3.1 CDI Extensions

    Bean Validation 1.1 Batch 1.0 Web Fragments JCA 1.7 JMS 2.0 JPA 2.1 Managed Beans 1.0 Concurrency 1.0 Common Annotations 1.1 Interceptors
 1.2, JTA 1.2 CDI 1.1 JSF 2.2,
 JSP 2.3,
 EL 3.0 JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0
  23. Previously named JBoss Application Server Named change to better differentiate

    Community from Supported product Support Java EE 7 Fast, Lightweight, Manageable Developer Friendly Open Source JBoss WildFly
  24. Alpha 1 - May 2013 Alpha 2 - June 2013

    (Java EE 7 released on the 22) Alpha 3 - July 2013 Alpha 4 - August 2013 Beta 1 - October 2013 CR1 - December 2013 Final - Mar/Apr 2014 That’s 8/9 months after EE 7 release (better than 2 years for AS 7) WildFly Roadmap
  25. Welcome to Chat-e-Chat-o Chat-e-Chat-o is a Startup which develop a

    SaaS chat service We raised fund from VC to create their first release CTO decided to use Java EE 7 to develop the service As the main developer, you have the task to implement all the feature asked by marketing Events and name in this HOL are totally fictive Situation and use cases are simplified This is your story...
  26. At the beginning After reading some doc. You created the

    first chat demo It contains 4 files pom.xml : Maven configuration file ChatEndPoint.java : A Java class corresponding to a websocket Endpoint index.html : Home Page of the Service websocket.js : a little JS lib to exchange with the server This 4 files are enough to start the application server with a (very) basic chat service
  27. pom.xml 1/2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>org.lab.javaee</groupId>
 <artifactId>demo-chat</artifactId>


    <version>1.0-SNAPSHOT</version>
 <packaging>war</packaging>
 <name>demo-chat</name>
 
 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>
 
 <dependencies>
 <dependency>
 <groupId>javax</groupId>
 <artifactId>javaee-api</artifactId>
 <version>7.0</version>
 <scope>provided</scope>
 </dependency>
 </dependencies>

  28. pom.xml 2/2 <build>
 <finalName>${project.name}</finalName>
 <plugins>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 <version>3.0</version>
 <configuration>


    <source>1.7</source>
 <target>1.7</target>
 </configuration>
 </plugin>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-war-plugin</artifactId>
 <version>2.3</version>
 <configuration>
 <failOnMissingWebXml>false</failOnMissingWebXml>
 </configuration>
 </plugin>
 <plugin>
 <groupId>org.wildfly.plugins</groupId>
 <artifactId>wildfly-maven-plugin</artifactId>
 <version>1.0.0.Beta1</version> <configuration>
 <version>8.0.0.CR1</version>
 </configuration>
 </plugin>
 </plugins>
 </build>
 </project>
  29. index.html <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>WebSocket Chat</title>
 </head>


    <body>
 <h1>Chat!</h1>
 <div style="text-align: center;">
 <form action="">
 <table>
 <tr>
 <td>
 Users<br/>
 <textarea readonly="true" rows="6" cols="20" id="userField"></textarea>
 </td>
 <td>
 Chat Log<br/>
 <textarea readonly="true" rows="6" cols="50" id="chatlogField"></textarea>
 </td>
 </tr>
 <tr>
 <td colspan="2">
 <input id="textField" name="name" value="Duke" type="text"><br>
 <input onclick="join();" value="Join" type="button">
 <input onclick="send_message();" value="Chat" type="button">
 </td>
 </tr>
 </table>
 </form>
 </div>
 <div id="output"></div>
 <script language="javascript" type="text/javascript" src="websocket.js"></script>
 </body>
 </html>
  30. websocket.js var wsUri = "ws://" + document.location.host + "/demo-chat/websocket";
 var

    websocket = new WebSocket(wsUri);
 var username;
 var output = document.getElementById("output");
 
 websocket.onopen = function (evt) {onOpen(evt)};
 websocket.onmessage = function (evt) {onMessage(evt)};
 websocket.onerror = function (evt) {onError(evt)};
 ! function join() {
 username = textField.value;
 websocket.send(username + " joined");
 }
 ! function send_message() {websocket.send(username + ": " + textField.value);}
 ! function onOpen() {writeToScreen("Connected to " + wsUri);}
 ! function onMessage(evt) {
 console.log("onMessage");
 writeToScreen("RECEIVED: " + evt.data);
 if (evt.data.indexOf("joined") != -1) {
 userField.innerHTML += evt.data.substring(0, evt.data.indexOf(" joined")) + "\n";
 } else {
 chatlogField.innerHTML += evt.data + "\n";
 }
 }
 ! function onError(evt) {writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);}
 ! function writeToScreen(message) {output.innerHTML += message + "<br>";}
  31. ChatEndPoint.java import javax.websocket.*;
 import javax.websocket.server.ServerEndpoint;
 import java.io.IOException;
 import java.util.*;
 !

    @ServerEndpoint("/websocket")
 public class ChatEndpoint {
 private static final Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());
 
 @OnOpen
 public void onOpen(Session peer) {
 peers.add(peer);
 }
 
 @OnClose
 public void onClose(Session peer) {
 peers.remove(peer);
 }
 
 @OnMessage
 public void message(String message, Session client) throws IOException, EncodeException {
 for (Session peer : peers) {
 peer.getAsyncRemote().sendText(message);
 }
 }
 }

  32. Files organization & launching Files must be organized like this

    way To launch the app In your shell, go to the directory containing the pom.xml file and type : mvn clean package wildfly:run! To test the app browse to : http://localhost:8080/demo-chat
  33. Step 1 : Create a Chat Service As we will

    add functionalities to our application, we want to separate future business logic from the Websocket endpoint That’s why we decide to create a ChatService classes to deal with chat business logic To implement this you’ll have to : Activate CDI Create ChatService CDI Bean Remove all business logic from ChatEndpoint to put it in ChatService
  34. beans.xml ! Activate CDI To activate CDI you only have

    to create an empty file named beans.xml in folder
 src/main/webapp/WEB-INF
  35. ChatService.java @ApplicationScoped
 public class ChatService {
 
 private final Set<Session>

    peers = Collections.synchronizedSet(new HashSet<Session>());
 
 public boolean add(Session session) {
 return peers.add(session);
 }
 
 public boolean remove(Object o) {
 return peers.remove(o);
 }
 
 
 public void processMessage(String message) {
 for (Session peer : peers) {
 peer.getAsyncRemote().sendText(message);
 }
 }
 }
  36. ChatEndPoint.java @ServerEndpoint("/websocket")
 public class ChatEndpoint {
 
 @Inject
 private ChatService

    service;
 
 @OnOpen
 public void onOpen(Session peer) {
 service.add(peer);
 }
 
 @OnClose
 public void onClose(Session peer) {
 service.remove(peer);
 }
 
 @OnMessage
 public void message(String message, Session client) throws IOException, EncodeException {
 service.processMessage(message);
 }
 }
  37. Step 2 : Keyword detection Our main partner is the

    Poodle website.They want to embed our service but they need a solution to detect keywords in chat to feed their advertising platform You decide to build a prototype of this feature with CDI built-in observer pattern To implement this you’ll have to : Modify ChatService class by : Injecting an Event generator in the endpoint Modifying the message() method to fire the event Create an observer bean for the event
  38. ChatService.java import javax.enterprise.event.Event;
 import javax.inject.Inject; ...
 ! @ApplicationScoped
 public class

    ChatService { 
 ... @Inject
 private Event<String> events; ... 
 public void processMessage(String message) {
 if (message.toLowerCase().indexOf("world") > -1)
 events.fire(message);
 for (Session peer : peers) {
 peer.getAsyncRemote().sendText(message);
 }
 } }

  39. Bean with Observer import javax.enterprise.event.Observes;
 
 public class MessageObserver {


    
 public void observesWorldMessages(@Observes String msg) {
 System.out.println("Keyword was trapped : " + msg);
 }
 }
  40. Keyword detection result In your shell, go to the directory

    containing the pom.xml file and type :
 mvn clean package wildfly:run! To test the app browse to :
 http://localhost:8080/demo-chat When you type a message with «world» inside an event is fired and an alert is written on the console
  41. Step 3 : More decoupling with AOP Ok, our system

    to detect certain keywords works nicely with some kind of decoupling thanks to CDI events But the team is not happy to have this code directly into the service. If other filtering needs occur, we’ll have a big if cascade in processMessage() method So you decide to use AOP and interceptor to externalize event firing from your main code : Extract interface from ChatService to allow use of Decorator Create a decorator to track Ad Word in the ChatService processMessage() method Move the event generator to the Decorator
  42. Extract Interface from ChatService public interface ChatService {
 boolean add(Session

    session);
 
 boolean remove(Object o);
 
 void processMessage(String message);
 } @ApplicationScoped
 public class ChatServiceImpl implements ChatService {
 ! … ! }
  43. Create the PoodleAdWord Decorator @Decorator
 @Priority(Interceptor.Priority.APPLICATION)
 public abstract class PoddleAddWordDecorator

    implements ChatService {
 
 @Inject
 @Delegate
 private ChatService delegateService;
 
 private final List<String> adWords = new ArrayList<String>() {{
 add("world");
 add("duck");
 add("cartman");
 }};
 
 @Inject
 private Event<String> events; // This should be moved from ChatServiceImpl class
 
 @Override
 public void processMessage(String message) {
 String lmessage = message.toLowerCase();
 for (String s : adWords) {
 if (lmessage.indexOf(s) > -1) {
 events.fire(s);
 }
 }
 delegateService.processMessage(message);
 }
 }
  44. Final version of ChatServiceImpl @ApplicationScoped
 public class ChatServiceImpl implements ChatService

    {
 
 private final Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());
 
 @Override
 public boolean add(Session session) {
 return peers.add(session);
 }
 
 @Override
 public boolean remove(Object o) {
 return peers.remove(o);
 }
 
 @Override
 public void processMessage(String message) {
 for (Session peer : peers) {
 peer.getAsyncRemote().sendText(message);
 }
 }
 }
  45. More decoupling result Our business code doesn’t contain cross cuting

    concern anymore We’re ready to add other filters with this pattern To test, type :
 mvn clean package wildfly:run! To test the app browse to :
 http://localhost:8080/demo-chat When you type a message containing an ad word (i.e. duck) an event is fired and an alert is written on the console
  46. Step 4 : Please be polite The famous Mapple company

    is also very interested in our chat platform But they have a strict policy regarding bad words. So they need a solution to catch bad words, get notification and replace them by good ones. As Poodle pay us more we want to give priority to their ad filter to be sure that «bad» keywords are still trapped for them You know how to build this filter Create Qualifiers to differentiate Ad Word events from Bad Word events Build a new decorator to test messages content and correct impolite words Configure decorator priority to have the Poodle one in first Change existing event generator to add qualifiers top them
  47. Create the AdWord qualifier import javax.inject.Qualifier;
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;


    
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 ! @Qualifier
 @Documented
 @Retention(RUNTIME)
 public @interface AdWord {
 }
  48. Create the BadWord qualifier import javax.inject.Qualifier;
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;


    
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 ! @Qualifier
 @Documented
 @Retention(RUNTIME)
 public @interface BadWord {
 }
  49. Create the Mapple Decorator @Decorator
 @Priority(Interceptor.Priority.APPLICATION + 10)
 public abstract

    class MapplePoliteDecorator implements ChatService {
 
 static final Map<String, String> DICTIONARY = new HashMap<String, String>() {{
 put("fuck", "duck");
 put("crap", "trap");
 put("idiots", "world");
 put("cartman", "Stan");
 }};
 
 @Inject
 @Delegate
 private ChatService delegateService;
 
 @Inject
 @BadWord
 private Event<String> events;
 
 @Override
 public void processMessage(String message) {
 String lmessage = message.toLowerCase();
 String res = message;
 for (String word : DICTIONARY.keySet())
 if (lmessage.indexOf(word) > -1) {
 res = res.replaceAll("(?i)" + word, DICTIONARY.get(word));
 events.fire(word);
 }
 delegateService.processMessage(res);
 }
 }
  50. Change existing code to introduce AdWord qualifier @Decorator
 @Priority(Interceptor.Priority.APPLICATION)
 public

    abstract class PoddleAddWordDecorator implements ChatService {
 
 …
 @Inject
 @AdWord
 private Event<String> events;
 … } public class MessageObserver {
 
 public void observesAdWords(@Observes @AdWord String word) {
 System.out.println("Ad word trapped : " + word);
 }
 
 public void observesbadWords(@Observes @BadWord String word) {
 System.out.println("Bad word trapped : " + word);
 }
 }
  51. Be polite result We created a new Decorator that change

    message content after the 1st decorator did its job. We’ll feed those dictionaries with a database later To test type :
 mvn clean package wildfly:run! To test the app browse to :
 http://localhost:8080/demo-chat When you type a message containing a bad word inside, message is changed, an event is fired and an alert is written on the console. If the bad word is also an ad word. The Addword is still track thanks to priority
  52. Step 5 : Intercept to log Our code is nice

    with all this Decorators, but we’d like to have an easy way to trace what code is called without modifying it For that we’ll need another kind of AOP : an interceptor to log information Create an interceptor binding Create the Log interceptor Use it in our code
  53. Create the Interceptor Binding import javax.interceptor.InterceptorBinding;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;


    import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 @InterceptorBinding
 @Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 public @interface Log {
 }
  54. Create the interceptor @Interceptor
 @Log
 @Priority(Interceptor.Priority.APPLICATION)
 public class LoggerInterceptor {


    
 @AroundInvoke
 public Object manageTransaction(InvocationContext ctx) throws Exception {
 System.out.println("*** Before " + ctx.getMethod().toString());
 Object res = ctx.proceed();
 System.out.println("*** After " + ctx.getMethod().toString());
 return res;
 
 }
 }
  55. Log Interceptor result We created an interceptor and its binding

    to activate logging by annotation To test type :
 mvn clean package wildfly:run! To test the app browse to :
 http://localhost:8080/demo-chat All calls on ChatServiceImpl will be logged to the console
  56. Step 6 : Plastic surgery Let’s face the cruel truth

    our UI is totally ugly! As we decided to use Java EE stack, we give a try to JSF for our front Out of the box JSF doesn’t provide rich component, we’re going to use Primefaces to produce a nice UI proposal So, in this step, we’ll develop a JSF chat page to enhance the user experience
  57. Adding PrimeFaces to the POM <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">


    <modelVersion>4.0.0</modelVersion> …
 <dependencies>
 …
 <dependency>
 <groupId>org.primefaces</groupId>
 <artifactId>primefaces</artifactId>
 <version>4.0</version>
 <scope>runtime</scope>
 </dependency>
 </dependencies>
 …
 </project>
  58. The JSF Page <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD

    XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:ui="http://java.sun.com/jsf/facelets">
 <h:head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
 <title>WebSocket Chat</title>
 </h:head>
 <h:body>
 <p:layout style="width:1024px;height:600px;margin-left: auto;margin-right: auto;">
 <p:layoutUnit position="center" header="Chat-e-Chat-o">
 <div style="text-align: center;">
 <h:form id="chat">
 <table>
 <tr>
 <td>
 Users<br/>
 <p:inputTextarea readonly="true" rows="6" cols="20" id="userField"/>
 </td>
 <td>
 Chat Log<br/>
 <p:inputTextarea readonly="true" rows="6" cols="50" id="chatlogField"/>
 </td>
 </tr>
 <tr>
 <td colspan="2">
 <p:inputText id="textField" name="name" value="Duke"/><br/>
 <p:commandButton onclick="join();" value="Join" id="join"/>
 <p:commandButton onclick="send_message();" value="Chat" id="chat"/>
 </td>
 </tr>
 </table>
 </h:form>
 </div>
 <div id="output"></div>
 <script language="javascript" type="text/javascript" src="websocket.js"></script>
 </p:layoutUnit>
 </p:layout>
 </h:body>
 </html>
  59. var wsUri = "ws://" + document.location.host + "/ demo-chat/websocket";
 !

    ... ! var userField = document.getElementById("chat:userField");
 var chatlogField = document.getElementById("chat:chatlogField");
 var textField = document.getElementById("chat:textField");
 ! ... 
 function join() {
 username = textField.value;
 websocket.send(username + " joined");
 document.getElementById("chat:join").disabled = true;
 } Modification of websocket.js JSF generates different component id so we have to adapt the code We also choose to disable the «join» button after usage to give focus to chat button
  60. Plastic surgery result We got a better UI and user

    experience. Ok there’s still work to do, but we have the POC here ;) To test type :
 mvn clean package wildfly:run! To test the app browse to :
 http://localhost:8080/demo-chat Beautiful isn’t it ?
  61. Step 7 : A bit of structure So we get

    message and dispatch them to all people, but we don’t do anything of them It could be nice to receive structured message in JSON format and create our own object from it In this step we’re gone : Change client side js to generate JSON structure with username and message Create a Message class to contain the java version of this JSON structure Change the ChatService bean to deserialize JSON message with the new JSONP specification
  62. Websocket.js modification function send_message() {
 var msg = new Object();


    msg.user = username;
 msg.content = textField.value;
 websocket.send(JSON.stringify(msg));
 }
 
 ...
 
 function onMessage(evt) {
 console.log("onMessage : " + evt.data);
 writeToScreen("RECEIVED: " + evt.data);
 if (evt.data.indexOf("joined") != -1) {
 userField.innerHTML += evt.data.substring(0, evt.data.indexOf(" joined")) + "\n";
 } else {
 var msg = JSON.parse(evt.data)
 chatlogField.innerHTML += msg.content + " said " + msg.user + "\n";
 }
  63. New Message Class public class Message {
 
 private String

    user;
 private String content;
 
 public String getUser() {
 return user;
 }
 
 public void setUser(String user) {
 this.user = user;
 }
 
 public String getContent() {
 return content;
 }
 
 public void setContent(String content) {
 this.content = content;
 }
 }
  64. ChatService processMessage modification public void processMessage(String message) {
 System.out.println(message);
 JsonReader

    reader = Json.createReader(new StringReader(message));
 try {
 JsonObject msgObj = reader.readObject();
 Message msg = new Message();
 msg.setUser(msgObj.getString("user"));
 msg.setContent(msgObj.getString("content"));
 System.out.println("Message from " + msg.getUser() + " : " + msg.getContent());
 } catch (JsonParsingException e) {
 System.out.println("Message is not in JSON format");
 } finally {
 reader.close();
 }
 for (Session peer : peers) {
 peer.getAsyncRemote().sendText(message);
 }
 }
  65. Structure result We got now a data structure for all

    the messages. We can use it to provide other service (history, search, etc...) To test type :
 mvn clean package wildfly:run! To test the app browse to :
 http://localhost:8080/demo-chat Nothing changed... But look at the console...
  66. Step 8 : Save our messages Now we have messages

    in a nice Pojo. What about persist them to provide new services In this step we’re gone : Add a JPA configuration Turn our Pojo into a JPA entity Create a service to handle message
  67. Persistence.xml in META-INF <?xml version="1.0" encoding="UTF-8"?>
 <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence

    http://java.sun.com/xml/ns/persistence/persistence_2_1.xsd"
 version="2.1">
 
 <persistence-unit name="chatPU" transaction-type="JTA">
 <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
 <properties>
 
 <!-- Properties for Hibernate -->
 <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
 <property name="hibernate.show_sql" value="true"/>
 <property name="hibernate.format_sql" value="true"/>
 <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
 
 </properties>
 </persistence-unit>
 </persistence>
  68. @Entity
 @Vetoed
 public class Message {
 
 
 @Id
 @GeneratedValue(strategy

    = GenerationType.AUTO)
 private Long id;
 
 @Column(name = "USERNAME")
 private String user;
 private String content;
 
 ... ! 
 public Long getId() {
 return id;
 }
 
 public void setId(Long id) {
 this.id = id;
 }
 } Message.java modification We transform the class in an entity. Note the @Vetoed CDI annotation that exclude the class from being a bean We should also change the column name of user. Because user is a reserved name in SQL
  69. ChatService modification public class ChatServiceImpl implements ChatService {
 
 …

    @Inject
 EntityManager em;
 
 …
 @Override
 public void persistMessage(Message msg) {
 em.persist(msg);
 }
 
 …
 @Override
 @Transactional
 public void processMessage(String message) {
 System.out.println(message);
 JsonReader reader = Json.createReader(new StringReader(message));
 try {
 JsonObject msgObj = reader.readObject();
 Message msg = new Message();
 msg.setUser(msgObj.getString("user"));
 msg.setContent(msgObj.getString("content"));
 System.out.println("Message from " + msg.getUser() + " : " + msg.getContent());
 persistMessage(msg);
 } catch (JsonParsingException e) {
 System.out.println("Message is not in JSON format");
 } finally {
 reader.close();
 }
 for (Session peer : peers) {
 peer.getAsyncRemote().sendText(message);
 }
 }
 }
  70. Save our messages result We saved our messages to provide

    future services (history, search, etc...) To test type :
 mvn clean package wildfly:run! To test the app browse to :
 http://localhost:8080/demo-chat Nothing changed... But look at the console...
  71. Step 9 : Message in a bottle Poodle plan to

    provide an appliance to send ad to our application This appliance uses JMS to receive information asynchronously So we decide to build a POC to test Messaging feature in Java EE 7 Create a message queue and a Sender Service Modify PoodleAdWord Decorator to use the sender Bean Create a MDB to mock appliance side and listen to our messages
  72. Message queue and SenderService import javax.annotation.Resource;
 import javax.inject.Inject;
 import javax.jms.JMSContext;


    import javax.jms.JMSDestinationDefinition;
 import javax.jms.Queue;
 
 
 @JMSDestinationDefinition(name = "java:global/jms/myQueue",
 resourceAdapter = "jmsra",
 interfaceName = "javax.jms.Queue",
 destinationName = "classicQueue",
 description = "My Sync Queue")
 
 
 public class JmsSenderService {
 
 @Resource(mappedName = "java:global/jms/myQueue")
 private Queue myQueue;
 
 @Inject
 private JMSContext jmsContext;
 
 public void sendMessage(String message) {
 jmsContext.createProducer().send(myQueue, message);
 }
 }
  73. PoodleAdWord decorator modification public abstract class PoddleAddWordDecorator implements ChatService {


    
 …
 @Inject
 JmsSenderService jms;
 
 …
 
 @Override
 public void processMessage(String message) {
 String lmessage = message.toLowerCase();
 for (String s : adWords) {
 if (lmessage.indexOf(s) > -1) {
 jms.sendMessage(s);
 }
 }
 delegateService.processMessage(message);
 }
 }
  74. The Message Driven Bean import org.lab.javaee.chat.AdWord;
 
 import javax.ejb.ActivationConfigProperty;
 import

    javax.ejb.MessageDriven;
 import javax.enterprise.event.Event;
 import javax.inject.Inject;
 import javax.jms.JMSException;
 import javax.jms.Message;
 import javax.jms.MessageListener;
 
 @MessageDriven(activationConfig = {
 @ActivationConfigProperty(propertyName = "destinationLookup",
 propertyValue = "java:global/jms/myQueue"),
 @ActivationConfigProperty(propertyName = "destinationType",
 propertyValue = "javax.jms.Queue"),
 })
 public class PoodleAdListener implements MessageListener {
 
 @Inject
 @AdWord
 private Event<String> adWordEvents;
 
 @Override
 public void onMessage(Message msg) {
 try {
 System.out.println("**** Poodle MDB receiving Ad Word thru jms : " + msg.getJMSMessageID());
 adWordEvents.fire(msg.getBody(String.class));
 } catch (JMSException e) {
 throw new RuntimeException("Something nasty happened", e);
 }
 }
 }
  75. Message in a bottle result We put a messaging system

    in place with two classes and two annotations To test type :
 mvn clean package wildfly:run! To test the app browse to :
 http://localhost:8080/demo-chat Enter an ad word and check the console