Thursday Mar 19, 2015

WebSocket Client API – Java 8

Since Java 8 was released, lots of new or reworked APIs emerged, simply because Java 8 is really evolutionary step in Java language specification and it is definitely worth to update the APIs to enable newly added features.

Unfortunately, Java EE APIs have different release cycle and we’d need to wait a little bit for next version, but I was able to add at least something to Tyrus, which is reference implementation of JSR 356 – WebSocket API for Java. There are some other changes which could be made, but most of them require changes in the API itself, which we cannot do at the moment, so I focused on other features which do enhance the experience. You can view this as the “first” attempt to bring some Java 8 API features into the existing programming model.

The area covered in this post is Client API – mainly because this change can be used easily with any WebSocket API implementation; it is built on top of existing API. If I would be thorough, I’d apply this to deployment of the programmatic endpoints on the server side as well, but that would be far more work and since the server side usually uses annotated endpoints instead of programmatic ones, I believe this should be sufficient to evaluate the proposal and provide any feedback you might have.

The client API was originally crafted as something, which should be similar to the JavaScript counterpart, but the language differences at that time diminished that effort to basically just naming and few other details (and the alignment with server side API had higher priority). Anyway, I believe it is the time, when we should reconsider Client API (and programmatic model in general).

If you look at javascript API, it’s basically just one object, to which you can set handlers for some events:

1
2
3
4
5
6
window.websocket = new WebSocket(window.wsUrl("/sample-btc-xchange/market"));
var websocket = window.websocket;
websocket.onopen = function () { /* ... */ };
websocket.onmessage = function (evt) {/* ... */ };
websocket.onclose = function () { /* ... */ };
websocket.onerror = function () { * ... */ };

The current Java version of this would be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
client.connectToServer(new Endpoint() {
@Override
public void onOpen(Session session, EndpointConfig EndpointConfig) {
try {
session.addMessageHandler(new MessageHandler.Whole() {
@Override
public void onMessage(String message) {
});
}
}
}
@Override
public void onClose(Session session, CloseReason closeReason) {
}
}, ClientEndpointConfig.Builder.create().build(), getURI(EchoEndpoint.class));

which does not seem nice to me, additionally, since Lambdas and Method References were added to the language, we could do much better than that. The main idea behind these changes is that programmatic endpoint (class javax.websocket.Endpoint) is no longer necessary, since it can be replaced by three method references, especially when you usually don’t need all of them. And Java 8 offers nice predefined Functional Interfaces, which work just fine, so we don’t even need to introduce declaration of those, we only need to define consumed types.

With these in mind, the previous code could look like:

1
2
3
4
Session session = new SessionBuilder().uri(getURI(SessionBuilderTestEndpoint.class))
.messageHandler(String.class, message -> { })
.onClose((session, closeReason) -> { })
.connect();

The main advantage I see here (other than readability) is that the configuration is no longer in two places – programmatic connectToServer method requires Endpoint, ClientEndpointConfig and other parameters, but it does not allow to register MessageHandler right away – user needs to implement that logic in @OnOpen method. On the other hand, proposed approach does that for you, so @OnOpen implementation in this case will be only what it is supposed to be. And I believe it could be omitted in lots of cases, which also contributes to readability and ease of use. Also, last but not least, less code written, less bugs introduced..

Previous code sample included lambdas, but sometimes, you might want to have more complicated code there, which does not look good implemented as lambda. In that case, you can declare standard methods with appropriate parameters and provide Method Reference instead. Slightly more complex sample would then look like:

1
2
3
4
5
6
Session s = new SessionBuilder().uri(getURI(SessionBuilderTestEndpoint.class))
.onOpen(this::onOpen)
.messageHandler(String.class, this::onMessage)
.onError(this::onError)
.onClose(this::onClose)
.connect();

More code examples can be seen in SessionBuilderTest class.

You are welcomed to try and give us your feedback. The SessionBuilder is in module “org.glassfish.tyrus.ext:tyrus-client-java8″, which is currently released only as snapshot (should be part of next Tyrus release), so you’ll need to add reference to maven.java.net snapshot repository: https://maven.java.net/content/repositories/snapshots/

Complete dependencies and repo declaration in pom.xml might look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
org.glassfish.tyrus.ext
tyrus-client-java8
1.11-SNAPSHOT
org.glassfish.tyrus
tyrus-container-grizzly-client
1.11-SNAPSHOT
maven.java.net-snapshots

Any feedback appreciated!

Links

Wednesday Mar 11, 2015

WebSocket vs REST

As controversial or potentially “flame starting” topic this might seem to be, don’t worry. I will approach this purely from pro-WebSocket view and the comparison with REST will be done on the sample, which heavily favours WebSocket ;)

Not that long ago, I had to explain one of my colleague where he should consider using WebSocket protocol and I realised, that lots of people don’t really know about it much. I even heard question whether WebSocket is successor of REST, like REST was/is to SOAP web services.. well, I’ll try to make this little bit clearer in this post.

For starters, WebSocket is NOT REST replacement. These are two technologies, which can coexist very nicely even in single application or webpage. Both are doing similar things and for some applications are even interchangeable. Bold statement, but it’s true. Both approaches have it’s own pros and cons, as with everything else..

Let’s go little back to the history of web services and remember why was WebSocket protocol even created – to allow bi-directional communication with clients, mainly represented by web pages. It was (and still is) possible to achieve the same with plain REST, but there are some issues with it. Let’s name two of them:

  • REST is always Request/Response “stateless” communication,
  • by the nature of the HTTP protocol, lots of information must be sent in each Request and response.

