Quantcast
Viewing latest article 1
Browse Latest Browse All 2

Java EE 7 Web Sockets with AngularJS

The objective of this post is to show how I set up a web project with Maven and Eclipse Kepler with Java EE 7 Web Sockets running on the Java EE 7 reference implementation, Glassfish 4.  All the code is available in javaee7-websockets-example on GitHub.


TL;DR summary

For those in a rush and know HTML and Angular already, here’s the quick summary on how to get this working.

  • Download and install the latest version of Glassfish 4.0, Java 7 SE (not EE) and Maven.
  • Get the current Kepler release candidate for Eclipse IDE for Java Developers. Get the Glassfish Tools adapter.
  • Create a WAR pom.xml file and make sure it has the following defined:
    <build>
      <plugins>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.1</version>
          <configuration>
            <source>1.7</source>
            <target>1.7</target>
          </configuration>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>2.3</version>
        </plugin>
      </plugins>
    </build>
    <dependencies>
      <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
      </dependency>
    </dependencies>
  • Create a document element only web.xml file
    &lt;web-app xmlns=<a href="http://xmlns.jcp.org/xml/ns/javaee">http://xmlns.jcp.org/xml/ns/javaee</a> 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee <a href="http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd&quot;">http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    </a>  version="3.1"&gt;
    &lt;/web-app&gt;
  • Define the endpoint.  See how simple it is?
    @ServerEndpoint("/echo")
    public class EchoSocket {
      @OnMessage
      public String echo(String message, Session client) {
        return message + " (from your server)";
      }
    }
  • Provide the web socket using an AngularJS factory.
    .factory('echoSocket', function() {
    var loc = window.location;
    var wsUri;
    if (loc.protocol === 'https:') {
      wsUri = 'wss:';
    } else {
      wsUri = 'ws:';
    }
    wsUri += "//" + loc.host + loc.pathname.substring(0, loc.pathname.lastIndexOf('/')) + '/echo';
    return new WebSocket(wsUri);
    })
  • Send and receive messages via the controller
    // handle received messages
    echoSocket.onmessage = function(event) {
      $scope.interactions.push({
        direction : "RECEIVED",
        message : event.data
      });
      $scope.$apply();
    };
    
    // send a message
    $scope.sendMessage = function() {
      $scope.interactions.push({
        direction : "SENT",
        message : $scope.message
      });
      echoSocket.send($scope.message);
      $scope.message = "";
    };
  • Run on server

Required software

  • Download and install the latest version of Java SE 7.  Side note, don’t ever bother with the Java EE packages from Oracle, they generally cause more confusion than necessary.
  • Download the current release of Glassfish 4.0.  I installed it in c:/glassfish4.   Windows 8 still has the maximum path length limitation and I want to avoid that issue during run-time if possible, it’s not like any sane Java EE deployment would be on Windows anyway.  Don’t forget to do asadmin start-domain as per the Glassfish instructions.
  • Download the current Kepler release candidate for Eclipse IDE for Java Developers.
  • Unzip it to a new folder. In my case I put it in c:/opt/kepler.
  • Run eclipse.
  • Go to the Servers view (Ctrl-3 “Servers”)
  • Click on No servers are available. Click this link to create a new server…
  • Click on Download additional server adapters
  • Locate Glassfish Tools and follow the rest of the dialog.
  • Restart Eclipse
  • Go to the Servers view (Ctrl-3 “Servers”)
  • Click on No servers are available. Click this link to create a new server…
  • Choose Glassfish 4.0 and specify the Glassfish directory as c:\glassfish4\glassfish and finish the rest of the dialogs.

Project setup

FYI, I have put the completed project files in GitHub.

In my case, I have a javaee-project POM that is used by my organisation as a baseline for Java EE projects. However, as of writing the Maven Java EE plugins are not updated for Java EE 7 and Eclipse Kepler is not out yet so I only have a SNAPSHOT release for now. As of now only the maven-war-plugin would work as it does not have any tie-ins with the Java EE levels unlike the EAR plugin, so this just uses the WAR packaging.

To set up a Java EE 7 web app in Maven, your POM file has to have the following:

  • maven-compiler-plugin set to 1.7
  • maven-war-plugin set to at least version 2.8
  • A dependency to Java EE 7 API
    &lt;dependency&gt;
        &lt;groupId&gt;javax&lt;/groupId&gt;
        &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;
        &lt;version&gt;7.0&lt;/version&gt;
        &lt;scope&gt;provided&lt;/scope&gt;
      &lt;/dependency&gt;

