Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
The Magnificent java EE 7 in Wildfly-O-Rama
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
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. 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. 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. 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. 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. 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. 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. 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
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. 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)
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. 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
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. 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
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. 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. 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. 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
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. 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. 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
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. 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. 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. 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. 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
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. 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. 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. 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
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. 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
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. New content for index.html
<html>
<head>
<meta http-equiv="Refresh" content="0; URL=index.jsf">
</head>
</html>
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. 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
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. 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. 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. 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. 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
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. 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. 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. 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
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