The first one implies simple fact – web server cannot send anything to the webpage without a Request. There are various workarounds (yes, workarounds. First real standard solution is WebSocket protocol) like long polling or JSONP, but they are solving only the communication from server to client, which implies that there needs to be the other channel from client to server. And we are getting to the second item in short list above – efficiency. When the application needs to communicate frequently with the server, the volume of HTTP traffic can be really big. Now try to compute the entropy (how much information is acquired due to observation of the Request/Response) and see how much redundant and unimportant bytes is sent with each HTTP communication. This is already addressed in HTTP/2, but anyway, the overhead still exists. I intentionally skip the HTTP/2 server push implementation – I plan to address that in another blogpost.

Enough with history lesson and plain “code-less” chatter. You might remember Shared collection sample introduced couple of moths ago in Tyrus workspace – the last modification of it was inspired by the discussion with that colleague – I wanted to compare REST and WebSocket implementation of the same thing.

Quick recapitulation – the sample exposes a map-like object in JavaScript and Java and synchronises their changes using WebSocket. Additionally you can register listeners on both sides, so you always know when anyone changes anything.. basically very simple and fragile implementation of coherence/hazelcast/yourFavouriteDistributedFramework.

As you most likely already expect, I implemented the same thing (or extended that implementation) to support REST based transport instead of WebSocket. I must admit I cheated a little – I used Server-Sent Events (SSE), which is not really RESTful, but this feature is implemented as part of Jersey, which is Reference Implementation of JAX-RS: The JavaTM API for RESTful Web Services and also my favourite REST framework (I used to be a contributor, so consider this as another very-impartial fact). SSE also has simple JavaScript API implemented in all modern browsers, so it was an easy decision for me – I have the channel from server to client covered and the other way will be just standard request using XMLHttpRequest (or an ActiveXObject when in M$ Internet Explorer).

Below is the simple scheme with mentioned protocols.

Screen Shot 2015-03-11 at 16.10.45

When you compile and deploy the sample, the standard behaviour is actually quite comparable (I’m on localhost, so that is not that much surprising), both maps receive and send updates and the experience is almost the same. So let’s look under the hood…

When you create or modify a map entry, browsers sends and event. In case of WebSocket, it is short (text) message containing Json “object” + few bytes (let’s say 8) of overhead – WebSocket message “header”. On the other hand, when you do the same action on REST version of the page, HTTP Request is sent (and Response received – it does not contain anything, just status, headers and no entity):

Screen Shot 2015-03-11 at 16.44.18

I don’t even want to know what is the overhead in this case…

You might say that it does not matter, since we are not connected using 33.6 kbps modems.. well, that’s true, but every byte introduces some delay, additional handling in the network and even app servers – they have to read/write that byte, even when it won’t be used. And that’s not everything related to the resources utilisation – imagine, that every such Request created new TCP connection to the server (which does not need to be true when HTTP keep-alive is used). Since I’m still on localhost, I wanted to push the bar little higher and wrote simple performance test: method, which will create 10k updates of single map entry (you can execute it by clicking on [PerfTest] button on the sample page – both Rest and WebSocket version have it). Starting with WebSocket – it does what is expected and I can measure how long it takes to have some comparison with REST.. but.. the problem is that the REST version does not even finish. I did not dig into that that much, but seems like every browser has some kind of limit for JavaScript requests. I was usually able to achieve something around 3-5k Requests, but after that, browser “run out of resources”, most likely to protect itself or the target site from potentially DDoS-y case.

Conclusion? If you need truly bi-directional communication, with high frequency of shorter messages (it is far easier to handle those in JavaScript than big ones), you should consider using WebSocket. On the other side, if you have some application, which already works well and uses REST efficiently, you don’t need to change that! REST is still the best solution for lots of use cases, you should look at these two technologies/protocols as complements, not as competitors.

And please don’t forget, that this was not by any means an attempt for unbiased comparison :-) Any comments/feedback is appreciated!

Links

Thursday Feb 12, 2015

Tyrus 1.10

Tyrus 1.10 is a maintenance relase, so unfortunately no cool new features to highlight, but we were able to add some new examples – Shared collection and BTC Xchange.

Complete list of fixed issues is below. I would like to thank to java.net users “toto2″ and “gray” for their help with GLASSFISH-21213. There is one other issue worth mentioning and that is TYRUS-329. In 1.10 release, Tyrus (after added tests for Per-Message compression) becomes fully compliant with Autobahn Test Suite.

Let me shortly introduce the new samples which were added in this version, just to make this blog post justifiable :).

Shared Collection Sample

In this example I tried to explore one possibility of data sharing between JavaScript client and Java code. The sample name could be misleading, the only implemented collection is a Map, which is backed up by WebSocket connection going back to the server. Both sides do implement “standard” Map, with some added flavour of distributed structures – update listener.

If you want to try it, you can follow the instructions in README.html; the application should present itself with a simple JavaScript based interface to modifying the content of the map. Don’t modify the content right away, open it in another window and observe how fast are changes propagated to other window(s).

BTC Xchange Sample

Another sample which demonstrates simple-to-implement communication with JavaScript code. On the title page you can see the graph, which in this case represents current exchange rate BTC/USD and there are some buy and sell proposals which can be executed. The sample currently allow you to go to “red numbers”, but you can create few simple modifications and make a “game” from that – the sample can be also opened from multiple windows and you can try to compete with someone else; for example, you can make a goal of getting some amount of USD or BTC :)

