Java EE 7 WebSocket Server-Side Programing with Twitter4J

2012年12月22日 at 11:42 午後 1件のコメント

In this entry, I will explain the new feature of Java EE 7. In Java EE 7, Java API for WebSocket (JSR-356) will be included.

I explained these technology at Japanese Java conference as follows. At that time, I showed the Twitter Timeline demo by using the WebSocket. So I will explain following how to create WebSocket application as standard technology of Java.


Now Java EE expert group is developing and evaluating the specification of JSR-356 Java API for WebSocket. So it may be possible to change the coding style when the Java EE 7 had released officially release at next year (We are planning to release the Java EE 7 at 2013 Spring). So please note this point ?

This program was created for GlassFish 4.0 b58 environment at November. You can download the promoted build of GlassFish v4.0 from following site. So please download it before the coding ?

http://dlc.sun.com.edgesuite.net/glassfish/4.0/promoted/

Latest version of the GlassFish was “glassfish-4.0-b67.zip”. (2012/12/20)

It seems that already the API had changed during this one month. Arun Gupta already mentioned about it on following entry.


WebSocket Samples in GlassFish 4 build 66 – javax.websocket.* package: TOTD #190

So if you get the latest version of the GlassFish, please refer to the above entry too?

And you need to get the “Twitter4J” libraries from following site before coding. Twitter4J. Twitter4J is very very useful libraries to create Twitter service by Java. Twitter4J is created by Japanese guyes whose name is Yusuke Yamamoto-san.

Actually I got two libraries as follows.

* twitter4j-core-2.2.6.jar
* twitter4j-stream-2.2.6.jar

Perhaps as you may know, WebSocket is able to communicate by Full duplex and bi-directional between Client and Server. And it is used the upgrade protocol of HTTP protocol as WebSocket protocol.

Once WebSocket connection had established, it is possible to write the program depends on the WebSocket lifecycle.

* Open (@WebSocketOpen)
* Receiving the Message (@WebSocketMessage )
* Error (@WebSocketError)
* Close (@WebSocketClose)

I will show the sample code of getting the Twitter Timeline as follows. At first, you need to specify the @WebSocketEndpoint annotation to the Java class. And you need to specify the context root in the argument of the annotation. For example, if you specify following,
@WebSocketEndpoint(value = “/twitter”) // since build 61
the client can connect to the server by using following
“ws://WEBSOCKET-SERVER/APP_NAME/twitter”.

And I implemented two method on the class as initOpen, closeWebSocket. And also I specified two annotation as @WebSocketOpen, @WebSocketClose.

* @WebSocketOpen initOpen : if the client access to the server, it inserted the Session to the Set(peers). Session has the information of RemoteEndpoint(client).
@ @WebSocketClose closeWebSocket : if the connection had cut, it delete the Session from the Set(peers). Session has the information of RemoteEndpoint(client).

package jp.co.oracle;

import java.io.IOException;
import javax.net.websocket.Session;
import javax.net.websocket.annotations.WebSocketClose;
import javax.net.websocket.annotations.WebSocketEndpoint;
import javax.net.websocket.annotations.WebSocketMessage;
import javax.net.websocket.annotations.WebSocketOpen;

@WebSocketEndpoint(path = "/twitter") // build 58
// @WebSocketEndpoint(value = "/twitter") build 61
public class TwitterWebSocket {

    @WebSocketOpen
    public void initOpen(Session session) {
        TwitterClientSingleton.peers.add(session);
    }

    @WebSocketClose
    public void closeWebSocket(Session session) {
        TwitterClientSingleton.peers.remove(session);
    }
}

Next, I created Twitter monitoring program by using Singleton EJB with Twitter4j lib. In this program, if the EJB received the new message from Twitter, the EJB automatically send the message to all of connected WebSocket Client. In the EJB, I had used the Streaming API of Twitter4J. And also I specified two annotation to the class as @Startup and @Singleton. Thus, the EJB will be automatically initialized and started the service by EJB Container when the application is started.
Once EJB had loaded, initTwitterStream() method will be called by container because @PostConstruct annotation is specified to the method. In the method, it initialized Twitter4J API and it is using the Twitter Stream API. And in this example, I specify the search keyword as “java”.

In the Twitter4J, StatusAdapter is provided and onStatus() method can receive the message when the above filter had matched. So I wrote the code of publishing the message to all of connected RemoteEndpoint in this method. Of course if you would like to write JSON, you can do it.

(* NOTE: If you would like to receive the message from client, you can write the method with @WebSocketMessage annotation.)

package jp.co.oracle;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Future;
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.net.websocket.SendHandler;
import javax.net.websocket.SendResult;
import javax.net.websocket.Session;
import twitter4j.FilterQuery;
import twitter4j.Status;
import twitter4j.StatusAdapter;
import twitter4j.TwitterStream;
import twitter4j.TwitterStreamFactory;
import twitter4j.User;

