Monday Feb 03, 2014

WebSocket Client Reconnect

Another new feature was recently added to Tyrus (Java API for WebSocket Reference Implementation): Client ReconnectHandler. Some client use cases require almost persistent client-to-server connection and don’t really care about lower layer issues, like unstable internet connection.

Tyrus Client now include possibility of registering ReconnectHandler, which can help with these scenarios. Let’s see ReconnectHandler declaration:

1
2
3
4
5
6
7
8
9
10
public class ReconnectHandler {
public boolean onDisconnect(CloseReason closeReason) {
return false;
}
public boolean onConnectFailure(Exception exception) {
return false;
}
}

Method onDisconnect is executed whenever client endpoint @OnClose annotated method is called, method onConnectFailure is executed whenever client has some troubles connecting to remote endpoint (network issues, server returning HTTP Status 500, …). Both methods can return boolean value, which indicates whether client should try to reconnect or not.

It is perfectly fine to wait in any of these methods for some time – I would recommend it for onConnectFailure, because there usually is some reason for network failure and repeating requests without any delay can prolong them or even make them worse. Also I would recommend include some kind of counter, which would set the number of reconnect attempts.

Example implementation could look like:

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
ClientManager client = ClientManager.createClient();
ClientManager.ReconnectHandler reconnectHandler = new ClientManager.ReconnectHandler() {
private int counter = 0;
@Override
public boolean onDisconnect(CloseReason closeReason) {
counter++;
if (counter <= 3) {
System.out.println("### Reconnecting... (reconnect count: " + counter + ")");
return true;
} else {
return false;
}
}
@Override
public boolean onConnectFailure(Exception exception) {
counter++;
if (counter <= 3) {
System.out.println("### Reconnecting... (reconnect count: " + counter + ") " + exception.getMessage());
// Thread.sleep(...) or something other "sleep-like" expression can be put here - you might want
// to do it here to avoid potential DDoS when you don't limit number of reconnects.
return true;
} else {
return false;
}
}
};
client.getProperties().put(ClientManager.RECONNECT_HANDLER, reconnectHandler);
client.connectToServer(...)

Tuesday Jan 21, 2014

WebSocket Client on Android – Tyrus

Running some Java EE libraries or frameworks in non-standard VM is not an uncommon task and same is for Tyrus. I have to admit that this task was driven mainly by issue report TYRUS-256 from Reza. There is no official support from Tyrus running on Dalvik and I'm not even sure if it is a good idea, but important fact is that it works and you can do it if you want :-).

Whole issue which blocked runtime from being able to run on Android was in usage of javax.naming.InitialContext class. There is no simple alternative to it, but fortunately there is always a possibility to do little bit of reflection hacking to get rid of the dependency if it's not there. The rest was only about creating the sample application and testing it on my phone, which was not that hard. I have to give kudos to IntelliJ IDEA team for their support, but not for Android Studio - it uses gradle as build tool and it seems like you cannot include java library because android plugin clashes with java plugin (I'm not very familiar with gradle as you might have noticed). Using and build script and build in support was better for my task.

The application I used for testing is available on github in my personal workspace: https://github.com/pavelbucek/tyrus-client-android-test. Feel free to test it and/or provide pull requests. I would be particularly interested in gradle build script.

That's it for today. If you are using Tyrus on Android or if you have any related comments, please share them with us on Tyrus mailing list or as an enhancement request.

Saturday Dec 28, 2013

Tyrus client – shared container

Current “trunk” version contains one notable feature – shared client container. It can save significant portion of resources on client side if you are creating lots of client connections and there is almost no drawback.

This feature was added as a response to TYRUS-275 and it somehow copies what other containers are doing in the JRS 356 implementation. Specification does not really state which system resources should be reusable (that’s ok, I think this is implementation detail), but it also does not take care of thread pool related settings, which might introduce some inconsistencies among implementations.