Complete list of changes

  • [TYRUS-394]  – Proxy bypassed on Linux but not on Windows.
  • [TYRUS-391]  – Tyrus reconnect handler not reached on Android.
  • [TYRUS-393] – Incorrect handling of sending whole message during (unfinished) partial message.
  • [TYRUS-329] – Deflate extension fixes – autobahn test suite.
  • [GLASSFISH-21213] – Deadlock (HttpSession vs TyrusWebSocket).

Monday Feb 09, 2015

Is WebSocket Session really thread safe?

Todays article would be about one simple use-case of JSR-356: Java API for WebSocket. This was brought to my attention by Mark Thomas, who started relatively long thread on the jsr356-experts mailing list. The described problem can be simplified to following code:

1
2
session.getAsyncRemote().sendText(message);
session.getBasicRemote().sendText(message);

You might be wondering what is the problem here.. first message is sent asynchronously and the second one synchronously. Session object itself is meant to be thread safe (last paragraph on class level javadoc), but there is a problem with container itself, more precisely with RemoteEndpoint.Basic interface, see following quote of its documentation:

If the websocket connection underlying this RemoteEndpoint is busy sending a message when a call is made to send another one, for example if two threads attempt to call a send method concurrently, or if a developer attempts to send a new message while in the middle of sending an existing one, the send method called while the connection is already busy may throw an IllegalStateException.

What I get from this paragraph is that the second line (from the sample above) can throw an IllegalStateException, when previous message is not sent. To be honest, reference implementation did not throw that exception (ever) and I don’t believe that any sample application or any WebSocket application I wrote checks for that state. Anyway, the javadoc does not mention that it MUST throw an exception, so for the mentioned sample, it is ok to block the second send until both messages are sent.

Unfortunately, that’s not all :). WebSocket API also allows sending partial messages and when you mix partial messages and whole messages in this context, you might start getting small headache… let’s consider following:

1
2
3
session.getBasicRemote().sendText(message, false); // partial msg
session.getBasicRemote().sendBinary(data);
session.getBasicRemote().sendText(message, true); // partial msg

In this sample, the second message should not be sent before the message from third line. Problem arises when this sequence is executed from a single thread – if second line blocks until text message is completed, we would have a problem. Implementation cannot really assume what will or won’t happen and generally it does not want to block the thread for a long time, so throwing IllegalStateException seem to be relatively OK.

(Sidenote: reference implementation, Tyrus, did not handle this scenario correctly.  The issue related to this functionality was filed as TYRUS-393 and the fix will be present in next released version – 1.10)

Since this seem to be grey area in the specification (it says what “may” be done, not what MUST or MUST NOT be done), the implementation can choose whatever it want – actually I believe that blocking the thread and waiting until it can send a message is valid, specification compliant approach. For Tyrus, I implemented little more defensive solution: the implementation waits (blocks the thread) for short period of time and if the conditions still don’t allow sending the message, IllegalStateException will be thrown.

Conclusion is not as clear as it should be – WebSocket Session object is thread safe for sure, but there are some conditions and states, which might be surprising and confusing for common users of this API. All of them can be prevented by following some rules when using WebSocket Sessions – for example if you are sending only whole messages synchronously, you don’t need to care about anything. If you are sending messages only asynchronously, it should be similar, but you might encounter some discrepancies among the implementations. When you want or need to send partial message, the issue might be harder to deal with – since WebSocket Session does not offer any way how to check the current state, it will need to be stored somewhere else and checked before invoking send* methods. My current advice is that the applications you write should add handling of  IllegalStateException from RemoteEndpoint.Basic.send* methods, especially if you expect that it can be run on different JSR 356 implementation.

Wednesday Jan 14, 2015

Reducing WebSocket client jar size with ProGuard

We already know there is a demand for standalone web socket client runnable even on different platforms than just Java EE or Java SE – Tyrus publishes client runtime all-in-one bundles for Java 6 (works on Android!) and Java 7+ (takes advantage of NIO API introduced in Java 7). In following article, we will try to create optimised version of these bundles to see whether they do contain some redundant classes. (spoiler: they do).

Tool of the choice for todays exercise would be ProGuard. Maybe not that easy to use, but it is low-level tool capable of various optimisations. We won’t cover any obfuscation, our goal is to create smaller jar with the same functionality.

Starting point is:

551K tyrus-standalone-client-jdk-1.10-SNAPSHOT.jar
1.9M tyrus-standalone-client-1.10-SNAPSHOT.jar

These jar files are representing two distribution which were already mentioned – client-jdk is Java 7 based client, client jar is Grizzly based (JDK 6+). For those who don’t know, Grizzly is Java NIO container, so it basically does the same thing as Java 7 NIO API, but in a little different manner. Also, Grizzly is the NIO framework of choice for Glassfish, Java EE reference implementation.

Downloading and executing ProGuard is not complicated, there is even GUI if you are more used to this kind of applications. After initial study and few trial runs, it seems I can produce optimised jar files with following configuration:

tyrus-client.pro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-dontoptimize
-dontobfuscate
-keepparameternames
-keepattributes Signature,InnerClasses,*Annotation*
-keepclassmembers,allowoptimization enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep public class org.glassfish.tyrus.** { public protected private *; }
-keep public class javax.websocket.** { public protected *; }
-dontwarn

 The command line for running this configuration against Tyrus client distributions would look somehow like following:

