Ether Framework
Unified API docs for Ether modules
Loading...
Searching...
No Matches
JettyWebSocketSession.java
Go to the documentation of this file.
1package dev.rafex.ether.websocket.jetty12;
2
3/*-
4 * #%L
5 * ether-websocket-jetty12
6 * %%
7 * Copyright (C) 2025 - 2026 Raúl Eduardo González Argote
8 * %%
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 * #L%
27 */
28
29import java.nio.ByteBuffer;
30import java.util.Collections;
31import java.util.LinkedHashMap;
32import java.util.List;
33import java.util.Map;
34import java.util.Objects;
35import java.util.concurrent.CompletableFuture;
36import java.util.concurrent.CompletionStage;
37import java.util.concurrent.ConcurrentHashMap;
38
39import org.eclipse.jetty.websocket.api.Callback;
40import org.eclipse.jetty.websocket.api.Session;
41
42import dev.rafex.ether.websocket.core.WebSocketCloseStatus;
43import dev.rafex.ether.websocket.core.WebSocketSession;
44
45public final class JettyWebSocketSession implements WebSocketSession {
46
47 private final Session session;
48 private final String path;
49 private final Map<String, String> pathParams;
50 private final Map<String, List<String>> queryParams;
51 private final Map<String, List<String>> headers;
52 private final Map<String, Object> attributes = new ConcurrentHashMap<>();
53
54 public JettyWebSocketSession(final Session session, final String path, final Map<String, String> pathParams,
55 final Map<String, List<String>> queryParams, final Map<String, List<String>> headers) {
56 this.session = Objects.requireNonNull(session, "session");
57 this.path = Objects.requireNonNull(path, "path");
58 this.pathParams = Map.copyOf(pathParams);
59 this.queryParams = copyMultiMap(queryParams);
60 this.headers = copyMultiMap(headers);
61 }
62
63 @Override
64 public String id() {
65 return Integer.toHexString(System.identityHashCode(session));
66 }
67
68 @Override
69 public String path() {
70 return path;
71 }
72
73 @Override
74 public String subprotocol() {
75 final var protocol = session.getUpgradeResponse() == null ? null : session.getUpgradeResponse().getAcceptedSubProtocol();
76 return protocol == null ? "" : protocol;
77 }
78
79 @Override
80 public boolean isOpen() {
81 return session.isOpen();
82 }
83
84 @Override
85 public String pathParam(final String name) {
86 return pathParams.get(name);
87 }
88
89 @Override
90 public String queryFirst(final String name) {
91 final var values = queryParams.get(name);
92 if (values == null || values.isEmpty()) {
93 return null;
94 }
95 return values.get(0);
96 }
97
98 @Override
99 public List<String> queryAll(final String name) {
100 return queryParams.getOrDefault(name, List.of());
101 }
102
103 @Override
104 public String headerFirst(final String name) {
105 final var values = headers.get(name);
106 if (values == null || values.isEmpty()) {
107 return null;
108 }
109 return values.get(0);
110 }
111
112 @Override
113 public Object attribute(final String name) {
114 return attributes.get(name);
115 }
116
117 @Override
118 public void attribute(final String name, final Object value) {
119 if (value == null) {
120 attributes.remove(name);
121 return;
122 }
123 attributes.put(name, value);
124 }
125
126 @Override
127 public Map<String, String> pathParams() {
128 return pathParams;
129 }
130
131 @Override
132 public Map<String, List<String>> queryParams() {
133 return queryParams;
134 }
135
136 @Override
137 public Map<String, List<String>> headers() {
138 return headers;
139 }
140
141 @Override
142 public CompletionStage<Void> sendText(final String text) {
143 final var future = new CompletableFuture<Void>();
144 session.sendText(text, callbackOf(future));
145 return future;
146 }
147
148 @Override
149 public CompletionStage<Void> sendBinary(final ByteBuffer data) {
150 final var future = new CompletableFuture<Void>();
151 session.sendBinary(data == null ? ByteBuffer.allocate(0) : data.slice(), callbackOf(future));
152 return future;
153 }
154
155 @Override
156 public CompletionStage<Void> close(final WebSocketCloseStatus status) {
157 final var future = new CompletableFuture<Void>();
158 final var closeStatus = status == null ? WebSocketCloseStatus.NORMAL : status;
159 session.close(closeStatus.code(), closeStatus.reason(), callbackOf(future));
160 return future;
161 }
162
163 private static Callback callbackOf(final CompletableFuture<Void> future) {
164 return Callback.from(() -> future.complete(null), future::completeExceptionally);
165 }
166
167 private static Map<String, List<String>> copyMultiMap(final Map<String, List<String>> input) {
168 final var out = new LinkedHashMap<String, List<String>>();
169 if (input != null) {
170 for (final var entry : input.entrySet()) {
171 out.put(entry.getKey(), entry.getValue() == null ? List.of() : List.copyOf(entry.getValue()));
172 }
173 }
174 return Collections.unmodifiableMap(out);
175 }
176}
CompletionStage< Void > sendBinary(final ByteBuffer data)
CompletionStage< Void > close(final WebSocketCloseStatus status)
JettyWebSocketSession(final Session session, final String path, final Map< String, String > pathParams, final Map< String, List< String > > queryParams, final Map< String, List< String > > headers)
void attribute(final String name, final Object value)