Spring WebServiceTemplate persistent connection - spring

I am trying to execute a SOAP message for an SPML searchRequest iterator. My endpoint is using the Quest SPML Provider tool which sits on top of IIS.
The problem is, I execute the search, it returns the results and an iterator ID. You take this iterator ID and make another request (this time an IteratorRequest) and the web service will return the next set of items.
When this is done through either the UI provided with the software, or through SoapUI, I have no problems, but when implementing through Spring, I get an invalid ID.
After some digging, I found this https://support.quest.com/SolutionDetail.aspx?id=SOL76284 which is stating that when a connection, or session is lost to the endpoint, the iterator will be made invalid.
My question is, is there a way to force a WebServiceTemplate.marshalSendAndReceive to keep a connection alive until I'm done iterating through the results? Or am I offbase, and need to pursue a different avenue.
Thanks a bunch!

The messageSender is what is used by the WebServiceTemplate to send the payload over protocol of choice. If it is HTTP then you can configure it to use HttpComponentsMessageSender that uses HttpClient which supports persistent HTTP connections (keep-alive).
NOTE
HTTP/1.1 has connection keep-alive but the server can decide to close it after a number of requests or does not support keep-alive.
Even JDK 6 related classes support keep-alive but you can enable pooling with HttpClient

Related

when should a web server do accept to create a new client, or reuse the same client?

In a Webserver for basic static website non-blocking event-driven, I don't understand the mechanics I should implement for a "new client".
When a browser connects to my socket, I get the clientfd from accept and answer with a HTTP response, but when the browser is reloaded, should it create a new connection and answer, or should it reuse the same connection and just send the new response?
I use poll to handle multiple fds, but when I reload the page its the same connection (for me this makes sense) but then I open a new tab, and it's still the same connection (It only does accept once). I'm not finding any documentation on this, and I don't have a way to test with multiple client's if it reuses the same one every time.
You can't reuse a connection from another client, new connections must always be accepted as new connections. It doesn't matter what kind of server application you're writing.
However, if the client passes the header Connection: keep-alive you should not close the connection once the response is finished, but keep the connection open for future requests from the same client.
I hope i understand correctly,
but anyway, What i personally do is create a map of sockets, each socket is a client.
Every time a socket disconnects, it's being removed from that map... and so on...
Whether to use a new connection is the browser's choice. You don't get much of a choice.
However, you can tell the browser that you don't allow it to reuse a connection, if you send Connection: close in the response. In this case, the browser is forced to open a new connection for the next request. This is the only control you have.
If you want to test several connections at the same time, you could open several different browsers, or you could use a different program, such as some HTTP load testing tool (there are many). You could also send it a web page with many images; browsers should try to download all the images using several connections at the same time.
A web server doesn't create clients. A web server has clients -- new clients trying to connect, and existing clients communicating on the sockets that it has already opened.
To handle new clients, a web server should pretty much be calling accept all the time, unless it's already handling the maximum number of clients that it's configured to handle.
As soon as you get a new connection from accept, hand it off to other threads to process and call accept again.

Pysyft client and server

This question is with regards to my project on federated learning using the pysyft library, but those with the knowledge of websockets can help too since pysyft uses websockets for the server and client interaction.
To start off, i have an issue regarding server and client interaction. I have created a dashboard to launch a pysyft server and a pysyft client which connects to the aforementioned server. However, i have a scenario where i want to have the client disconnect from the server from time to time (manual disconnection) so as to perform changes in model parameters.
My solution was to perform a close() on the pysyft websocketClientWorker which calls the shutdown() function on the websocket object. Doing which, i presume, will close the connection between the client and the server. After whatever changes to the model parameters have been done. I will recreate the pysyft websocketClientWorker object again and perform the model training all over again. However, i am faced with the issue of : websocket._exceptions.WebSocketConnectionClosedException: socket is already closed. This exception is being thrown (despite the successful connection to the server) during the iteration of the dataloader.
Perhaps there's a better way to go about this scenario, or am i missing certain fundamental understanding of websockets. Any help will be appreciated. Thank you :)
I managed to find the solution to my question after days of thorough inspection of the pysyft library. Turns out there is no issue with the Websocket connection and re-connection. Apparently, the superclass of websocketclient (baseworker) contains a worker registry which caches the websocketclient objects when the auto_add variable is set to True. This registry is indexed by the websocketclient ID and thus, recreation of the websocketclient object will not get replaced in the registry if the ID is the same. Therefore, this explains the 'socket is already closed' issue since it's referencing to the previous websocketclient connection that I have closed. The solution was to simply call the remove_worker_from_local_worker_registry() method on the websocketclient object before closing its connection.