1
proguard.sh -injars ./client-jdk/target/tyrus-standalone-client-jdk-1.10-SNAPSHOT.jar -outjars tyrus-client-jdk.jar -libraryjars $JAVA_HOME/jre/lib/rt.jar @tyrus-client.pro

(previous line is for client-idk distribution, but it is very similar to the other one; just for the completeness of presented data, I’m using JDK 8; if you are using different version, your “-libraryjars” parameter might need to be adjusted).

Result:

533K tyrus-client-jdk.jar
1.2M tyrus-client.jar

For the Java 7+ client distribution, the difference is actually quite small, so we can make an assumption that the distribution is already quite optimal. The other is different story – but there is a good reason for it. Java 6+ distribution is based on Grizzly and Grizzly is mainly written as a server, not as a client. We are reusing some stuff from there, but the problem seem to be in not optimal modularization for client usecases. Anyway, just to sum that up, ProGuard was able to find and remove approximately 700 kB of “not used code”.

The conclusion is that you should consider using tool similar to ProGuard, especially when you are redistributing any java application. Special note for Android developers: you are already doing this, maybe even without knowing – DexGuard seem to be standard part of Android application development lifecycle.

Monday Dec 01, 2014

New Tyrus sample - Shared Collection

Sometime in JavaOne 2014 timeframe colleague came to me and showed me Meteor.js library, which seems to be really nice javascript framework, client and server side (kudos to the authors!). I started looking at the docs and examples and discovered leaderboard sample. In short, it is about having javascript collection backed up by some (persistent) storage on the server side, which is also shared (or replicated, if you wish) to all other clients. Meteor.js does this in Javascript “class” called Mongo.Collection (used to be Meteor.Collection, but it was renamed before 1.0 release). I really liked the idea and dug little bit more into the implementation and saw that they are using Socket.IO for the communication with the server, which is basically websocket (+fallback and other handy features).

Long story short – I wanted to do something similar and ideally publish it as Tyrus sample :-) and it wasn’t that hard! Obviously, this task is more about client javascript implementation than about what is going to happen on the server side, but it was refreshing experience – next step is Tyrus version of  Socket.IO (nah, I’m kidding…).

I don’t really want to go into details in javascript implementation, since I don’t feel very confident about that (and you can check it out in the Tyrus sources), but the goal was to create a java map-like API to store data and have it synchronized using WebSocket with all other client.

1
2
3
4
5
6
7
8
9
10
/**
* Create new Tyrus map.
*
* @param {string} url
* @param {function} updateListener
* @constructor
*/
Tyrus.Collection.Map = function (url, updateListener) {
// …
}

I created Tyrus.Collection namespace and “class” Map in it. The constructor have two arguments – URL of websocket endpoint and update listener. Update listener is invoked whenever the map is changed (this is not optimal, so currently it might be called even when you are putting the key value pair which is already there). Map has following public methods, which should feel familiar for java developers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* Get size of the map.
*
* @returns {Number} number of records in the map.
*/
self.size = function () { };
/**
* Return {@code true} when the map is empty.
*
* @returns {boolean} {@code true} when the map is empty, {@code false} otherwise.
*/
self.isEmpty = function () { };
/**
* Get value corresponding to provided key from a map.
*
* @param {string} key key.
* @returns {*} value for corresponding key or {@code null} when there is no such key.
*/
self.get = function (key) { };
/**
* Put an item into the map.
*
* @param {string} key key.
* @param {*} value value.
*/
self.put = function (key, value) { };
/**
* Remove key (and corresponding value) from the map.
*
* @param {string} key key to be removed.
*/
self.remove = function (key) { };
/**
* Clear the map.
*/
self.clear = function () { };
/**
* Get the key set.
*
* @returns {Array} array containing all keys from the map (as indexes AND values - TODO).
*/
self.keySet = function () { };

Server side implementation was quite simple and it currently stores the info only in static map. You can easily extend this by persisting the map to file/database/anywhere else. The communication is driven by very simple protocol, which broadcasts mutating messages to other clients. All get operations are handled by client-side javascript, the map on the server side is kept in sync only because it is a source for clients connected later – this is why this is just “shared” map, not “distributed” (which would be more complicated to implement). The source of the sever endpoint can be found on github, in samples directory: SharedCollectionEndpoint.

Instruction how to run this sample are included in README.html in sample root dir.

When you access the front page, you should see something like:

You can add/modify existing items in the map by using the form on the bottom side (it will automatically load an item when you click on it) and you can remove any item by clicking on the red cross on the right side. All changes should be automatically propagated to all other clients (just open the page in another browser window).

Hope you’ll enjoy the new sample and if you have any comments or suggestions, please send us a note to users@tyrus.java.net.

Links

Friday Nov 21, 2014

Tyrus 1.9

Long time no see! After a while (longer than anticipated, sorry about that), we cut off Tyrus 1.9 release. Not much changed in the code since last release, but we were able to squeeze in some stability updates and performance improvements. I’ll highlight some of the features or fixes in next paragraphs:

What’s new?

Petr worked on new feature tracked as TYRUS-289 – Debug mode. Now you can enable more verbose logging on server, which would start logging data like handshake request and response, application and endpoint configuration and information about sessions and even messages, if you want. This could be useful for answering questions like “Why I cannot access my websocket endpoint?!” and so on.

Ondřej spent some time playing with debugger and found out few code paths, which were improved. Namely instantiating default (stateless) encoders and decoders per endpoint, which will save some memory and unnecessary calls to message localization code.

