Custom WebSocket Interceptors
(This is an addition to the WebSocket routing and intercepting features. If you want to know more about it please visit the WebSocket routing and intercepting.)
Similar to how one can create interceptors for the HTTP functionality of Membrane one can also create WebSocket interceptors for usage in the webSocket interceptor. For this the WebSocketInterceptorInterface interface is defined in Membrane.
public interface WebSocketInterceptorInterface { void init(Router router) throws Exception; void handleFrame(WebSocketFrame frame, boolean frameTravelsToRight, WebSocketSender sender) throws Exception; }
The init(Router router) method is used to give the interceptor access to the router object of Membrane.
The interesting part of this interface is the handleFrame(…) method. In it one has access to a WebSocket frame and can manipulate it. Additionally the flight direction of the WebSocket frame is specified by a boolean. Traveling to right means that the WebSocket frame is sent from client to server, traveling to left means from server to client. When processing is done one can either stop the interceptor chain or let it go on. In the second case one has to call the sender.handleFrame(…) method to send the WebSocket frame down the chain. The sender.handleFrame(…) method can optionally be called multiple times (with same or different frames) to send additional frames down the chain.
In the following chapter we will reimplement the WebSocket logging interceptor of Membrane.
Do-it-yourself Intercepting
The goal of this interceptor is to write the contents of all incoming WebSocket frames to the console.
We will start out by creating a new class file named MyWebSocketLogInterceptor that implements WebSocketInterceptorInterface. We complete the class definition by adding the missing methods from the interface.
import com.predic8.membrane.core.Router; import com.predic8.membrane.core.transport.ws.WebSocketFrame; import com.predic8.membrane.core.transport.ws.WebSocketInterceptorInterface; import com.predic8.membrane.core.transport.ws.WebSocketSender; public class MyWebSocketLogInterceptor implements WebSocketInterceptorInterface { public void init(Router router) throws Exception { } public void handleFrame(WebSocketFrame frame, boolean frameTravelsToRight, WebSocketSender sender) throws Exception { } }
Note: This listing can be used as a base for all custom interceptors.
The WebSocket logging interceptor is a simple WebSocket interceptor and does not need any special initialization. Thus the init(…) method will stay empty.
A WebSocket interceptor has the chance to process a WebSocket frame in the handleFrame(…) method. Here we will do the work that is needed to log the content of a WebSocket frame to the console. The WebSocket frame argument that is given to the method contains all information about a WebSocket frame so all we need to do is to convert this data into a String object and print it. Luckily the WebSocketFrame class already overrides the toString() method of the WebSocket frame and so we do not need to do this manually.
It would also be useful to know in which direction (client to server or server to client) the WebSocket frame is traveling. The direction of the WebSocket frame is not included in the toString() method as the WebSocket frame does not know about the direction it is send. But this information is given through the travelsToRight argument of the handleFrame(…) method.
The processing of the WebSocket frame in the log interceptor is done now. The interceptor can now decide to omit the frame or to send it further down the interceptor chain/to the target. As we only want to log the WebSocket frame we invoke the handleFrame(…) method on the sender object to send the WebSocket frame further.
The resulting handleFrame(…) method of the log interceptor is thus:
public void handleFrame(WebSocketFrame frame, boolean frameTravelsToRight, WebSocketSender sender) throws Exception { System.out.println("Frame travels from " + (frameTravelsToRight ? "client to server" : "server to client")); System.out.println(frame.toString()); sender.handleFrame(frame); }
Now the interceptor is usable. There is nothing else to do besides instantiating the interceptor in your other program.
The resulting class looks as follows:
import com.predic8.membrane.core.Router; import com.predic8.membrane.core.transport.ws.WebSocketFrame; import com.predic8.membrane.core.transport.ws.WebSocketInterceptorInterface; import com.predic8.membrane.core.transport.ws.WebSocketSender; public class MyWebSocketLogInterceptor implements WebSocketInterceptorInterface { public void init(Router router) throws Exception { } public void handleFrame(WebSocketFrame frame, boolean frameTravelsToRight, WebSocketSender sender) throws Exception { System.out.println("Frame travels from " + (frameTravelsToRight ? "client to server" : "server to client")); System.out.println(frame.toString()); sender.handleFrame(frame); } }
Getting Started
See $MEMBRANE_HOME/examples/custom-websocket-interceptor in the Membrane Service Proxy distribution for a working example.