WebSocket client implementation in Tyrus re-creates client runtime wheneverWebSocketContainer#connectToServer is invoked. This approach gives us some perks like out-of-the-box isolation and relatively low thread count (currently we have 1 selector thread and 2 worker threads). Also it gives you the ability to stop the client runtime – one Session instance is tied to exactly one client runtime, so we can stop it when Session is closed. This seems as a good solution for most of WebSocket client use cases – you usually use java client from application which uses it for communicating with server side and you typically don’t need more than 10 instances (my personal estimate is that more than 90% applications won’t use more than 1 connection). There are several reasons for it – of it is just a client, it needs to preserve server resources – one WebSocket connection means one TCP connection and we don’t really want clients to consume more than needed. Previous statement may be invalidated by WebSocket multiplexing extension, but for now, it is still valid.

On the other hand, WebSocket client implementations in some other containers took another (also correct) approach – they share client runtime for creating all client connections. That means they might not have this strict one session one runtime policy, they cannot really give user way how he to control system resources, but surely it has another advantage – it can handle much more opened connections. Thread pools are share among client sessions which may or may not have some unforeseen consequences, but if its implemented correctly, it should outperform Tyrus solution mentioned in previous paragraph in some use cases, like the one mentioned in TYRUS-275 - performance tests. Reported created simple program which used WebSocket API to create clients and connect to remote endpoint and he measured how many clients can he create (or in other words: how many parallel client connection can be created; I guess that original test case is to measure possible number of concurrent clients on server side, but that does not really matter for this post). Tyrus implementation loose compared to some other and it was exactly because it did not have shared client runtime capability.

I hope that common grounds are established and explained and we can take more detailed look to Tyrus implementation of shared client runtime. Default client implementation is using Grizzly as client container and all the work was done there – client SPI did not need to be changed (phew), so basically there are only some static fields and some basic synchronisation required for this to work. Grizzly part was really easy, it is only about sharing the instance of created TCPNIOTransport. Another small enhancement related to this feature is shared container timeout – if shared client runtime does not handle any connections for set period of time, it will just shutdown and clear all used resources. Everything will be automatically recreated when needed. Default value for this is 30 seconds.

How can you use this feature?

1
2
3
ClientManager client = ClientManager.createClient();
client.getProperties().put(GrizzlyClientContainer.SHARED_CONTAINER, true);

And you are done. You might also want to specify container idle timeout:

1
client.getProperties().put(GrizzlyClientContainer.SHARED_CONTAINER_IDLE_TIMEOUT, 5);

and last but not least, you might want to specify thread pool sizes used by shared container (please use this feature only when you do know what are you doing. Grizzly by default does not limit max number of used threads, so if you do that, please make sure thread pool size fits your purpose):

1
2
client.getProperties().put(GrizzlyClientSocket.SELECTOR_THREAD_POOL_CONFIG, ThreadPoolConfig.defaultConfig().setMaxPoolSize(3));
client.getProperties().put(GrizzlyClientSocket.WORKER_THREAD_POOL_CONFIG, ThreadPoolConfig.defaultConfig().setMaxPoolSize(10));

And that’s it for today. You can use mentioned features with Tyrus 1.4-SNAPSHOT and newer, feel free to comment this post or drop me a note to users@tyrus.java.net with any feedback or suggestion how this can be improved.

Links

Tuesday Jul 16, 2013

WebSocket via HTTP proxy

As you might know, WebSocket can be used for bi-directional "real-time" communication with multiple clients. What does that mean in proxy environments and how this even works? WebSocket uses HTTP upgrade mechanism specified in HTTP 1.1 and by design requires open (TCP) connection.

HTTP CONNECT is there for exactly these usecases. It is usually used for tunneling HTTPS via proxy, but it can be used for WebSocket as well.

I will describe complete "proxified" handshake using captured connection of Tyrus Client connecting to public echo service - echo.websocket.org. Please note that we are directly using Tyrus API - not WebSocket specification (JSR-356), because we need to set a proxy.

final ClientManager client = ClientManager.createClient();

