Line 0
Link Here
|
|
|
1 |
/* |
2 |
* Licensed to the Apache Software Foundation (ASF) under one or more |
3 |
* contributor license agreements. See the NOTICE file distributed with |
4 |
* this work for additional information regarding copyright ownership. |
5 |
* The ASF licenses this file to You under the Apache License, Version 2.0 |
6 |
* (the "License"); you may not use this file except in compliance with |
7 |
* the License. You may obtain a copy of the License at |
8 |
* |
9 |
* http://www.apache.org/licenses/LICENSE-2.0 |
10 |
* |
11 |
* Unless required by applicable law or agreed to in writing, software |
12 |
* distributed under the License is distributed on an "AS IS" BASIS, |
13 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 |
* See the License for the specific language governing permissions and |
15 |
* limitations under the License. |
16 |
*/ |
17 |
package websocket.chat; |
18 |
|
19 |
import org.apache.catalina.websocket.MessageInbound; |
20 |
import org.apache.catalina.websocket.StreamInbound; |
21 |
import org.apache.catalina.websocket.WebSocketServlet; |
22 |
import org.apache.catalina.websocket.WsOutbound; |
23 |
import util.HTMLFilter; |
24 |
|
25 |
import java.io.IOException; |
26 |
import java.nio.ByteBuffer; |
27 |
import java.nio.CharBuffer; |
28 |
import java.util.Set; |
29 |
import java.util.concurrent.CopyOnWriteArraySet; |
30 |
import java.util.concurrent.atomic.AtomicInteger; |
31 |
|
32 |
/** |
33 |
* Example web socket servlet for chat. |
34 |
*/ |
35 |
public class ChatWebSocketServlet extends WebSocketServlet { |
36 |
|
37 |
private static final long serialVersionUID = 1L; |
38 |
|
39 |
private static final String GUEST_PREFIX = "Guest"; |
40 |
|
41 |
private final AtomicInteger connectionIds = new AtomicInteger(0); |
42 |
private final Set<ChatMessageInbound> connections = |
43 |
new CopyOnWriteArraySet<ChatMessageInbound>(); |
44 |
|
45 |
@Override |
46 |
protected StreamInbound createWebSocketInbound(String subProtocol) { |
47 |
return new ChatMessageInbound(connectionIds.incrementAndGet()); |
48 |
} |
49 |
|
50 |
private final class ChatMessageInbound extends MessageInbound { |
51 |
|
52 |
private final String nickname; |
53 |
|
54 |
private ChatMessageInbound(int id) { |
55 |
this.nickname = GUEST_PREFIX + id; |
56 |
} |
57 |
|
58 |
@Override |
59 |
protected void onOpen(WsOutbound outbound) { |
60 |
connections.add(this); |
61 |
String message = String.format("* %s %s", |
62 |
nickname, "has joined."); |
63 |
broadcast(message); |
64 |
} |
65 |
|
66 |
@Override |
67 |
protected void onClose(int status) { |
68 |
connections.remove(this); |
69 |
String message = String.format("* %s %s", |
70 |
nickname, "has disconnected."); |
71 |
broadcast(message); |
72 |
} |
73 |
|
74 |
@Override |
75 |
protected void onBinaryMessage(ByteBuffer message) throws IOException { |
76 |
throw new UnsupportedOperationException( |
77 |
"Binary message not supported."); |
78 |
} |
79 |
|
80 |
@Override |
81 |
protected void onTextMessage(CharBuffer message) throws IOException { |
82 |
// Never trust the client |
83 |
String filteredMessage = String.format("%s: %s", |
84 |
nickname, HTMLFilter.filter(message.toString())); |
85 |
broadcast(filteredMessage); |
86 |
} |
87 |
|
88 |
private void broadcast(String message) { |
89 |
for (ChatMessageInbound connection : connections) { |
90 |
try { |
91 |
CharBuffer buffer = CharBuffer.wrap(message); |
92 |
connection.getWsOutbound().writeTextMessage(buffer); |
93 |
} catch (IOException ignore) { |
94 |
// Ignore |
95 |
} |
96 |
} |
97 |
} |
98 |
} |
99 |
} |