@@ -0,0 +1,3450 @@
+/*%0A *  Licensed to the Apache Software Foundation (ASF) under one or more%0A *  contributor license agreements.  See the NOTICE file distributed with%0A *  this work for additional information regarding copyright ownership.%0A *  The ASF licenses this file to You under the Apache License, Version 2.0%0A *  (the %22License%22); you may not use this file except in compliance with%0A *  the License.  You may obtain a copy of the License at%0A *%0A *      http://www.apache.org/licenses/LICENSE-2.0%0A *%0A *  Unless required by applicable law or agreed to in writing, software%0A *  distributed under the License is distributed on an %22AS IS%22 BASIS,%0A *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.%0A *  See the License for the specific language governing permissions and%0A *  limitations under the License.%0A */%0Apackage websocket.chat;%0A%0Aimport java.io.IOException;%0Aimport java.util.Set;%0Aimport java.util.concurrent.CopyOnWriteArraySet;%0Aimport java.util.concurrent.atomic.AtomicInteger;%0A%0Aimport javax.websocket.OnClose;%0Aimport javax.websocket.OnError;%0Aimport javax.websocket.OnMessage;%0Aimport javax.websocket.OnOpen;%0Aimport javax.websocket.Session;%0Aimport javax.websocket.server.ServerEndpoint;%0A%0Aimport org.apache.juli.logging.Log;%0Aimport org.apache.juli.logging.LogFactory;%0A%0Aimport util.HTMLFilter;%0A%0A@ServerEndpoint(value = %22/websocket/chat%22)%0Apublic class ChatAnnotation %7B%0A%0A    private static final Log log = LogFactory.getLog(ChatAnnotation.class);%0A%0A    private static final String GUEST_PREFIX = %22Guest%22;%0A    private static final AtomicInteger connectionIds = new AtomicInteger(0);%0A    private static final Set%3CChatAnnotation%3E connections =%0A            new CopyOnWriteArraySet%3CChatAnnotation%3E();%0A%0A    private final String nickname;%0A    private Session session;%0A%0A    public ChatAnnotation() %7B%0A        nickname = GUEST_PREFIX + connectionIds.getAndIncrement();%0A    %7D%0A%0A%0A    @OnOpen%0A    public void start(Session session) %7B%0A        this.session = session;%0A        connections.add(this);%0A        String message = String.format(%22* %25s %25s%22, nickname, %22has joined.%22);%0A        broadcast(message);%0A    %7D%0A%0A%0A    @OnClose%0A    public void end() %7B%0A        connections.remove(this);%0A        String message = String.format(%22* %25s %25s%22,%0A                nickname, %22has disconnected.%22);%0A        broadcast(message);%0A    %7D%0A%0A%0A    @OnMessage%0A    public void incoming(String message) %7B%0A        // Never trust the client%0A        String filteredMessage = String.format(%22%25s: %25s%22,%0A                nickname, HTMLFilter.filter(message.toString()));%0A        broadcast(filteredMessage);%0A    %7D%0A%0A%0A%0A%0A    @OnError%0A    public void onError(Throwable t) throws Throwable %7B%0A        log.error(%22Chat Error: %22 + t.toString(), t);%0A    %7D%0A%0A%0A    private static void broadcast(String msg) %7B%0A        for (ChatAnnotation client : connections) %7B%0A            try %7B%0A                synchronized (client) %7B%0A                    client.session.getBasicRemote().sendText(msg);%0A                %7D%0A            %7D catch (IOException e) %7B%0A                log.debug(%22Chat Error: Failed to send message to client%22, e);%0A                connections.remove(client);%0A                try %7B%0A                    client.session.close();%0A                %7D catch (IOException e1) %7B%0A                    // Ignore%0A                %7D%0A                String message = String.format(%22* %25s %25s%22,%0A                        client.nickname, %22has been disconnected.%22);%0A                broadcast(message);%0A            %7D%0A        %7D%0A    %7D%0A%7D%0A%0A

Create ChatAnnotation.java