client.getProperties().put(
  GrizzlyClientSocket.PROXY_URI, "http://my.proxy:8080"
);
final Session session = client.connectToServer(new Endpoint() {

  @Override
  public void onOpen(Session session, EndpointConfig config) {
    session.addMessageHandler(new MessageHandler.Whole<String>() {
      @Override
      public void onMessage(String message) {
        System.out.println("# Message received: " + message);
      }
    });
  }
}, ClientEndpointConfig.Builder.create().build(),
   URI.create("ws://echo.websocket.org"));

session.getBasicRemote().sendText("test message");

BTW, Tyrus Client proxy support can be improved, currently it does not support proxy authentication, JDK's ProxySelector and so on. Please vote/comment on TYRUS-204 if you lack some of the mentioned options or anything else related to proxy support.

Current modern browsers do support this out of the box, so all you need is to set your HTTP proxy and described handshake will be done automatically. There might be limitation for parallel open connection in browser tab/instance, but I don't have any exact data about this.

Also, you might ask whether there is some need to server-side support - simple answer is "no". HTTP containers will see regular connection (from proxy), there is no additional work or overhead on that side.

Lets see our dumped communication:

client > proxy
CONNECT echo.websocket.org:80 HTTP/1.1
Host: echo.websocket.org
Proxy-Connection: keep-alive
Connection: keep-alive

Firstly, client need to send a request to proxy for new "permanent" connection. As already mentioned, CONNECT method handles this. First argument is a hostname (echo.websocket.org) and standard HTTP version.

proxy > client
HTTP/1.0 200 Connection established

If you are lucky, your proxy does support CONNECT and allows you to create connection (HTTP 200 is returned).

client > proxy
GET / HTTP/1.1
Connection: Upgrade
Host: echo.websocket.org
Origin: echo.websocket.org
Sec-WebSocket-Key : sDD3Wk7PMRCPE9+C0VyOcQ==
Sec-WebSocket-Version: 13
Upgrade: websocket

This is standard WebSocket handshake request, which will be passed to target HTTP container.

proxy > client
HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: 8TNIHr7bJHqQadjXYvqLql6RFEA=
Date: Tue, 16 Jul 2013 15:30:53 GMT
...

And there is a valid response to our handshake request, connection is established and communication can be started; there is nothing else different than in proxy-less environment. Please note that proxies do have limited resources and your request may be turned down because proxy "CONNECT" pool is empty.

Conclusion here is that WebSocket can work via proxies without any limitation, it just introduces different kind of traffic than pure HTTP and might cause some additional requirements related to proxy performance in case you are going to use WebSocket for long-running client connections.

Monday Jul 08, 2013

WebSocket command line client

Tyrus 1.1 brings new feature - simple command line client, which can be useful in many scenarios. You can use it for simple development testing, sanity testing or for monitoring of your deployed endpoints.

How to use:

# you can use wget .. or anything else you like:
wget http://search.maven.org/remotecontent?filepath=org/glassfish/tyrus/ext/tyrus-client-cli/1.1/tyrus-client-cli-1.1.jar -O ./tyrus-client-cli-1.1.jar
  • Execute downloaded binary
java -jar ./tyrus-client-cli-1.1.jar --help

that should print out usage information. Tyrus CLI client currently supports sending text messages and pings to one opened endpoint + you can close current session and connect to another one within one run. (If you try to open another connection while having another one already connected, close will be invoked automatically, so you will be still talking only to one endpoint).

Example:

$ java -jar ./tyrus-client-cli-1.1.jar ws://echo.websocket.org
# Connecting to ws://echo.websocket.org...
# Connected in session e303ad22-c5af-4bc3-9384-58ce6832ae94
session e303...ae94> ping
# pong-message
session e303...ae94> send tyrus-test-message
# text-message: tyrus-test-message
session e303...ae94> close
# closed: CloseReason[1000,no reason given]
# Session closed

note: lines starting with hash '#' symbol are generated from the client runtime, "# text-message: ..." means text message was received, etc.