Is there a Spring WebSocketSession repository?

I'm building out a Spring 4.2 based, WebSocket + SockJS + STOMP server, and I'd like to be able to get a reference to the WebSocketSession instance using the ws sessionId.
I can create a session manager myself by adding a WebSocketHandlerDecorator that registers new WebSocketSession's as their connections are established (and de-register's on close), but... this seems like something that Spring would already have created in the app context.
Does such a bean/service exist already?
Some background:
My main use case is a security concern. I am performing authorization on a per STOMP message basis, and an unauthorized message should result in the closure of the associated WS. I can intercept the messages and perform authorization, but at the moment I can't get a reference to the WebSocketSession in order to close it.
Second use case; after a successful web socket connection is made, my protocol expects a STOMP CONNECT within X seconds, or again I need to close the underlying WS connection. This one is slightly more interesting since it is asynchronous/timed and doesn't have any natural context like a message interceptor has.
All thoughts and suggestions appreciated.
EDIT
Indeed, Spring's SubProtocolWebSocketHandler class maintains a sessionId to WebSocketSession map, but all access to that map is private.
EDIT
There is support for tracking Users, Sessions, and Subscriptions at the STOMP level. This was added in version 4.2 and isn't documented in the chapter on WebSockets. (It's mentioned as a bullet point under "what's new".)
There is a SimpUserRegistry interface which provides the ability to get a user by name or a set of all users. These are SimpUser instances, which expose access to that user's sessions as a SimpSession either by a session id or as a set of all sessions for that user. From that you can obtain a set of SimpSubscription instances that represent STOMP subscriptions.
Per the javadoc, this should also work in a clustered (relay broker) environment.
Note for future readers, the SimpUserRegistry assumes that you've authenticated a user at the HTTP level, and that said user is defined by the request Principal. If you find yourself with an empty user registry, even though you have good STOMP connections, then you may not be authenticating the way the code wants.
See the last section of authentication under web sockets:
Note that even though the STOMP CONNECT frame has "login" and
"passcode" headers that can be used for authentication, Spring’s STOMP
WebSocket support ignores them and currently expects users to have
been authenticated already via HTTP.
All of the above still preclude access the the underlying web socket session, with it's close() method. I suspect my adoption on WebSocket's is a bit early, and that what I'm seeing is good support at the upper layer protocol (STOMP) level, but less fully fleshed out support for customization at the lower Web Socket layer.
I'm still looking for a way to affect the lower level Web Socket connection based on upper level activity, like non-authorized messages or failure to CONNECT after a TTL.

Which is better: multiple web socket endpoints or single web socket endpoint in Java EE7

Java EE 7 allows you to create new endpoints very easily through annotations. However, I was wondering is having multiple endpoints one to handle each message type a good idea or should I have just one endpoint facade for everything?
I am leaning towards having one single end-point facade based on the theory that each endpoint creates a new socket connection to the client. However, that theory could be incorrect and Web Socket may be implemented so that it will use just one TCP/IP socket connection regardless of how many web socket end points are connected so long as they connect to the same host:port.
I am asking specifically for Java EE 7, as there may be other web socket server implementations that may do things differently.
Just noticed an ambiguity on my question re: message types. When I say message types I meant different kinds of application messages not native message types such as "binary" or "text". As such I marked #PavelBucek answer as the accepted one.
However, I did try an experiment with Glassfish and having two end points. My suspicions were correct and that there is a TCP connection established per connected endpoint. This would cause more load on the server side if there is more than one websocket endpoint being used on a single page.
As such I concluded that there should be only one endpoint to handle the application messages provided that everything is a single native type.
This would mean that the application needs to do the dispatching rather than relying on some higher level API to do it for us.
The only valid answer here is the latter option - having multiple endpoints.
See WebSocket spec chaper 2.1.3:
The API limits the registration of MessageHandlers per Session to be one MessageHandler per native websocket message type. [WSC 2.1.3-1] In other words, the developer can only register at most one Mes- sageHandler for incoming text messages, one MessageHandler for incoming binary messages, and one MessageHandler for incoming pong messages. The websocket implementation must generate an error if this restriction is violated [WSC 2.1.3-2].
As for using or not using multiple TCP connections - AFAIK currently there will be new connection for every client and there is no easy way how you can force anything else. WebSocket multiplexing should solve it, but I don't think any WebSocket API implementation support it (I might be wrong..)