@Startup
@Singleton
public class TwitterClientSingleton extends StatusAdapter {

    private static TwitterStream twStream = null;
    public static Set<Session> peers = null; // Session の Set (The information of the RemodeEndpoint is includedn in Session object)

    static {
        peers = Collections.synchronizedSet(new HashSet());
    }

    @PostConstruct
    public void initTwitterStream() {
        //Initialize the Twitter Stream of Twitter4J
        twStream = TwitterStreamFactory.getSingleton();
        FilterQuery filter = new FilterQuery();
        filter.track(new String[]{"java"});
        twStream.addListener(this);
        twStream.filter(filter);
    }

    @Override
    public void onStatus(Status status) {
        // when the filter had matched this code will be called
        User user = status.getUser();
        if (status.getUser().getLang().equals("ja")) {
            String resStr = "@" + user.getScreenName() + " : " + status.getText();
            try {
                // I send the message to all of connected client as sequencial
                for (Session peer : peers) {
                    peer.getRemote().sendString(resStr);
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }
}

Finally, I will write the View. This View is very very simple. So you can write simply HTML or JSF or other. However in this example, I will write as JSF faceless. In the program, if this client receive the Twitter message from Server, onMessage() of JavaScript is called and show the message on the first line of the HTML Table.

<?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">
    <h:head>
        <title>Twitter TimeLine Sample</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>Twitter TimeLine Sample</title>
        <style type="text/css">
            table,td,th { 
                width: 700px;
                border-collapse: collapse; 
                border: 1px black solid; 
            }
        </style>

        <script language="javascript" type="text/javascript">
            var wsUri = "ws://localhost:8080/TwitterTimeLine/twitter";
            var websocket = new WebSocket(wsUri);
            websocket.onopen = function(evt) { onOpen(evt) };
            websocket.onmessage = function(evt) { onMessage(evt) };
            websocket.onerror = function(evt) { onError(evt) };

            var  numberOfMessage;

            function init() {
                numberOfMessage = 0;
            }
            function onOpen(evt) {
                ;
            }

            function onMessage(evt) {                                        
                writeToScreen(evt.data);                    
                numberOfMessage++;
            }

            function onError(evt) {
                writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
            }
            

            function writeToScreen(messages) {
                var table = document.getElementById("TBL"); 
                var row = table.insertRow(0);  
                var cell1 = row.insertCell(0); 
                
                var textNode = document.createTextNode(messages);

                var z = numberOfMessage%2;
                if(z==1){
                    cell1.style.backgroundColor="#ADD8E6" ;
                }
                cell1.appendChild(textNode);
            }

            window.addEventListener("load", init, false);
        </script>
    </h:head>
    <h:body>
        <h2>Twitter Time Line <BR/>WebSocket Sample Application!!</h2>
        <TABLE BORDER="1" ID="TBL">            
        </TABLE>
    </h:body>
</html>

In order to run the Application, You need to get the consumer key and access Token from Twitter. http://twitter.com/oauth_clients/new After created the consumer key and access token, you need to write the following properties on twitter4j.properties file. And please placed the properties file to WEB-INF/classes ?

# To change this template, choose Tools | Templates
# and open the template in the editor.
debug=false
oauth.consumerKey=*********************
oauth.consumerSecret=****************************************
oauth.accessToken=********-****************************************
oauth.accessTokenSecret=******

And also you need the following libraries to compile and run.

* Twitter4J: twitter4j-core-2.2.6.jar
* Twitter4J: twitter4j-stream-2.2.6.jar
* WebSocket: tyrus-servlet.jar (GlassFish-INSTALL/glassfish/modules)
* EJB : (GlassFish-INSTALL/glassfish/modules)
* CDI : (GlassFish-INSTALL/glassfish/modules)

I will show the directory structure of NetBeans project as follows.

Finally :
Perhaps you can understand that the Java API for WebSocket API is very very easy to use. And also if you use the Singleton EJB , it is very useful to monitor the backend service.
For example, please consider the DataBase monitoring instead of Twitter. If client request the DB update information to the Application Server, the Application Server will send the query to DB server for every individual request until now. However if you create the DB monitoring application like this, the load of DB may be extremery decrease.

Following is the demo video of this sample application.

WebSocket is the key technology included in the Java EE 7. And it is very easy to implement. If you are interested in the WebSocket on Java Platfor, please try to use the NetBeans and GlassFish v4.

広告

Entry filed under: 未分類.

Concurrency Update (jsr166e)のご紹介 Java EE 7 WebSocket Client Sample Application with JavaFX

1件のコメント


Java Champion & Evangelist

Translate

ご注意

このエントリは個人の見解であり、所属する会社の公式見解ではありません

カレンダー

2012年12月
 12
3456789
10111213141516
17181920212223
24252627282930
31  

カテゴリー

clustermap

ブログ統計情報

  • 1,267,388 hits

RSSフィード

アーカイブ


%d人のブロガーが「いいね」をつけました。