This utility can be improved, please let us know if you have any suggestions about what feature would you like to add.

Many thanks to Gerard Davison for contributing main functionality of this module!

Tuesday Jun 28, 2011

Jersey non blocking client

Although Jersey already have support for making asynchronous requests, it is implemented by standard blocking way - every asynchronous request is handled by one thread and that thread is released only after request is completely processed. That is OK for lots of cases, but imagine how that will work when you need to do lots of parallel requests. Of course you can limit (and its really wise thing to do, you do want control your resources) number of threads used for asynchronous requests, but you'll get another maybe not pleasant consequence - obviously processing time will increase.

There are few projects which are trying to deal with that problem, commonly named as async http clients. I didn't want to "re-implement a wheel" and I decided I'll use AHC - Async Http Client made by Jeanfrancois Arcand. There is also interesting implementation from Apache - HttpAsyncClient, but it is still in "very early stages of development" and others haven't been in similar or better shape as AHC.

How this works? Non-blocking clients allow users to make same asynchronous requests as we can do with standard approach but implementation is different - threads are better utilized, they don't spend most of time in idle state. Simply described - when you make a request (send it over the network), you are waiting for reply from other side. And there comes main advantage of non-blocking approach - it uses these threads for further work, like making other requests or processing responses etc.. Idle time is minimized and your resources (threads) will be far better used.

Who should consider using this? Everyone who is making lots of asynchronous requests. I haven't done proper benchmark yet, but some simple dumb tests are showing huge improvement in cases where lots of concurrent asynchronous requests are made in short period.

Last but not least - this module is still experimental, so if you don't like something or if you have ideas for improvements/any feedback, feel free to comment this blog post, send mail to users@jersey.java.net or contact me personally. All feedback is greatly appreciated!

maven dependency (will be present in java.net maven 2 repo by the end of the day):

link: http://download.java.net/maven/2/com/sun/jersey/experimental/jersey-non-blocking-client

<dependency>
 <groupId>com.sun.jersey.experimental</groupId>
 <artifactId>jersey-non-blocking-client</artifactId>
 <version>1.9-SNAPSHOT</version>
</dependency>

code snippet:

 ClientConfig cc = new DefaultNonBlockingClientConfig();
 cc.getProperties().put(NonBlockingClientConfig.PROPERTY_THREADPOOL_SIZE, 10); // default value, feel free to change
 Client c = NonBlockingClient.create(cc);

 AsyncWebResource awr = c.asyncResource("http://oracle.com");

 Future<ClientResponse> responseFuture = awr.get(ClientResponse.class);

 // or
 awr.get(new TypeListener<ClientResponse>(ClientResponse.class) {
     @Override
     public void onComplete(Future<ClientResponse> f) throws InterruptedException {
          ...
     }
 });

javadoc (temporary location, won't be updated): http://anise.cz/~paja/jersey-non-blocking-client/

Friday May 20, 2011

Limiting threads used for asynchronous requests - Jersey Client

Jersey Client already has support for making asynchronous requests, but it uses default ExecutorService, which spawns new thread for each request, which is not very convenient in most of cases. You can set your own ExecutorService (see Client.setExecutorService()) and limit thread count but it is not that obvious thing and lots of users are not aware of this possibility.

So I've added another property to ClientConfig class which represents threadpool size of created ExecutorService. See code snippet below:

        ClientConfig cc = new DefaultClientConfig();
        cc.getProperties().put(ClientConfig.PROPERTY_THREADPOOL_SIZE, 10);
        Client c = Client.create(cc);
        AsyncWebResource r = c.asyncResource("http://somehost.tld/resource").build());

And possibility to set your own ExecutorService still remains, so consider this just as some minor improvement/try for visibility gain for this option.

Thursday Apr 21, 2011

Jersey Client - Presentation slides - CZJUG

Slides

Jersey Client - Apache HTTP Client 4.x integration