In addition, a src/main/webapps/WEB-INF/web.xml containing the web-app element needs to be provided.

&lt;web-app xmlns=<a href="http://xmlns.jcp.org/xml/ns/javaee">http://xmlns.jcp.org/xml/ns/javaee</a> 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee <a href="http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd&quot;">http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
</a>  version="3.1"&gt;
&lt;/web-app&gt;

As this example is going to use Angular and Bootstrap CSS, the following dependencies are also required and pulled from WebJars to take advantage of dependency management.

&lt;dependency&gt;
  &lt;groupId&gt;org.webjars&lt;/groupId&gt;
  &lt;artifactId&gt;angularjs&lt;/artifactId&gt;
  &lt;version&gt;1.1.5-1&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
  &lt;groupId&gt;org.webjars&lt;/groupId&gt;
  &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;
  &lt;version&gt;2.3.2&lt;/version&gt;
&lt;/dependency&gt;

See pom.xml in Github for the complete source

Creating a web socket server

As of Java EE 7, creating a web socket can be done in less than 10 lines of code. Much like web services and REST services in previous versions. No need for complex setup and dependencies like in CometD, CXF or Spring-WS.

The following is the code minus the comments and imports for src/main/java/.../EchoSocket.java:

@ServerEndpoint("/echo")
public class EchoSocket {
  @OnMessage
  public String echo(String message, Session client) {
    return message + " (from your server)";
  }
}

The echo-client module

In the example, it is a bit more complicated because I used my preferred Angular app organisation rather than keeping it to just a few HTML and JavaScript files. The reason being, I don’t want to propagate relatively bad coding practices any more than I have to. However, most of the logic is actually found in the echo-client module.

The src/main/webapp/.../echo-client.js module consists of one directive, echoClient that is responsible handle the UI interactions and echoSocket factory that provides the web socket connection.

The template file src/main/webapp/.../template.html consists of a message sending block:

Message: &lt;input data-ng-model="message" /&gt;
&lt;button data-ng-click="sendMessage()"
  class="btn"&gt;Send message&lt;/button&gt;

A message log block

&lt;tr data-ng-repeat="interaction in interactions"&gt;
  &lt;td&gt;{{interaction.direction}}&lt;/td&gt;
  &lt;td&gt;{{interaction.message}}&lt;/td&gt;
&lt;/tr&gt;

A singleton web socket connection is provided using factory() that calculates the URL for the web socket connection using  the protocol ws: or wss: and appends the service endpoint.  In the example I had provided, I just put it in the same module as the directive, in larger applications it would likely be put in its own module that is used by different modules.

.factory('echoSocket', function() {
var loc = window.location;
var wsUri;
if (loc.protocol === "https:") {
  wsUri = "wss:";
} else {
  wsUri = "ws:";
}
wsUri += "//" + loc.host + loc.pathname.substring(0, loc.pathname.lastIndexOf('/')) + '/echo';
return new WebSocket(wsUri);
})

On the controller, a message receiver callback is registered using the onmessage callback

echoSocket.onmessage = function(event) {
  $scope.interactions.push({
    direction : "RECEIVED",
    message : event.data
  });
  $scope.$apply();
};

Message sending, which is triggered by the ng-click is done using the following function in the controller:

$scope.sendMessage = function() {
  $scope.interactions.push({
    direction : "SENT",
    message : $scope.message
  });
  echosocket.send($scope.message);
  $scope.message = "";
};

Once all of the files are set up, it should just now be a matter of Run on Server and view in the web browser to see it in action.

What about others?

There are other IDEs out there aside from Eclipse, though this is post is talking about Eclipse Kepler, there is no reason why a similar approach cannot be done on IntelliJ since the Maven portion can be done on the command line at any time.

AngularJS was used because that is the preferred Web Application UI framework for my organisation.  However, the web sockets API does not depend on any framework.

Also remember that web sockets are pretty new and you don’t want to get burned by incompatible clients.  As far as I can tell, Modernizr or web-socket-js will not work with Internet Explorer 8.  However, this does work with Internet Explorer 10.  For those clients you’re better off using CometD.


Viewing latest article 1
Browse Latest Browse All 2

Trending Articles