10 maio 2013

Líderes de JUG de Latinoamérica, Oracle quiere ponerse en contacto


Hola Comunidad Java de América Latina! Dentro de un par de meses, voy a empezar una gira por América Latina para llevar a usted las nuevas características de la plataforma Java EE 7.

Esta gira comenzará en julio en Brasil, en el TDC - The Developers Conference, en São Paulo. Luego, después de eso, voy a empezar mi viaje a través de varios países. Pero para ayudar a terminar mi agenda, necesito tu ayuda!

Todo lo que necesitas hacer es compartir este artículo con alguien que usted conoce o en su red social. , y por supuesto, proporcionar la información que pido aquí. Esto me ayudará a ponerme en contacto con los líderes JUG locales en su país, y planear las reuniones.s.

Su ayuda es muy apreciada!

¡Gracias!

08 maio 2013

WebSocket is the new kid on the block when you think about Web Development these days. And it is expected that you want to integrate it with whatever is available in your hands. Java EE 7 is coming with cool things beyond this, for example JMS 2.0. And then you wonder: how can I send asynchronous messages to all WebSocket sessions connected to my website? Server push; no polling: for real!
The answer is quite simple: CDI. Also know as the Java EE magic glue. CDI enables a developer to build inter-communication between, apparently, distinct parts of your application. Let's go through all the steps to enable your WebSocket application to send and receive messages through JMS.

1 - Creating the WebSocket Server Endpoint

First we need to build the WebSocket server endpoint that will receive messages from clients, and to also notify clients asynchronously with a server push, with incoming JMS message payloads:
@Named
@ServerEndpoint("/websocket") public class WebSocketEndpoint implements Serializable { // this object will hold all WebSocket sessions connected to this WebSocket // server endpoint (per JVM) private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>()); 
Now you must also add three key methods to this WebSocket: 
@OnOpen public void onOpen(final Session session) { sessions.add(session); } @OnMessage public void onMessage(final String message, final Session client) { ... } @OnClose public void onClose(final Session session) { sessions.remove(session); }
Notice that on onOpen and onClose, we manage all user sessions connected to this endpoint. We will see later howsessions will be used inside onMessage. For now, let's create a SessionBean to send messages to a JMS Queue.

2 - Creating the SessionBean to send JMS messages

As we cannot create JMS objects directly inside the WebSocket endpoint due to restrictions defined both in the WebSocket and JMS specifications, we must create a SessionBean so we can forward incoming WebSocket messages to a JMS queue. Create a class named QueueSenderSessionBean as it follows:
@Named
@LocalBean
@Stateless public class QueueSenderSessionBean { ... }
This SessionBean is @Stateless, as well part of the CDI context (@Named), and as it does not have an interface, it is a @LocalBean. Now, let's add a business method to it, called sendMessage:
public void sendMessage(String message) { ... } 
Quite straight-forward, isn't? One of the great things about JMS 2.0 is its simplicity to send messages to a destination. To do that, we need to inject two objects:
@Resource(mappedName = "jms/myQueue")
private Queue myQueue;
@Inject private JMSContext jmsContext; 
JMSContext is one of the new classes added to JMS API, and is documented here. It encapsulates a Connection and aSession, and makes use of a default ConnectionFactory, now a required resource to be provided by all Java EE 7 certified application servers. Next, all you need is to add the logic to the previously added method:
jmsContext.createProducer().send(myQueue, message);
And you are done with the SessionBean. Next we will add some glue between the SessionBean and the WebSocket to send messages to the JMS destination.

3 - Forwarding an incoming WebSocket message to a JMS destination

This is quite simple. All you need to do is to inject the SessionBean into your WebSocket, and call thesendMessage method inside onMessage of your endpoint. Let's start with the injection first, but due to a bug, we must do constructor injection. Open your WebSocket server endpoint class WebSocketEndpoint, and add the following field:
private QueueSenderSessionBean senderBean;
Now add the following constructor to it:
  @Inject  public WebSocketEndpoint(QueueSenderSessionBean sb) {     this.senderBean = sb;  }
Next step is to simply call the method inside onMessage:
senderBean.sendMessage(message);
We have finished the first part of this application. With this code, you are now able to send a message from a WebSocket client, to a JMS destination. Next, we will do the opposite. Let's push some data from a JMS queue to all WebSocket clients!

4 - Listening to a JMS Destination with a MessageDriven Bean

Funny fact: some developers have not realized yet, but the MessageDriven annotation is not specified by the JMS API. Instead, it is part of the EJB specification, and it can be used not only for JMS, but for many other things. David Blevins from the awesome Apache TomEE realized that, and proposed a small change to the EJB spec, where resource adapters required connectors to provide a messagelistener-type. His proposal though, suggests that you should be able to use an MDB to listen to different things, and the listener interface should be optional. One example is to listen to Telnet commands. Pretty awesome! But let's focus on our use case here, which is specific to JMS.
Now that we can publish messages into a Queue destination from a WebSocket client, we must process them to later forward to somewhere else. Let's start coding our JMS MDB (remember, not all MDBs are implicitly JMS-related!), implementing the MessageListener interface, required by JMS ResourceAdapter connectors:
  @Named  @MessageDriven(mappedName = "jms/myQueue")  public class WebSocketMDB implements MessageListener 
@Override
public void onMessage(Message msg) { ... }
  }
