WebSocketController.java
5.05 KB
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package net.ziemers.swxercise.ui.ws;
import net.ziemers.swxercise.lg.model.user.User;
import net.ziemers.swxercise.lg.user.service.SessionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import javax.websocket.CloseReason;
import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Stub für die WebSocket-Unterstützung.
*
* Aufgepasst: Mittels CDI kann nur @ApplicationScoped injiziert werden,
* da während eines WebSocket-Callbacks kein Session-Kontext aktiv ist.
*
* Copyright (c) 2017 Dipl.-Inform. Thomas Ziemer
*
* This file is part of swXercise.
*
* swXercise is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* swXercise is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with swXercise.
* If not, see <http://www.gnu.org/licenses/>.
*/
@ServerEndpoint(value = WebSocketController.serverEndpointPath,
encoders = { WebSocketJson.MessageEncoder.class },
decoders = { WebSocketJson.MessageDecoder.class } )
public class WebSocketController {
static final String serverEndpointPath = "/ws/api/v1/anEndpoint/{restSessionid}";
private static Map<Session, String> peers = Collections.synchronizedMap(new HashMap<>());
private Logger logger;
@PostConstruct
private void init() {
logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
}
/**
* Callback-Methode für das Öffnen einer neuen WebSocket-Verbindung. <code>restSessionId</code>
* wird benötigt, um die WebSocket-Verbindung mit einer REST-Authentifizierung in Bezug bringen
* zu können.
*
* @param wsSession das {@link Session}-Objekt der neuen WebSocket-Verbindung
* @param restSessionId die Session-Id einer vorangegangenen REST-Authentifizierung
*/
@OnOpen
public void onOpen(Session wsSession, @PathParam("restSessionid") String restSessionId) {
logger.info("WebSocket {} opened with session id #{}", restSessionId, wsSession.getId());
// wir können später über die gegebene WebSocket-Session die REST-Session-Id dieses WebSockets ermitteln
peers.putIfAbsent(wsSession, restSessionId);
getUserBySession(wsSession);
}
/**
* Callback-Methode, die den Empfang einer neuen WebSocket-Nachricht signalisiert.
*
* @param json der JSON-strukturierte Inhalt der WebSocket-Nachricht
* @param wsSession das {@link Session}-Objekt der sendenden WebSocket-Verbindung
*/
@OnMessage
public void onMessage(WebSocketJson json, Session wsSession) throws IOException, EncodeException {
logger.info("WebSocket Message '{}' received by session id #{}", json.getMessage(), wsSession.getId());
getUserBySession(wsSession);
try {
// Wir senden die empfangene Nachricht gleich wieder zurück. Das JSON-Marshalling geschieht automatisch.
wsSession.getBasicRemote().sendObject(json);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Callback-Methode, wenn in der WebSocket ein Problem auftrat.
*
* @param t die Exception
*/
@OnError
public void onError(Throwable t) {
logger.error("WebSocket Error '{}' occured!", t.getMessage());
}
/**
* Callback-Methode für das Schließen einer geöffneten WebSocket-Verbindung.
*
* @param reason die Ursache für das Schließen der WebSocket-Verbindung
* @param wsSession das {@link Session}-Objekt der geschlossenen WebSocket-Verbindung
*/
@OnClose
public void onClose(CloseReason reason, Session wsSession) {
logger.info("Closing WebSocket due to '{}' by session id #{}", reason.getReasonPhrase(), wsSession.getId());
peers.remove(wsSession);
}
private User getUserBySession(final Session wsSession) {
// die Map liefert uns zur WebSocket-Session gegebenenfalls die REST-Session-Id zurück;
// und mit dieser schließen wir auf den authentifizierten REST-Benutzer
String restSessionId = WebSocketController.peers.get(wsSession);
SessionContext ctx = SessionContext.getInstanceByRestSessionId(restSessionId);
if (ctx != null) {
User user = ctx.getUser();
logger.info("Detected WebSocket User '{}'", user.getFullName());
return user;
}
return null;
}
}