Since this week, Jersey users can benefit from Apache HTTP Client 4.x integration. "jersey-apache-http-client4" module has been finalized and provides similar functionality as "jersey-apache-http-client", but make sure you read javadoc - most of settings have changes because of major change in Apache HTTP Client API.

How to start with Jersey and Apache HTTP Client 4.x?

Add following dependency:

<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-apache-http-client4</artifactId>
    <version>1.7-SNAPSHOT</version> <!-- or 1.7-ea04 and newer, when available -->
</dependency>


And you can instantiate new client for example like described in Javadoc: package com.sun.jersey.client.apache4.

Friday Feb 11, 2011

Replacing client used in Jersey Test Framework

There was an interesting question on mailing list - Is it possible to replace default Jersey client in JerseyTest? (JerseyTest is a class from Jersey Test Framework, basically superclass of all "Jersey enabled" tests).

Answer is.. not really. It just wasn't made to support this option. Until now :)

There was method getClient(), but it couldn't be easily overriden (it was private static) and it actually does more that create Client, so it isn't really method you want to replace. Long story short.. I created overridable ClientFactory which is (surprisingly) responsible for creating new Clients..

Let's say we want to just replace default Jersey Client implementation by Apache:

public class MainTest extends JerseyTest {
    ...
    @Override
    protected ClientFactory getClientFactory() {
        return new ClientFactory() {
            @Override
            public Client create(ClientConfig clientConfig) {
                return ApacheHttpClient.create(clientConfig);
            }
        };
    }
}

This overrides default client implementation BUT still allows container override this and use its client (this is used for example in InMemoryTestContainer). If you want to have total control and replace even this concept, you can do it by overriding getClient() method:

    @Override
    protected Client getClient(TestContainer tc, AppDescriptor ad) {
        return ApacheHttpClient.create(ad.getClientConfig());
    }

but I don't recommend this approach, former one should be sufficient in most cases.

This functionality is present in 1.6-SNAPSHOT and 1.6-ea03 (and newer Jersey versions).

Friday Feb 04, 2011

Jersey Client - Making requests with HttpURLConnection hack

HttpURLConnection provided in JDK has serious limitation - you can't do requests with arbitrary chosen method - actually it limit methods to some subsed defined in javadoc, which is NOT extendable in any way.. which might cause some problems. For example you can't do PATCH request because it wasn't in HTTP spec in the time of writing that class. And if you would want to use it for making WebDav client, you are totally lost, it just can't be done.

 Well, until now ;)

One Jersey user - Markus Karg came with a workaround. Method name can be "injected" to one field in HttpURLConnection via injection and it will be used to create request. We don't want to have this enabled by default, so if you want to use it, you need to set property URLConnectionClientHandler.PROPERTY_HTTP_URL_CONNECTION_SET_METHOD_WORKAROUND to true.

        DefaultClientConfig config = new DefaultClientConfig();
        config.getProperties().put(URLConnectionClientHandler.PROPERTY_HTTP_URL_CONNECTION_SET_METHOD_WORKAROUND, true);
        Client c = Client.create(config);

        WebResource r = c.resource(getUri().path("test/entity").build());

        ClientResponse cr = r.method("GOTOSLEEP", ClientResponse.class);

will produce:

Feb 4, 2011 11:25:44 AM com.sun.jersey.api.client.filter.LoggingFilter log
INFO: 1 \* Client out-bound request
1 > GOTOSLEEP http://localhost:9997/test/test

and you can cleary see that method "GOTOSLEEP" was used and HttpURLConnection don't complain about anything. This workaround has some limitation - you can't put an entity to the request. And additionally, it \*probably\* wont work on some containers and maybe in future versions of JDK (containers sometimes have their own implementation of HttpURLConnection).

This functionality is available in current Jersey trunk (1.6-SNAPSHOT) and in promoted build 1.6-ea02 (which will be released later today).

Wednesday Jan 26, 2011

Jersey - Apache HTTP Client 4.1 (experimental) integration available