Another topic worth mentioning is that we fixed (again) client runtime on Android, so if you are looking (or already using) Tyrus client on Dalvik/Art, you should be able to update to 1.9.

Complete list of resolved JIRA tickets is below. As always, if you have any feedback, please use our mailing list users@tyrus.java.net or create a new bug or enhancement request  at https://java.net/jira/browse/TYRUS/. You can also use stackoverflow – in that case, please use tag “tyrus“.

Complete list of changes

  • [TYRUS-285] – Improve broadcast by sending from multiple (configurable) threads.
  • [TYRUS-289] – DEBUG mode (client/server)
  • [TYRUS-307] – Revise ignored tests
  • [TYRUS-342] – Tyrus throw CancellationException
  • [TYRUS-355] – HTTP Redirect – Location header cannot be a relative address
  • [TYRUS-361] – JVM does not exits if shared transport is enabled
  • [TYRUS-365] – Broadcast messages are not included in the monitoring statistics
  • [TYRUS-366] – master branch not buildable with JDK 1.6
  • [TYRUS-368] – Instantiate default encoders and decoders once per endpoint
  • [TYRUS-369] – Format localized messages when necessary
  • [TYRUS-370] – Masking key is generated on server side
  • [TYRUS-371]– Introduce an option for using custom masking key generator.
  • [TYRUS-375] – Buffer overflow during HTTP Response size parsing (jdk client container)
  • [TYRUS-376] – Investigate how/whether is ScheduledExecutorService terminated when session is closed (related to heart beat feature)
  • [TYRUS-379] – Autobahn testcases 7.3.4 & 7.3.5 fail in close stage
  • [TYRUS-380] – setContextClassLoader throws “access denied” exception in JNLP client app
  • [TYRUS-381] – exception message error
  • [TYRUS-382] – onError parameter exception is wrapped in InvocationTargetException when an exception is thrown from programmatic endpoint (onOpen or onClose)
  • [TYRUS-383] – session.getRequestParameterMap does not contain query parameters when running on Grizzly standalone server
  • [TYRUS-385] – Session idle timeout concurrency issues
  • [TYRUS-386] – Dalvik class loader rejects TyrusEnpointWrapper
  • [TYRUS-387] – Unable to use Tyrus in android appllication

Friday Oct 03, 2014

Slides from my presentations from JavaOne 2014

I was given the opportunity to attend and speak at JavaOne this year. I’m pretty sure that the slide decks will be made available by conference content system, but If you have not attended or maybe want them little bit faster, you can see it on slideshare. I had two talks, the furst was about the future of Java API for WebSocket (JSR 356):

and the other one was about using WebSockets in enterprise applications:

As always, any questions or comments are welcomed!

Monday Aug 18, 2014

Tyrus 1.8

Another version of Tyrus, the reference implementation of JSR 356 – Java API for WebSocket is out! Complete list of fixes and features is below, but let me describe some of the new features in more detail. All information presented here is also available in Tyrus documentation.

What’s new?

First to mention is that JSR 356 Maintenance review Ballot is over and the change proposed for 1.1 release was accepted. More details about changes in the API can be found in this article. Important part is that Tyrus 1.8 implements this API, meaning you can use Lambda expressions and some features of Nashorn without the need for any workarounds.

