6c5e2536a4ef404c7cb212ac9c35d0a48134b711
[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
34     private static final Logger LOG = LoggerFactory.getLogger(WebSocketSessionHandler.class);
35
36     private final CountDownLatch sessionCloseLatch = new CountDownLatch(1);
37     Session webSocketSession;
38
39     /**
40      * Handling of the initialized web-socket session. Created web-socket session is saved.
41      *
42      * @param session Just created web-socket session.
43      * @see OnWebSocketConnect more information about this event
44      */
45     @OnWebSocketConnect
46     public synchronized void onWebSocketConnected(final Session session) {
47         if (session != null) {
48             webSocketSession = session;
49             LOG.info("Web-socket session has been initialized: {}", session);
50         } else {
51             LOG.warn("Created web-socket session is null.");
52         }
53     }
54
55     /**
56      * Handling of the closed web-socket session. Related log messages are generated and the session latch
57      * is unreleased.
58      *
59      * @param statusCode Status code of the closed session.
60      * @param reason     Reason why the web-socket session has been closed.
61      * @see OnWebSocketClose more information about this event
62      */
63     @OnWebSocketClose
64     public synchronized void onWebSocketClosed(final int statusCode, final String reason) {
65         if (webSocketSession != null) {
66             LOG.info("{}: Web-socket session has been closed with status code {} and reason: {}.", getUri(),
67                     statusCode, reason);
68             sessionCloseLatch.countDown();
69         } else {
70             LOG.warn("Trying to close web-socket session which initialization phase hasn't been registered yet "
71                     + "with status code {} and reason: {}.", statusCode, reason);
72         }
73     }
74
75     /**
76      * Handling of the error that occurred on the web-socket. Error is logged but the web-socket is not explicitly
77      * closed on error because of the testing environment in which this tool should be used.
78      *
79      * @param error Error details.
80      * @see OnWebSocketError more information about this event
81      */
82     @OnWebSocketError
83     public synchronized void onWebSocketError(final Throwable error) {
84         if (webSocketSession != null) {
85             if (error != null) {
86                 LOG.error("{}: An error occurred on web-socket session.", getUri(), error);
87             }
88         } else {
89             LOG.error("An error occurred on web-socket session which initialisation phase hasn't been "
90                     + "registered yet.", error);
91         }
92         sessionCloseLatch.countDown();
93     }
94
95     /**
96      * Handling of incoming web-socket text message. If message is not null or empty the contents of the web-socket
97      * message is logged.
98      *
99      * @param message Web-socket text message.
100      * @see OnWebSocketMessage more information about this event
101      */
102     @OnWebSocketMessage
103     public synchronized void onWebSocketMessage(final String message) {
104         if (webSocketSession != null) {
105             if (webSocketSession.isOpen()) {
106                 if (message != null) {
107                     if (!message.isEmpty()) {
108                         LOG.info("{}: Received web-socket message:\n{}.", getUri(), message);
109                     } else {
110                         LOG.info("{}: Received empty message.", getUri());
111                     }
112                 } else {
113                     LOG.warn("{}: Received null message.", getUri());
114                 }
115             } else {
116                 LOG.warn("{}: Received web-socket message on closed web-socket session:\n{}", getUri(), message);
117             }
118         } else {
119             LOG.warn("Received web-socket message on web-socket session which initialisation phase hasn't been "
120                     + "registered yet:\n{}", message);
121         }
122     }
123
124     /**
125      * Handling of incoming web-socket control frame. Only web-socket PING and PONG frames are processed and their
126      * content is logged. Web-socket PONG frames are automatically generated as the response to received PING frame
127      * by JETTY framework.
128      *
129      * @param frame Web-socket control frame.
130      * @see OnWebSocketFrame more information about this event
131      */
132     @OnWebSocketFrame
133     public synchronized void onWebSocketFrame(final Frame frame) {
134         if (webSocketSession != null) {
135             if (webSocketSession.isOpen()) {
136                 if (frame != null) {
137                     if (frame instanceof PingFrame) {
138                         LOG.info("{}: Received PING frame with message (PONG respond is automatically generated):\n{}",
139                                 getUri(), ((PingFrame) frame).getPayloadAsUTF8());
140                     } else if (frame instanceof PongFrame) {
141                         LOG.info("{}: Received PONG frame with message:\n{}", getUri(),
142                                 ((PongFrame) frame).getPayloadAsUTF8());
143                     }
144                 } else {
145                     LOG.warn("{}: Received null frame.", getUri());
146                 }
147             } else {
148                 LOG.warn("{}: Received web-socket frame on closed web-socket session:\n{}", getUri(), frame);
149             }
150         } else {
151             LOG.warn("Received web-socket frame on web-socket session which initialisation phase hasn't been "
152                     + "registered yet:\n{}", frame);
153         }
154     }
155
156     String getUri() {
157         return webSocketSession.getUpgradeRequest().getRequestURI().toString();
158     }
159
160     /**
161      * Blocking of the current thread until the web-socket session is closed.
162      */
163     void awaitClose() {
164         try {
165             sessionCloseLatch.await();
166         } catch (final InterruptedException e) {
167             LOG.error("Web-socket session was closed by external interruption.", e);
168         }
169     }
170 }