What is supported? All basic functionality (simple requests with or without entity) and Jersey related things like filters (logging, auth, ...). Additionally, some of Apache HTTP Client features are supported by default - like cookies processing.

What needs to be done:

  • Apache style auth support
  • Proxy configuration settings
  • Caching and other features...

How can you give it a try? Simply.. put another dependency to your maven project:

        <dependency>
            <groupId>com.sun.jersey.experimental</groupId>
            <artifactId>jersey-apache-client4</artifactId>
            <version>1.6-SNAPSHOT</version>
        </dependency>

And create your client like:

        Client c = new com.sun.jersey.client.apache.ApacheHttpClient4();

        WebResource wr = c.resource("http://localhost:9998/helloworld-webapp");

        String s = wr.path("helloworld").get(String.class);

        System.out.println(s);

and use it like you are used to..

Comments/remarks/suggestions are welcomed!

Tuesday May 05, 2009

Jersey Client - Using ContainerListener

I would like to introduce a possibility to monitor connections made within jersey client api. Monitoring in this case means have knowledge about amount of transferred bytes.

This functionality is provided (as many others) as a client filter, concretely ConnectionListenerFilter. To create ConnectionListenerFilterinstance, you have to implement OnStartConnectionListener. It might look as follows:

class ListenerFactory implements OnStartConnectionListener {
     public ContainerListener onStart(ClientRequest cr) {
         return new Listener();
    }
}

Looks simple (and it is). This factory creates ContainerListener instance based on ClientRequest. Important note: ClientRequest instance here may be used only for getting values. Any attempt to change anything will produce UnsupportedOperationException.

Ok. Now we need ContainerListener implementation. This class is defined as:

public abstract class ContainerListener {

    public void onSent(long delta, long bytes) {};

    public void onReceiveStart(long totalBytes) {};

    public void onReceived(long delta, long bytes) {};

    public void onFinish() {};
}

Parameters should be easy to understand, delta is always difference to previous call, bytes is sum of sent/received bytes so far and totalBytes is value from http header (if present, otherwise is set to -1).

Every request has a simple "lifecycle":

1) Send request
2) Receive response

Method onSent is called during step one only when request has some entity. When request is sent and response has no entity, onFinish() is called and that's it. More interesting scenario is when response contains some entity - onReceiveStart is called after sending a request and onReceived during data receiving. Method onFinish is called after whole entity is read.

You will probably have some nice GUI progress bar but I'm going to do only plain text log for now to keep it simple.

class Listener extends ContainerListener {
     @Override
     public void onSent(long delta, long bytes) {
         System.out.println("onSent: delta: " + delta + " bytes: " + bytes);
     }

     @Override
     public void onReceiveStart(long totalBytes) {
         System.out.println("onReceiveStart: " + totalBytes);
     }

     @Override
     public void onReceived(long delta, long bytes) {
         System.out.println("onReceived: delta: " + delta + " bytes: " + bytes);
     }

     @Override
     public void onFinish() {
         System.out.println("onFinish");
     }
}

And we're almost done! Last thing to do is register our ListenerFactory as a client filter:

    Client c = Client.create();

    c.addFilter(new ConnectionListenerFilter(new ListenerFactory()));

and actually do a request:

    WebResource r = c.resource("http://download.java.net/maven/2/com/sun/jersey/samples/jersey-samples/1.1.0-ea/jersey-samples-1.1.0-ea-project.zip");
    r.get(String.class);

Output should look like this:

onReceiveStart: 615534
onReceived: delta: 3677 bytes: 3677
onReceived: delta: 2608 bytes: 6285
...
onReceived: delta: 2608 bytes: 613949
onReceived: delta: 1585 bytes: 615534
onFinish

You can experiment with some requests containing entity (so you will see that onSent method is called during sending).

For more information about project Jersey visit http://jersey.dev.java.net

About

Pavel Bucek

Search

Categories
Archives
« July 2014
SunMonTueWedThuFriSat
  
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
  
       
Today