Almost all other features are related to client side support, which was significantly improved in this release. Firstly – I have to admit, that Tyrus client contained security issue – SSL Hostname verification was not performed when connecting to “wss” endpoints. This was fixed as part of TYRUS-339 and resulted in some changes in the client configuration API. Now you can control whether HostnameVerification should be performed (SslEngineConfigurator#setHostnameVerificationEnabled(boolean)) or even set your own HostnameVerifier (please use carefully): #setHostnameVerifier(…). Detailed description can be found in Host verification chapter.

Another related enhancement is support for Http Basic and Digest authentication schemes. Tyrus client now enables users to provide credentials and underlying implementation will take care of everything else. Our implementation is strictly non pre-emptive, so the login information is sent always as a response to 401 Http Status Code. If the Basic and Digest are not good enough and there is a need to use some custom scheme or something which is not yet supported in Tyrus, custom Authenticator can be registered and the authentication part of the handshake process will be handled by it. Please seeClient HTTP Authentication chapter in the user guide for more details.

There are other features, like fine-grain threadpool configuration for JDK client container, build-in Http redirect support and some reshuffling related to unifying the location of client configuration classes and properties definition – every property should be now part of ClientProperties class. All new features are described in the user guide – in chapterTyrus proprietary configuration.

Update – Tyrus 1.8.1

There was another slightly late reported issue related to running in environments with SecurityManager enabled, so this version fixes that. Another noteworthy fixes are TYRUS-355 and TYRUS-361; the first one is about incorrect thread factory used for shared container timeout, which resulted in JVM waiting for that thread and not exiting as it should. The other issue enables relative URIs in Location header when using redirect feature.

Links

Complete list of changes:

Bug

  • [TYRUS-333] – Multiple endpoints on one client
  • [TYRUS-334] – When connection is closed by a peer, periodic heartbeat pong is not stopped
  • [TYRUS-336] – ReaderBuffer.getNextChars() keeps blocking a server thread after client has closed the session
  • [TYRUS-338] – JDK client SSL filter needs better synchronization during handshake phase
  • [TYRUS-339] – SSL hostname verification is missing
  • [TYRUS-340] – Test PathParamTest are not stable with JDK client
  • [TYRUS-341] – A control frame inside a stream of continuation frames is treated as the part of the stream
  • [TYRUS-343] – ControlFrameInDataStreamTest does not pass on GF
  • [TYRUS-345] – NPE is thrown, when shared container timeout property in JDK client is not set
  • [TYRUS-346] – IllegalStateException is thrown, when using proxy in JDK client
  • [TYRUS-347] – Introduce better synchronization in JDK client thread pool
  • [TYRUS-348] – When a client and server close connection simultaneously, JDK client throws NPE
  • [TYRUS-356] – Tyrus cannot determine the connection port for a wss URL
  • [TYRUS-357] – Exception thrown in MessageHandler#OnMessage is not caught in @OnError method
  • [TYRUS-359] – Client based on Java 7 Asynchronous IO makes application unexitable

Improvement

  • [TYRUS-328] – JDK 1.7 AIO Client container – threads – (setting threadpool, limits, …)
  • [TYRUS-332] – Consolidate shared client properties into one file.
  • [TYRUS-337] – Create an SSL version of Basic Servlet test

New Feature

  • [TYRUS-228] – Add client support for HTTP Basic/Digest

Task

  • [TYRUS-330] – create/run tests/servlet/basic via wss
  • [TYRUS-335] – [clustering] – introduce RemoteSession and expose them via separate method (not include remote sessions in the getOpenSessions())
  • [TYRUS-344] – Introduce Client support for HTTP Redirect

WebSocket API 1.1 released!

Its my please to announce that JSR 356 – Java API for WebSocket maintenance release ballot vote finished with majority of “yes” votes (actually, only one eligible voter did not vote, all other votes were “yeses”). New release is maintenance release and it addresses only one issue:  WEBSOCKET_SPEC-226.

What changed in the 1.1?

Version 1.1 is fully backwards compatible with version 1.0, there are only two methods added to javax.websocket.Session:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Register to handle to incoming messages in this conversation. A maximum of one message handler per
* native websocket message type (text, binary, pong) may be added to each Session. I.e. a maximum
* of one message handler to handle incoming text messages a maximum of one message handler for
* handling incoming binary messages, and a maximum of one for handling incoming pong
* messages. For further details of which message handlers handle which of the native websocket
* message types please see {@link MessageHandler.Whole} and {@link MessageHandler.Partial}.
* Adding more than one of any one type will result in a runtime exception.
*
* @param clazz   type of the message processed by message handler to be registered.
* @param handler whole message handler to be added.
* @throws IllegalStateException if there is already a MessageHandler registered for the same native
*                               websocket message type as this handler.
*/
public void addMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler);
/**
* Register to handle to incoming messages in this conversation. A maximum of one message handler per
* native websocket message type (text, binary, pong) may be added to each Session. I.e. a maximum
* of one message handler to handle incoming text messages a maximum of one message handler for
* handling incoming binary messages, and a maximum of one for handling incoming pong
* messages. For further details of which message handlers handle which of the native websocket
* message types please see {@link MessageHandler.Whole} and {@link MessageHandler.Partial}.
* Adding more than one of any one type will result in a runtime exception.
*
*
* @param clazz   type of the message processed by message handler to be registered.
* @param handler partial message handler to be added.
* @throws IllegalStateException if there is already a MessageHandler registered for the same native
*                               websocket message type as this handler.
*/
public void addMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler);

Why do we need to add those methods? Short and not precise version: to support Lambda expressions as MessageHandlers.

Longer and slightly more precise explanation: old Session#addMessageHandler method (which is still there and works as it worked till now) does rely on getting the generic parameter during the runtime, which is not (always) possible. The unfortunate part is that it works for some common cases and the expert group did not catch this issue before 1.0 release because of that. The issue is really clearly visible when Lambdas are used as message handlers:

1
2
3
session.addMessageHandler(message -> {
System.out.println("### Received: " + message);
});

There is no way for the JSR 356 implementation to get the type of the used Lambda expression, thus this call will always result in an exception. Since all modern IDEs do recommend to use Lambda expressions when possible and MessageHandler interfaces are single method interfaces, it basically just scream “use Lambdas” all over the place but when you do that, the application will fail during runtime.

Only solution we currently have is to explicitly provide the type of registered MessageHandler. (There might be another sometime in the future when generic type reification is introduced, but that is not going to happen soon enough). So the example above will then be:

1
2
3
session.addMessageHandler(String.class, message -> {
System.out.println("### Received: " + message);
});

and voila, it works.

There are some limitations – you cannot do

1
List<String>.class

, so you will need to encapsulate these types when you want to use them in MessageHandler implementation (something like “class MyType extends ArrayList<String>”). There is no better way how to solve this issue, because Java currently does not provide good way how to describe generic types.

The api itself is available on maven central, look for javax.websocket:javax.websocket-api:1.1. The reference implementation is project Tyrus, which implements WebSocket API 1.1 from version 1.8.

Monday Jun 16, 2014

Tyrus 1.7

This release cycle was shorter comparing to previous ones and the main purpose was to integrate and align with upper stack projects. Despite that fact there are some new features and bugfixes:

What’s new?

Ondřej added nice feature which allows to limit opened WebSocket sessions. And it is configurable, currently supported scopes of limitations are “per endpoint”, “per client remote address” and “per application”. This should allow effective control of server-side resources. For now, the values are static and constant, but if there will be a demand for creating more advanced session limit support, like dynamic load-balancing among set of endpoints etc, we will provide that as well. Feel free to file an enhancement request if you are interested!