This is the basic code to any JMS MDB. Now let's do some magic... 

5 - Firing CDI events with the JMS Message payload

Remember when I told that we cannot listen to JMS destinations directly from the WebSocket server endpoint due to specification restrictions? Well. We can actually, but using a different technique. If you haven't heard about CDI Events, you should read about it before continuing this tutorial. Done? Ok, let's go. First thing we need is an Event qualifier. Create the WSJMSMessage annotation inside your project:
  @Qualifier  @Retention(RetentionPolicy.RUNTIME)  @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})  public @interface WSJMSMessage {}
 With a defined qualifier, CDI will be able to connect the firing event with the observer object. Go back to the WebSocketMDB and add an Event dispatcher to it, with the qualifier we created above:
    @Inject
    @WSJMSMessage     Event<Message> jmsEvent; 
 Now let's add the logic to the onMessage method:
jmsEvent.fire(msg);

6 - Listening to CDI events within the WebSocket server endpoint

This is the last server-side part of this article, then next you will see how to code Javascript on the client-side. Let's listen to CDI events fired by the MDB, with the Message payload. Open again your WebSocketEndpoint class, and add the following method to it:
public void onJMSMessage(@Observes @WSJMSMessage Message msg) {
        try {
            for (Session s : sessions) {
                s.getBasicRemote().sendText("message from JMS: " + msg.getBody(String.class));
            }
        } catch (IOException | JMSException ex) {
            Logger.getLogger(WebSocketEndpoint.class.getName()).log(Level.SEVERE, null, ex);
        }     } 
Observe the @Observes and the qualifier @WSJMSMessage we defined previously. This is what tells CDI to listen to the fired events by the MDB.

7 - Client-side Javascript to connect with the WebSocket server endpoint

This has been floating around the Internet for a while as it is not Java nor Java EE specific, but anyway it is basically this:
// note the final path is the same defined inside WebSocketEndpoint class at @ServerEndpoint websocketSession = new WebSocket('ws://' + document.location.host + '/your-app-context-root/websocket');
Here is the final Javascript used by this example, as well the HTML interface.

Conclusion

I hope you have found this article useful to begin your development with Java EE 7, and what are the possibilities of integrating CDI, WebSockets, JMS, and EJB. These are the main points about this article:
  • ability to asynchronously communicate with WebSocket clients (although you can also usesession.getAsyncRemote() to send messages asynchronously)
  • ability to do a server push to WebSocket clients at any point in your application
  • ability to scale server-pushed communication to WebSocket client sessions across a cluster using JMS Topics
    This is perhaps one of the most interesting thing about this setup. If you use a Topic instead of a Queue, you will be able to push data to all WebSocket sessions connected to your application across a cluster. There's a know limit of roughly 64k client sessions per web server, and in this example we use a static synchronized Set to hold a reference to them. Imagine now a cluster. We change this to a Topic clustered subscriber, and we are able to scale up server pushed data :-)
The source code of this project is available at my GitHub repository javaee7-jms-websocket-example. I hope you liked the article!

What's new in Java EE 7 at JUDCon Brazil 2013

This weekend I talked about Java EE 7 at JUDCon Brazil 2013, the session "What's new in Java EE 7? From HTML5 to JMS 2.0". What a great honour to be at JBoss Users and Developers Conference to share with attendees the great work that Oracle, Red Hat, and many others are doing for this platform. Room was packed, with people standing, and so much interest to hear all the cool stuff to come, such as WebSockets, JMS, JAX-RS, JSF and even more. To add some value to this talk, and as I'm a fan of Game of Thrones, I thought that a few images would fit right at this talk :-)
            
Slides here!

Contato

Mobile: +55 21 7672-7099
Email:bruno.borges(at)gmail.com

LinkedIn: www.linkedin.com/in/brunocborges
Jawsys Consultoria
Florianópolis, SC Brasil

Comprei e Não Vou
Rio de Janeiro, RJ Brasil