Commit 668dfe4b771fe06d7ab013de74e9240a929f8f6d

Authored by Thomas Ziemer
1 parent ecbbc717

feature: REST- mit WebSocket-Verbindung in Bezug bringen können

src/main/java/net/ziemers/swxercise/lg/user/service/SessionContext.java
@@ -14,6 +14,8 @@ public class SessionContext implements java.io.Serializable { @@ -14,6 +14,8 @@ public class SessionContext implements java.io.Serializable {
14 14
15 private User user = null; 15 private User user = null;
16 16
  17 + private String sessionId = "";
  18 +
17 public User getUser() { 19 public User getUser() {
18 return user; 20 return user;
19 } 21 }
@@ -22,9 +24,21 @@ public class SessionContext implements java.io.Serializable { @@ -22,9 +24,21 @@ public class SessionContext implements java.io.Serializable {
22 this.user = user; 24 this.user = user;
23 } 25 }
24 26
25 - public boolean login(final User user) { 27 + public String getSessionId() { return sessionId; }
  28 +
  29 + private void setSessionId(String sessionId) { this.sessionId = sessionId; }
  30 +
  31 + /**
  32 + * Meldet einen Benutzer in diesem Session-Kontext an.
  33 + *
  34 + * @param user das {@link User}-Objekt des Benutzers dieses Session-Kontexts
  35 + * @param sessionId die Session-Id dieser Benutzer-Session
  36 + * @return Liefert <code>true</code> zurück, wenn der Benutzer am Session-Kontext angemeldet werden konnte.
  37 + */
  38 + public boolean login(final User user, final String sessionId) {
26 if (getUser() == null) { 39 if (getUser() == null) {
27 setUser(user); 40 setUser(user);
  41 + setSessionId(sessionId);
28 return true; 42 return true;
29 } 43 }
30 return false; 44 return false;
src/main/java/net/ziemers/swxercise/lg/user/service/UserService.java
@@ -34,11 +34,14 @@ public class UserService { @@ -34,11 +34,14 @@ public class UserService {
34 * Meldet den Benutzer im SessionContext an. 34 * Meldet den Benutzer im SessionContext an.
35 * 35 *
36 * @param dto das {@link UserDto} enthält die Eigenschaften des anzumeldenden Benutzers 36 * @param dto das {@link UserDto} enthält die Eigenschaften des anzumeldenden Benutzers
  37 + * @param sessionId die Session-Id, über die diese Benutzer-Authentifizierung erfolgt
37 * @return <code>true</code>, wenn die Anmeldung erfolgreich war. 38 * @return <code>true</code>, wenn die Anmeldung erfolgreich war.
38 */ 39 */
39 - public boolean loginUser(UserDto dto) { 40 + public boolean loginUser(UserDto dto, String sessionId) {
40 final User user = dao.findByUsername(dto.getUsername()); 41 final User user = dao.findByUsername(dto.getUsername());
41 - return user != null && user.getProfile().isValidPassword(dto.getPassword()) && sessionContext.login(user); 42 + return user != null
  43 + && user.getProfile().isValidPassword(dto.getPassword())
  44 + && sessionContext.login(user, sessionId);
42 } 45 }
43 46
44 /** 47 /**
src/main/java/net/ziemers/swxercise/ui/UserViewController.java
@@ -5,7 +5,9 @@ import java.util.Collection; @@ -5,7 +5,9 @@ import java.util.Collection;
5 import javax.annotation.security.RolesAllowed; 5 import javax.annotation.security.RolesAllowed;
6 import javax.enterprise.context.ApplicationScoped; 6 import javax.enterprise.context.ApplicationScoped;
7 import javax.inject.Inject; 7 import javax.inject.Inject;
  8 +import javax.servlet.http.HttpServletRequest;
8 import javax.ws.rs.*; 9 import javax.ws.rs.*;
  10 +import javax.ws.rs.core.Context;
9 import javax.ws.rs.core.MediaType; 11 import javax.ws.rs.core.MediaType;
10 12
11 import net.ziemers.swxercise.lg.user.enums.RightState; 13 import net.ziemers.swxercise.lg.user.enums.RightState;
@@ -83,6 +85,7 @@ public class UserViewController { @@ -83,6 +85,7 @@ public class UserViewController {
83 @RolesAllowed(RightState.Constants.LOGGED_IN) 85 @RolesAllowed(RightState.Constants.LOGGED_IN)
84 public User getUser() { 86 public User getUser() {
85 logger.info("Trying to get user's profile info."); 87 logger.info("Trying to get user's profile info.");
  88 +
86 return userService.findUser(); } 89 return userService.findUser(); }
87 90
88 /** 91 /**
@@ -199,6 +202,7 @@ public class UserViewController { @@ -199,6 +202,7 @@ public class UserViewController {
199 * Aufruf: 202 * Aufruf:
200 * POST http://localhost:8080/swxercise/rest/v1/user/login 203 * POST http://localhost:8080/swxercise/rest/v1/user/login
201 * 204 *
  205 + * @param request das {@link HttpServletRequest}-Objekt des augenblicklichen HTTP-Requests
202 * @param dto das mittels der als JSON-Objekt übergebenenen Eigenschaften zu füllende {@link UserDto} 206 * @param dto das mittels der als JSON-Objekt übergebenenen Eigenschaften zu füllende {@link UserDto}
203 * @return ein {@link ResponseState}-Objekt mit den Ergebnisinformationen des Aufrufs. 207 * @return ein {@link ResponseState}-Objekt mit den Ergebnisinformationen des Aufrufs.
204 */ 208 */
@@ -207,10 +211,14 @@ public class UserViewController { @@ -207,10 +211,14 @@ public class UserViewController {
207 @Consumes(MediaType.APPLICATION_JSON) 211 @Consumes(MediaType.APPLICATION_JSON)
208 @Produces(MediaType.APPLICATION_JSON) 212 @Produces(MediaType.APPLICATION_JSON)
209 @RolesAllowed(RightState.Constants.NOT_LOGGED_IN) 213 @RolesAllowed(RightState.Constants.NOT_LOGGED_IN)
210 - public RestResponse loginUser(UserDto dto) {  
211 - logger.info("Trying to log-in user '{}'.", dto.getUsername());  
212 - if (userService.loginUser(dto)) {  
213 - return new RestResponse(); 214 + public RestResponse loginUser(@Context HttpServletRequest request, UserDto dto) {
  215 + // wir benötigen die Session-Id später, um REST-Zugriffe mit WebSockets in Bezug zu bringen
  216 + String sessionId = request.getSession(false).getId();
  217 +
  218 + logger.info("Trying to log-in user '{}' with session id #{}.", dto.getUsername(), sessionId);
  219 +
  220 + if (userService.loginUser(dto, sessionId)) {
  221 + return new RestResponse(sessionId);
214 } 222 }
215 return new RestResponse(ResponseState.FAILED); 223 return new RestResponse(ResponseState.FAILED);
216 } 224 }
@@ -229,6 +237,7 @@ public class UserViewController { @@ -229,6 +237,7 @@ public class UserViewController {
229 @RolesAllowed(RightState.Constants.LOGGED_IN) 237 @RolesAllowed(RightState.Constants.LOGGED_IN)
230 public RestResponse logoutUser() { 238 public RestResponse logoutUser() {
231 logger.info("Trying to log-out user."); 239 logger.info("Trying to log-out user.");
  240 +
232 if (userService.logoutUser()) { 241 if (userService.logoutUser()) {
233 return new RestResponse(); 242 return new RestResponse();
234 } 243 }
src/main/java/net/ziemers/swxercise/ui/utils/RestResponse.java
@@ -21,6 +21,11 @@ public class RestResponse { @@ -21,6 +21,11 @@ public class RestResponse {
21 this.message = message; 21 this.message = message;
22 } 22 }
23 23
  24 + public RestResponse(final String message) {
  25 + this();
  26 + this.message = message;
  27 + }
  28 +
24 public int getResponseCode() { 29 public int getResponseCode() {
25 return responseState.getResponseCode(); 30 return responseState.getResponseCode();
26 } 31 }
src/main/java/net/ziemers/swxercise/ui/ws/WebSocketController.java
@@ -15,8 +15,8 @@ import javax.websocket.server.PathParam; @@ -15,8 +15,8 @@ import javax.websocket.server.PathParam;
15 import javax.websocket.server.ServerEndpoint; 15 import javax.websocket.server.ServerEndpoint;
16 import java.io.IOException; 16 import java.io.IOException;
17 import java.util.Collections; 17 import java.util.Collections;
18 -import java.util.HashSet;  
19 -import java.util.Set; 18 +import java.util.HashMap;
  19 +import java.util.Map;
20 20
21 /** 21 /**
22 * Stub für die WebSocket-Unterstützung. 22 * Stub für die WebSocket-Unterstützung.
@@ -29,11 +29,9 @@ import java.util.Set; @@ -29,11 +29,9 @@ import java.util.Set;
29 decoders = { WebSocketJson.MessageDecoder.class } ) 29 decoders = { WebSocketJson.MessageDecoder.class } )
30 public class WebSocketController { 30 public class WebSocketController {
31 31
32 - static final String serverEndpointPath = "/ws/api/v1/anEndpoint/{aParameter}"; 32 + static final String serverEndpointPath = "/ws/api/v1/anEndpoint/{restSessionid}";
33 33
34 - // Eine Verknüpfung zwischen der WebSocket-Session und dem SessionContext des per REST  
35 - // angemeldeten Benutzers muss irgendwie auch noch realisiert werden. :)  
36 - private static Set<Session> peers = Collections.synchronizedSet(new HashSet<>()); 34 + private static Map<Session, String> peers = Collections.synchronizedMap(new HashMap<>());
37 35
38 private Logger logger; 36 private Logger logger;
39 37
@@ -43,31 +41,37 @@ public class WebSocketController { @@ -43,31 +41,37 @@ public class WebSocketController {
43 } 41 }
44 42
45 /** 43 /**
46 - * Callback-Methode für das Öffnen einer neuen WebSocket-Verbindung. 44 + * Callback-Methode für das Öffnen einer neuen WebSocket-Verbindung. <code>restSessionId</code>
  45 + * wird benötigt, um die WebSocket-Verbindung mit einer REST-Authentifizierung in Bezug bringen
  46 + * zu können.
47 * 47 *
48 - * @param session das {@link Session}-Objekt der neuen WebSocket-Verbindung 48 + * @param wsSession das {@link Session}-Objekt der neuen WebSocket-Verbindung
  49 + * @param restSessionId die Session-Id einer vorangegangenen REST-Authentifizierung
49 */ 50 */
50 @OnOpen 51 @OnOpen
51 - public void onOpen(Session session) {  
52 - logger.info("WebSocket opened with session id #{}", session.getId());  
53 - peers.add(session); 52 + public void onOpen(Session wsSession, @PathParam("restSessionid") String restSessionId) {
  53 + logger.info("WebSocket {} opened with session id #{}", restSessionId, wsSession.getId());
  54 +
  55 + // wir können später über die gegebene WebSocket-Session die REST-Session-Id dieses WebSockets ermitteln
  56 + peers.putIfAbsent(wsSession, restSessionId);
54 } 57 }
55 58
56 /** 59 /**
57 * Callback-Methode, die den Empfang einer neuen WebSocket-Nachricht signalisiert. 60 * Callback-Methode, die den Empfang einer neuen WebSocket-Nachricht signalisiert.
58 * 61 *
59 * @param json der JSON-strukturierte Inhalt der WebSocket-Nachricht 62 * @param json der JSON-strukturierte Inhalt der WebSocket-Nachricht
60 - * @param session das {@link Session}-Objekt der sendenden WebSocket-Verbindung 63 + * @param wsSession das {@link Session}-Objekt der sendenden WebSocket-Verbindung
61 */ 64 */
62 @OnMessage 65 @OnMessage
63 - public void onMessage(WebSocketJson json,  
64 - Session session,  
65 - @PathParam("aParameter") String param) throws IOException, EncodeException {  
66 - logger.info("WebSocket Message '{}/{}' received by session id #{}",  
67 - json.getMessage(), param, session.getId()); 66 + public void onMessage(WebSocketJson json, Session wsSession) throws IOException, EncodeException {
  67 + // die Map liefert uns zur gegebenen WebSocket-Session die REST-Session-Id zurück
  68 + String restSessionId = peers.get(wsSession);
  69 +
  70 + logger.info("WebSocket {} Message '{}' received by session id #{}",
  71 + restSessionId, json.getMessage(), wsSession.getId());
68 try { 72 try {
69 - // Wir senden die empfangene Nachricht gleich wieder zurück. Das Marshalling geschieht automatisch.  
70 - session.getBasicRemote().sendObject(json); 73 + // Wir senden die empfangene Nachricht gleich wieder zurück. Das JSON-Marshalling geschieht automatisch.
  74 + wsSession.getBasicRemote().sendObject(json);
71 } catch (IOException e) { 75 } catch (IOException e) {
72 e.printStackTrace(); 76 e.printStackTrace();
73 } 77 }
@@ -87,12 +91,12 @@ public class WebSocketController { @@ -87,12 +91,12 @@ public class WebSocketController {
87 * Callback-Methode für das Schließen einer geöffneten WebSocket-Verbindung. 91 * Callback-Methode für das Schließen einer geöffneten WebSocket-Verbindung.
88 * 92 *
89 * @param reason die Ursache für das Schließen der WebSocket-Verbindung 93 * @param reason die Ursache für das Schließen der WebSocket-Verbindung
90 - * @param session das {@link Session}-Objekt der geschlossenen WebSocket-Verbindung 94 + * @param wsSession das {@link Session}-Objekt der geschlossenen WebSocket-Verbindung
91 */ 95 */
92 @OnClose 96 @OnClose
93 - public void onClose(CloseReason reason, Session session) {  
94 - logger.info("Closing WebSocket due to '{}' by session id #{}", reason.getReasonPhrase(), session.getId());  
95 - peers.remove(session); 97 + public void onClose(CloseReason reason, Session wsSession) {
  98 + logger.info("Closing WebSocket due to '{}' by session id #{}", reason.getReasonPhrase(), wsSession.getId());
  99 + peers.remove(wsSession);
96 } 100 }
97 101
98 } 102 }
src/main/webapp/websockets.html
@@ -7,7 +7,10 @@ @@ -7,7 +7,10 @@
7 7
8 <body> 8 <body>
9 <script> 9 <script>
10 - var url = "ws://localhost:8080/swxercise/ws/api/v1/anEndpoint/4711"; 10 + // sei "4711" die in einer vorangegangenen REST-Authentifizierung ermittelte "restSessionId"
  11 + var restSessionId = 4711;
  12 +
  13 + var url = "ws://localhost:8080/swxercise/ws/api/v1/anEndpoint/" + restSessionId;
11 var webSocket = new WebSocket(url); 14 var webSocket = new WebSocket(url);
12 15
13 // Callback-Methoden für die WebSocket-Kommunikation 16 // Callback-Methoden für die WebSocket-Kommunikation