Petr improved monitoring support which was added in Tyrus 1.6 – now there is a possibility to get the information about errors reported to the endpoints. Errors are collected per Exception type thrown, so you might get number of decoding issues, IOExceptions and other custom Throwables used in the endpoint implementation.

Other than that, there were just bugfixes. Two of them are worth mentioning: Tyrus now supports close codes 1012 and 1013 (SERVICE RESTART and TRY AGAIN LATER). Both of these can be returned only from server endpoint. When client side will try to send those, they will be replaced with close code 1000.

And the other bugfix is about SSL/TLS support in Java 7 AIO based client container – the issue manifested when bigger messages were sent from the client to server. The handling was not correct in this case and it could happen that the message was not completely sent.

Complete list of changes

TYRUS-313 Limiting opened connections
TYRUS-319 Bug call EJB from WebSocket
TYRUS-320 When put under heavy load by multiple clients, server throws an exception.
TYRUS-321 tyrus-client incorrectly reports HTTP staus 500 for all non-101 responses
TYRUS-322 Some of session close-codes are not supported
TYRUS-324 Session.close() should close the connection without close reason.
TYRUS-325 Server do not close session properly if non-instantiable endpoint class is provided
TYRUS-326 Expose monitoring statistics about number of @OnError method invocations
TYRUS-327 JDK client container cannot handle “big” messages over SSL/TLS

Link

If you have any feedback, suggestions or improvement requests, please send us a note tousers@tyrus.java.net or create new issue at our JIRA instance.

Friday May 16, 2014

Tyrus 1.6

I’m pleased to announce that Tyrus 1.6 was released this week and there are some nice features and bugfixes in this release, so let me introduce most important ones.

What’s new?

First bigger addition is JDK Client Transport. We used exclusively Grizzly framework for handling transport layer on the client side and now we provide an option to switch to JDK 1.7 based transport. Main advantage of it is reduced size and number of jar files. The default transport is still based on Grizzly, so if you want to try JDK 1.7 AIO, you need to enable it explicitly. See JDK 7 client chapter in Tyrus documentation for more details. This feature was implemented by Petr Janouch, new Tyrus team member.

Another important feature is monitoring server side resource utilisation and exposing this info as statistics via JMX beans. Currently available statistics are mostly about number and type of received and send messages, also there is higher level part which provides list of deployed endpoints and number of concurrent connected clients. If you want to try this out, see JMX Monitoring chapter in Tyrus user guide for configuration details. This feature was also contributed by Petr.

Next in line is change related to an issue in JSR 356. Current version of Session interface does allow use of Lambda expressions when registering a message handler, but it does not work as expected. Problem is, that it just cannot work. The API forces implementation to get the generic type information during runtime, which is not always available (in Java). Most usecases do work fine, but one doesn’t – when the anonymous class implementation is replaced by Lambda expression, type information is lost. Tyrus now implements proposed solution, but to be able to access mentioned methods, you need to cast Session to TyrusSession. Then you need to provide type of the message handler (java.lang.Class) and the handler itself – since the type info is now separated, there is no need to get it from the message handler instance , thus it will work with any representation. We are working on porting this fix to the WebSocket API, stay tuned for more details.

Last and in this case maybe least feature is WSADL. Don’t worry if you don’t know what that is – nobody does :). WSADL is XML (for now) descriptor of deployed application, currently providing only set of deployed endpoints (mainly because other information, like registered message handlers, is not that easy to get before client connects to the endpoint and can vary per Session). WSADL stands for WebSocket Application Descriptor Language and it is supposed to be the same as WADL is for RESTful webservices and WSDL for SOAP webservices. In case you want to test this feature, enableWSADL_SUPPORT (or see the test) and GET /contextPath/application.wsadl on your deployed Tyrus application.

Complete list of changes

TYRUS-301 Custom String encoder is not used
TYRUS-305 Add support for multiple client container to TestContainer
TYRUS-311 Session timeout on client does not work when set in onOpen method
TYRUS-312 TyrusFuture.get(long,TimeUnit) does not honor Future.get(long,TimeUnit) contract
TYRUS-293 Automatic heartbeat PING
TYRUS-259 Should produce a warning during deployment when OnMessage#maxMessageSize is larger than the value of org.glassfish.tyrus.servlet.incoming-buffer-size
TYRUS-308 JDK Client transport – SSL support
TYRUS-309 JDK Client transport – Proxy support
TYRUS-318 Writer returned from BasicRemote.getSendWriter() throws NPE when flush is called more than once.
TYRUS-314 Create WADL-like descriptor per deployed app
TYRUS-317 Allow server configuration using WebSocketContainer or WebSocketAddOn
TYRUS-302 Java 8 Lambda
TYRUS-214 Expose monitoring API/statistics
TYRUS-299 Missing tyrus-container-grizzly-server in the release package WebSocket RI archive
TYRUS-233 Provide client transport based on plain JDK
TYRUS-310 When max idle timeout is reset to 0, every received message or sent ping or pong causes an empty task to be scheduled and executed

Links

If you have any questions or comments or if you want to discuss anything related to Tyrus, easiest way to contact us is via users@tyrus.java.net mailing list.

Tuesday Mar 18, 2014

WebSocket API in JDK 8 - MessageHandler issue

JDK 8 is not yet released and it is already causing some headaches for JSR 356 implementors. The issue described in this article will be about the most famous and anticipated JDK 8 feature – lambda expressions and its impact to one part of WebSocket API.