How to handle different (url) websocket connections in netty

Websocket example in netty (examples) has a http request handler which:
performs hand shaking (at first)
(then) handles different types of WebSocket frames, eventually "TextWebSocketFrame"s.
There is only one url for websocket connections in this example.
The problem is, when TextWebSocketFrame based actual websocket communication starts, there is no direct way to determine websocket url from TextWebSocketFrames themselves (correct me if I am wrong).
So, how to handle different (url) websocket connections in netty?
One solution can be registering channels and their "websocket connection urls" during handshaking process.
The other is having only one websocket connection url and resolving different contexts by adding extra information to websocket messages (TextWebSocketFrames).
I don't find these solutions elegant, so any ideas?
It is my understanding that when you perform a web socket handshake, it is to a specific URL. That is specified in the web socket standard. See RFC 6455. Hence, there is no URL information in the TextWebSocketFrame because the assumption is that the frame will be sent to the URL to which the socket is bound.
To handle different URLs, you will have to either:
Setup a different pipeline and bind to a different IP and/or port for each URL, or
Like you stated, customise the hand shake and store the URL with the channel.
Personally, I've just used JSON in a TextWebSocketFrame. In my JSON, I have a field that states the intended action. This field is used for routing to the appropriate message handler.
I think it comes down to a design decision. WebSockets are intended for long lived connections where a request message can have 0, 1 or > 1 responses. This contrasts the REST style 1 request and 1 responses model.
Hope this helps.
The question "how to handle different (url) websocket connections in netty" does not make sense, I presume that the author meant to ask "how to serve multiple different websocket paths on a single port:host".
The question is valid because the HTTP protocol, (at least version 1.1,) WebSockets, and web browsers all support this scenario:
Client connects to server and the two start exchanging HTTP request/response pairs.
Client sends the HTTP request to upgrade to WebSocket, server honors it, and now a WebSocket is established between client and server.
The original HTTP connection remains open, so client and server can continue exchanging HTTP request/response pairs in parallel to the WebSocket. (In light of this, the term "upgrade" is a misnomer, because the connection is not upgraded at all; instead, a new connection is established for the WebSocket.)
Since the HTTP connection is still available, the client can send another HTTP upgrade request, thus creating another WebSocket. On the client side, it would look like this:
socket1 = new WebSocket( "https://acme.com:8443/alpha" );
socket2 = new WebSocket( "https://acme.com:8443/bravo" );
However, you can't have that, because Netty in all its magnificent glory and terrifying complexity does not exactly support that, and this is true even now, 10 years after the question was asked.
That's because:
Only one ServerBootstrap can bind to a given port on a given host.
(That's how the socket layer works.)
A ServerBootstrap can only have one "Child Handler".
(ServerBootstrap.childHandler() silently fails to report an error if you invoke it twice, but only the last invocation takes effect.)
A ChannelPipeline can only have one WebSocketServerProtocolHandler.
(Only the first WebSocketServerProtocolHandler that you add works, and Netty silently fails to issue an error if you add more.)
A WebSocketServerProtocolHandler accepts one and only one webSocketPath.
So, there you have it, a port:host can only have one webSocketPath, and that's a Netty limitation.
It might be possible to overcome this limitation by rewriting WebSocketServerProtocolHandler, but #aintNoBodyGotNoTimeFoDat.
Luckily, Netty does support another feature which makes it possible to achieve a similar thing. The constructor of WebSocketServerProtocolHandler supports a poorly documented and poorly named checkStartsWith parameter which, if set to true, will cause the handler to honor websocket negotiation requests not only on the given webSocketPath but also for any webSocket path that starts with the given webSocketpath and continues with a '?' or a '/' followed by other stuff. So, the code on the client would then look like this:
socket1 = new WebSocket( "https://acme.com:8443/allWebSocketsHere/alpha" );
socket2 = new WebSocket( "https://acme.com:8443/allWebSocketsHere/bravo" );
If you decide to build your netty server to handle this, the next problem you will face is how to obtain the "/allWebSocketsHere/alpha" and "allWebSocketsHere/bravo" parts. Luckily, someone else has already figured that out, see "Netty: How to use query string with websocket?" https://stackoverflow.com/a/47897963/773113

Resources