The Magnificent java EE 7 in Wildfly-O-Rama

2,853 views

Published on

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

Published in: Technology, Education
2 Comments
3 Likes
Statistics
Notes
No Downloads
Views
Total views
2,853
On SlideShare
0
From Embeds
0
Number of Embeds
48
Actions
Shares
0
Downloads
37
Comments
2
Likes
3
Embeds 0
No embeds

No notes for slide

The Magnificent java EE 7 in Wildfly-O-Rama

  1. 1. The Magnificent Java EE 7 in Wildfly-O-Rama Antoine Sabot-Durand Java EE Expert Senior Software Developer @ Red Hat @antoine_sd
  2. 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. 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. 4. Java EE Introduction
  5. 5. Java EE History 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
  6. 6. Java EE History Java Professional Edition Mai 1998 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
  7. 7. Java EE History Java Professional Edition Mai 1998 1998 1999 J2EE 1.2 12/12/1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
  8. 8. Java EE History Java Professional Edition Mai 1998 1998 1999 J2EE 1.2 12/12/1999 2000 J2EE 1.3 09/24/2001 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
  9. 9. Java EE History Java Professional Edition Mai 1998 1998 1999 J2EE 1.2 12/12/1999 2000 J2EE 1.3 09/24/2001 2001 2002 J2EE 1.4 11/11/2003 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
  10. 10. Java EE History Java Professional Edition Mai 1998 1998 1999 J2EE 1.2 12/12/1999 2000 J2EE 1.3 09/24/2001 2001 2002 J2EE 1.4 11/11/2003 2003 Java EE 5 05/11/2006 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
  11. 11. Java EE History Java Professional Edition Mai 1998 1998 1999 J2EE 1.2 12/12/1999 2000 J2EE 1.3 09/24/2001 2001 2002 J2EE 1.4 11/11/2003 2003 Java EE 5 05/11/2006 2004 2005 2006 2007 Java EE 6 12/10/2009 2008 2009 2010 2011 2012 2013
  12. 12. Java EE History Java Professional Edition Mai 1998 1998 1999 J2EE 1.2 12/12/1999 2000 J2EE 1.3 09/24/2001 2001 2002 J2EE 1.4 11/11/2003 2003 Java EE 5 05/11/2006 2004 2005 2006 2007 Java EE 6 12/10/2009 2008 2009 Java EE 7 06/22/2013 2010 2011 2012 2013
  13. 13. Java EE 7 Main Features 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
  14. 14. Java EE 7 JSR CDI Extensions JSF 2.2,
 JSP 2.3,
 EL 3.0 Web Fragments JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0 CDI 1.1 Interceptors
 1.2, JTA 1.2 Common Annotations 1.1 EJB 3.2 Managed Beans 1.0 JPA 2.1 JMS 2.0 Concurrency 1.0 JCA 1.7 Batch 1.0 Bean Validation 1.1 Servlet 3.1
  15. 15. Java EE 7 JSR CDI Extensions JSF 2.2,
 JSP 2.3,
 EL 3.0 Web Fragments JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0 CDI 1.1 Interceptors
 1.2, JTA 1.2 Common Annotations 1.1 EJB 3.2 Managed Beans 1.0 JPA 2.1 JMS 2.0 Concurrency 1.0 JCA 1.7 Batch 1.0 Bean Validation 1.1 Servlet 3.1
  16. 16. Java EE 7 JSR CDI Extensions JSF 2.2,
 JSP 2.3,
 EL 3.0 Web Fragments JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0 CDI 1.1 Interceptors
 1.2, JTA 1.2 Common Annotations 1.1 EJB 3.2 Managed Beans 1.0 JPA 2.1 JMS 2.0 Concurrency 1.0 JCA 1.7 Batch 1.0 Bean Validation 1.1 Servlet 3.1
  17. 17. Java EE 7 JSR CDI Extensions JSF 2.2,
 JSP 2.3,
 EL 3.0 Web Fragments JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0 CDI 1.1 Interceptors
 1.2, JTA 1.2 Common Annotations 1.1 EJB 3.2 Managed Beans 1.0 JPA 2.1 JMS 2.0 Concurrency 1.0 JCA 1.7 Batch 1.0 Bean Validation 1.1 Servlet 3.1
  18. 18. Java EE 7 JSR CDI Extensions JSF 2.2,
 JSP 2.3,
 EL 3.0 Web Fragments JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0 CDI 1.1 Interceptors
 1.2, JTA 1.2 Common Annotations 1.1 EJB 3.2 Managed Beans 1.0 JPA 2.1 JMS 2.0 Concurrency 1.0 JCA 1.7 Batch 1.0 Bean Validation 1.1 Servlet 3.1
  19. 19. Java EE 7 JSR CDI Extensions JSF 2.2,
 JSP 2.3,
 EL 3.0 Web Fragments JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0 CDI 1.1 Interceptors
 1.2, JTA 1.2 Common Annotations 1.1 EJB 3.2 Managed Beans 1.0 JPA 2.1 JMS 2.0 Concurrency 1.0 JCA 1.7 Batch 1.0 Bean Validation 1.1 Servlet 3.1
  20. 20. Java EE 7 JSR CDI Extensions JSF 2.2,
 JSP 2.3,
 EL 3.0 Web Fragments JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0 CDI 1.1 Interceptors
 1.2, JTA 1.2 Common Annotations 1.1 EJB 3.2 Managed Beans 1.0 JPA 2.1 JMS 2.0 Concurrency 1.0 JCA 1.7 Batch 1.0 Bean Validation 1.1 Servlet 3.1
  21. 21. Java EE 7 JSR CDI Extensions JSF 2.2,
 JSP 2.3,
 EL 3.0 Web Fragments JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0 CDI 1.1 Interceptors
 1.2, JTA 1.2 Common Annotations 1.1 EJB 3.2 Managed Beans 1.0 JPA 2.1 JMS 2.0 Concurrency 1.0 JCA 1.7 Batch 1.0 Bean Validation 1.1 Servlet 3.1
  22. 22. Java EE 7 JSR CDI Extensions JSF 2.2,
 JSP 2.3,
 EL 3.0 Web Fragments JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0 CDI 1.1 Interceptors
 1.2, JTA 1.2 Common Annotations 1.1 EJB 3.2 Managed Beans 1.0 JPA 2.1 JMS 2.0 Concurrency 1.0 JCA 1.7 Batch 1.0 Bean Validation 1.1 Servlet 3.1
  23. 23. Java EE 7 JSR CDI Extensions JSF 2.2,
 JSP 2.3,
 EL 3.0 Web Fragments JAX-RS 2.0, JAX-WS 2.2 JSON 1.0 WebSocket 1.0 CDI 1.1 Interceptors
 1.2, JTA 1.2 Common Annotations 1.1 EJB 3.2 Managed Beans 1.0 JPA 2.1 JMS 2.0 Concurrency 1.0 JCA 1.7 Batch 1.0 Bean Validation 1.1 Servlet 3.1
  24. 24. JBoss WildFly 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
  25. 25. WildFly Roadmap 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)
  26. 26. Download WildFly today http://wildfly.org
  27. 27. Let’s get some action !
  28. 28. 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...
  29. 29. 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
  30. 30. Git Start git clone git@github.com:antoinesd/magnificent-java-ee7.git! ! git checkout beginning
  31. 31. 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>

  32. 32. 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>
  33. 33. 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>
  34. 34. websocket.js var var var var 
 wsUri = "ws://" + document.location.host + "/demo-chat/websocket";
 websocket = new WebSocket(wsUri);
 username;
 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 ! function ! send_message() {websocket.send(username + ": " + textField.value);}
 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>";}
  35. 35. ChatEndPoint.java import import import import ! javax.websocket.*;
 javax.websocket.server.ServerEndpoint;
 java.io.IOException;
 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);
 }
 }
 }

  36. 36. 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
  37. 37. 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
  38. 38. Git Shortcut git checkout step_1
  39. 39. Activate CDI To activate CDI you only have to create an empty file named beans.xml in folder
 src/main/webapp/WEB-INF beans.xml !
  40. 40. 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);
 }
 }
 }
  41. 41. 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);
 }
 }
  42. 42. 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
  43. 43. Git Shortcut git checkout step_2
  44. 44. 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);
 }
 } }

  45. 45. Bean with Observer import javax.enterprise.event.Observes;
 
 public class MessageObserver {
 
 public void observesWorldMessages(@Observes String msg) {
 System.out.println("Keyword was trapped : " + msg);
 }
 }
  46. 46. 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
  47. 47. 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
  48. 48. Git Shortcut git checkout step_3
  49. 49. 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 {
 ! … ! }
  50. 50. 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);
 }
 }
  51. 51. 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);
 }
 }
 }
  52. 52. 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
  53. 53. 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
  54. 54. Git Shortcut git checkout step_4
  55. 55. 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 {
 }
  56. 56. 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 {
 }
  57. 57. 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);
 }
 }
  58. 58. 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);
 }
 }
  59. 59. 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
  60. 60. 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
  61. 61. Git Shortcut git checkout step_5
  62. 62. Create the Interceptor Binding 
 import import import import import javax.interceptor.InterceptorBinding;
 java.lang.annotation.ElementType;
 java.lang.annotation.Retention;
 java.lang.annotation.RetentionPolicy;
 java.lang.annotation.Target;
 @InterceptorBinding
 @Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 public @interface Log {
 }
  63. 63. 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;
 
 }
 }
  64. 64. Using the Interceptor @ApplicationScoped
 @Log
 public class ChatServiceImpl implements ChatService {
 … }
  65. 65. 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
  66. 66. 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
  67. 67. Git Shortcut git checkout step_6
  68. 68. 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>
  69. 69. 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>
  70. 70. Modification of websocket.js 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;
 } 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
  71. 71. New content for index.html <html>
 <head>
 <meta http-equiv="Refresh" content="0; URL=index.jsf">
 </head>
 </html>
  72. 72. 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 ?
  73. 73. 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
  74. 74. Git Shortcut git checkout step_7
  75. 75. 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";
 }
  76. 76. 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;
 }
 }
  77. 77. 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);
 }
 }
  78. 78. 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...
  79. 79. 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
  80. 80. Git Shortcut git checkout step_8
  81. 81. 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>
  82. 82. ConfigPersistence.java 
 
 public class ConfigPersistence {
 
 } @PersistenceContext
 @Produces
 private EntityManager em;

  83. 83. Message.java modification @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;
 }
 } 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
  84. 84. 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);
 }
 }
 }
  85. 85. 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...
  86. 86. 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
  87. 87. Git Shortcut git checkout step_9
  88. 88. Message queue and SenderService import import import import import 
 javax.annotation.Resource;
 javax.inject.Inject;
 javax.jms.JMSContext;
 javax.jms.JMSDestinationDefinition;
 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);
 }
 }
  89. 89. 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);
 }
 }
  90. 90. The Message Driven Bean import org.lab.javaee.chat.AdWord;
 
 import import import import import import import 
 javax.ejb.ActivationConfigProperty;
 javax.ejb.MessageDriven;
 javax.enterprise.event.Event;
 javax.inject.Inject;
 javax.jms.JMSException;
 javax.jms.Message;
 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);
 }
 }

  91. 91. 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
  92. 92. Questions

×