Bump upstreams
[netconf.git] / restconf / websocket-client / src / main / java / org / opendaylight / restconf / websocket / client / WebSocketSessionHandler.java
1 /*
2  * Copyright © 2019 FRINX s.r.o. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.restconf.websocket.client;
10
11 import java.util.concurrent.CountDownLatch;
12 import org.eclipse.jetty.websocket.api.Session;
13 import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
14 import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
15 import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
16 import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
17 import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
18 import org.eclipse.jetty.websocket.api.annotations.WebSocket;
19 import org.eclipse.jetty.websocket.api.extensions.Frame;
20 import org.eclipse.jetty.websocket.common.frames.PingFrame;
21 import org.eclipse.jetty.websocket.common.frames.PongFrame;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 /**
26  * Web-socket session handler that is responsible for handling of incoming web-socket session events, frames
27  * and messages.
28  *
29  * @see WebSocket more information about Jetty's web-socket implementation
30  */
31 @WebSocket
32 public class WebSocketSessionHandler {
33     private static final Logger LOG = LoggerFactory.getLogger(WebSocketSessionHandler.class);
34
35     private final CountDownLatch sessionCloseLatch = new CountDownLatch(1);
36     Session webSocketSession = null;
37
38     /**
39      * Handling of the initialized web-socket session. Created web-socket session is saved.
40      *
41      * @param session Just created web-socket session.
42      * @see OnWebSocketConnect more information about this event
43      */
44     @OnWebSocketConnect
45     public synchronized void onWebSocketConnected(final Session session) {
46         if (session != null) {
47             webSocketSession = session;
48             LOG.info("Web-socket session has been initialized: {}", session);
49         } else {
50             LOG.warn("Created web-socket session is null.");
51         }
52     }
53
54     /**
55      * Handling of the closed web-socket session. Related log messages are generated and the session latch
56      * is unreleased.
57      *
58      * @param statusCode Status code of the closed session.
59      * @param reason     Reason why the web-socket session has been closed.
60      * @see OnWebSocketClose more information about this event
61      */
62     @OnWebSocketClose
63     public synchronized void onWebSocketClosed(final int statusCode, final String reason) {
64         if (webSocketSession != null) {
65             LOG.info("{}: Web-socket session has been closed with status code {} and reason: {}.", getUri(),
66                     statusCode, reason);
67             sessionCloseLatch.countDown();
68         } else {
69             LOG.warn("Trying to close web-socket session which initialization phase hasn't been registered yet "
70                     + "with status code {} and reason: {}.", statusCode, reason);
71         }
72     }
73
74     /**
75      * Handling of the error that occurred on the web-socket. Error is logged but the web-socket is not explicitly
76      * closed on error because of the testing environment in which this tool should be used.
77      *
78      * @param error Error details.
79      * @see OnWebSocketError more information about this event
80      */
81     @OnWebSocketError
82     public synchronized void onWebSocketError(final Throwable error) {
83         if (webSocketSession != null) {
84             if (error != null) {
85                 LOG.error("{}: An error occurred on web-socket session.", getUri(), error);
86             }
87         } else {
88             LOG.error("An error occurred on web-socket session which initialisation phase hasn't been "
89                     + "registered yet.", error);
90         }
91         sessionCloseLatch.countDown();
92     }
93
94     /**
95      * Handling of incoming web-socket text message. If message is not null or empty the contents of the web-socket
96      * message is logged.
97      *
98      * @param message Web-socket text message.
99      * @see OnWebSocketMessage more information about this event
100      */
101     @OnWebSocketMessage
102     public synchronized void onWebSocketMessage(final String message) {
103         if (webSocketSession != null) {
104             if (webSocketSession.isOpen()) {
105                 if (message != null) {
106                     if (!message.isEmpty()) {
107                         LOG.info("{}: Received web-socket message:\n{}.", getUri(), message);
108                     } else {
109                         LOG.info("{}: Received empty message.", getUri());
110                     }
111                 } else {
112                     LOG.warn("{}: Received null message.", getUri());
113                 }
114             } else {
115                 LOG.warn("{}: Received web-socket message on closed web-socket session:\n{}", getUri(), message);
116             }
117         } else {
118             LOG.warn("Received web-socket message on web-socket session which initialisation phase hasn't been "
119                     + "registered yet:\n{}", message);
120         }
121     }
122
123     /**
124      * Handling of incoming web-socket control frame. Only web-socket PING and PONG frames are processed and their
125      * content is logged. Web-socket PONG frames are automatically generated as the response to received PING frame
126      * by JETTY framework.
127      *
128      * @param frame Web-socket control frame.
129      * @see OnWebSocketFrame more information about this event
130      */
131     @OnWebSocketFrame
132     public synchronized void onWebSocketFrame(final Frame frame) {
133         if (webSocketSession != null) {
134             if (webSocketSession.isOpen()) {
135                 if (frame != null) {
136                     if (frame instanceof PingFrame) {
137                         LOG.info("{}: Received PING frame with message (PONG respond is automatically generated):\n{}",
138                                 getUri(), ((PingFrame) frame).getPayloadAsUTF8());
139                     } else if (frame instanceof PongFrame) {
140                         LOG.info("{}: Received PONG frame with message:\n{}", getUri(),
141                                 ((PongFrame) frame).getPayloadAsUTF8());
142                     }
143                 } else {
144                     LOG.warn("{}: Received null frame.", getUri());
145                 }
146             } else {
147                 LOG.warn("{}: Received web-socket frame on closed web-socket session:\n{}", getUri(), frame);
148             }
149         } else {
150             LOG.warn("Received web-socket frame on web-socket session which initialisation phase hasn't been "
151                     + "registered yet:\n{}", frame);
152         }
153     }
154
155     String getUri() {
156         return webSocketSession.getUpgradeRequest().getRequestURI().toString();
157     }
158
159     /**
160      * Blocking of the current thread until the web-socket session is closed.
161      */
162     void awaitClose() {
163         try {
164             sessionCloseLatch.await();
165         } catch (final InterruptedException e) {
166             LOG.error("Web-socket session was closed by external interruption.", e);
167         }
168     }
169 }