Lambda expressions usable in WebSocket API can be diminished to just a replacement for standard anonymous classes; there might be some places where you can use method references, but not in the case of message handler. Following text is mainly about addMessageHandler method:

1
2
3
public interface Session extends Closeable {
void addMessageHandler(MessageHandler handler) throws IllegalStateException;
}

There are multiple use cases when addMessageHandler method is used – for example, in any endpoint based on programmatic API, which is typically true on client side. Then you have code like:

1
2
3
4
5
6
7
8
9
10
11
public class MyEndpoint extends Endpoint {
@Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String message) {
// handle message
}
});
}
}

which always works as expected. JDK 8 introduces lambda expressions which can (not only!) replace too verbose anonymous classes, when they have only single method – which is true for MessageHandler.Whole interface. So when that code is opened in IDE supporting Java 8, it will usually say something like “anonymous class can be replaced with lambda expression” and recommends that action to be done. The resulting code will be:

1
2
3
4
5
6
7
8
public class MyEndpoint extends Endpoint {
@Override
public void onOpen(javax.websocket.Session session, EndpointConfig config) {
session.addMessageHandler((MessageHandler.Whole<String>) message -> {
// handle message
});
}
}

It is nicer, part of the information is hidden, but my guess is it might not be seen as a drawback for most cases. And 3 lines of code were saved, so thumbs up! Well.. there is the last thing.. it doesn’t work.

Lambda expressions are not anonymous classes. Anonymous class can be replaced by using lambda expression and it still compiles, but the generic parameter is lost, or at least there is no way how to obtain it via standard reflection API. And that is the problem for any JSR 356 implementation – type parameter here is used for selecting appropriate Decoder (another part of the API). Any lambda expression used instead regular generic anonymous class will be treaded as MessageHandler.Whole<Object>.

What can we do with this? Surprisingly, not much. I will try to file a backwards compatibility issue/challenge agains JDK 8, but from the initial reactions on jdk8-dev mailing list, it does not seem like something anybody is willing to fix. There is one nice constructive proposal from Simone Bordet, which would at least make the variant with lambda not compilable. That would be great workaround (which will require WebSocket API 1.0.1 release and potentially changes in other APIs), but I still consider this being an issue which should be fixed in more generic way. And last but not least – I don’t think that new version of JDK should break any existing working API.

I’ll keep this post updated whenever I got additional information. Feel free to comment or suggest a solution!

EDIT:
Credit for discovering this issue should go to user ayyrk, reporter of TYRUS-302

Thursday Mar 06, 2014

Tyrus 1.5

New version of Tyrus was released today, so let’s do a quick summary of what is new compared to previous version and so on.

What’s new?

Maven archetype was (finally) added, so if you want to generate simple application, test it and maybe start playing with the code and modifying it to something more complex, you can. All you need is maven and little space on your hard drive. Then you can execute following command:

1
2
3
4
mvn archetype:generate -DarchetypeArtifactId=tyrus-archetype-echo \
-DarchetypeGroupId=org.glassfish.tyrus.archetypes -DinteractiveMode=false \
-DgroupId=com.example -DartifactId=echo -Dpackage=com.example \
-DarchetypeVersion=1.5

and the project should be created.

What’s fixed?

  • Close reason for dropped connection is now 1006, as it should be.
  • Standalone Server is not leaking daemon threads any more.
  • Java SE 8 runtime issues.
  • “Host” header parsing issue which caused failed handshakes when using IPv6 localhost address ([::1]).
  •  Internal InputStream implementation now correctly returns ‘-1′ to InputStream#read() only when end of input is reached. Thanks Raghu for contributing the fix!

Java SE 8 related issue is worth a short explanation, since the change introduced by this fix goes beyond SE 8. Original problem was about some bug in Java SE 7 which somehow corrected Tyrus behaviour, so it was not noticed by our tests – bridge methods are not returned from Class.getMethods() call there. This was fixed in Java SE 8 and it caused some troubles in Tyrus implementation, because we just did not expect them to be returned.

The other part of this issue was correcting Tyrus in terms of handling inherited methods. JSR 356 describes how these should be handled in little bit cryptic way, but it basically states that annotations are not inherited, which is already defined in Java language specification. Unfortunately, Tyrus prior this version was considering annotated methods (@OnOpen, @OnMessage, …) only from the very same class as the registered one, so inherited methods were always ignored. This is now changed, so you can have something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class BaseEndpoint {
@OnOpen
public void onOpen(Session session) throws IOException {
// do something.
}
}
@ServerEndpoint("/echo")
public class EchoEndpoint extends BaseEndpoint {
@OnMessage
public void echo(Session session, String message) throws IOException {
// do something else.
}
}

both methods – onOpen and onMessage will be considered as part of EchoEndpoint class. Please note that annotations are still not inherited, so if you for example declare BaseEndpoint class as abstract with onOpen method annotated with @OnOpen, overriding method won’t be called by Tyrus unless you “re-add” @OnOpen annotation to new method:

1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class BaseEndpoint {
public abstract void onOpen(Session session) throws IOException;
}
@ServerEndpoint("/echo")
public class EchoEndpoint extends BaseEndpoint {
@OnOpen // this has to be here!
@Override
public void onOpen(Session session) throws IOException {
// do something.
}
}

Feel free to ask here or send us a note to users@tyrus.java.net if you have any questions related to this release or anything related to our WebSocket implementation.

Links

Monday Feb 03, 2014

WebSocket Client Reconnect