001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.example.chat;
021
022import java.util.Collections;
023import java.util.HashSet;
024import java.util.Set;
025
026import org.apache.mina.core.service.IoHandler;
027import org.apache.mina.core.service.IoHandlerAdapter;
028import org.apache.mina.core.session.IoSession;
029import org.apache.mina.filter.logging.MdcInjectionFilter;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033/**
034 * {@link IoHandler} implementation of a simple chat server protocol.
035 *
036 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
037 */
038public class ChatProtocolHandler extends IoHandlerAdapter {
039    private final static Logger LOGGER = LoggerFactory.getLogger(ChatProtocolHandler.class);
040
041    private final Set<IoSession> sessions = Collections
042            .synchronizedSet(new HashSet<IoSession>());
043
044    private final Set<String> users = Collections
045            .synchronizedSet(new HashSet<String>());
046
047    @Override
048    public void exceptionCaught(IoSession session, Throwable cause) {
049        LOGGER.warn("Unexpected exception.", cause);
050        // Close connection when unexpected exception is caught.
051        session.closeNow();
052    }
053
054    @Override
055    public void messageReceived(IoSession session, Object message) {
056        Logger log = LoggerFactory.getLogger(ChatProtocolHandler.class);
057        log.info("received: " + message);
058        String theMessage = (String) message;
059        String[] result = theMessage.split(" ", 2);
060        String theCommand = result[0];
061
062        try {
063
064            ChatCommand command = ChatCommand.valueOf(theCommand);
065            String user = (String) session.getAttribute("user");
066
067            switch (command.toInt()) {
068
069            case ChatCommand.QUIT:
070                session.write("QUIT OK");
071                session.closeNow();
072                break;
073            case ChatCommand.LOGIN:
074
075                if (user != null) {
076                    session.write("LOGIN ERROR user " + user
077                            + " already logged in.");
078                    return;
079                }
080
081                if (result.length == 2) {
082                    user = result[1];
083                } else {
084                    session.write("LOGIN ERROR invalid login command.");
085                    return;
086                }
087
088                // check if the username is already used
089                if (users.contains(user)) {
090                    session.write("LOGIN ERROR the name " + user
091                            + " is already used.");
092                    return;
093                }
094
095                sessions.add(session);
096                session.setAttribute("user", user);
097                MdcInjectionFilter.setProperty(session, "user", user);
098
099                // Allow all users
100                users.add(user);
101                session.write("LOGIN OK");
102                broadcast("The user " + user + " has joined the chat session.");
103                break;
104
105            case ChatCommand.BROADCAST:
106
107                if (result.length == 2) {
108                    broadcast(user + ": " + result[1]);
109                }
110                break;
111            default:
112                LOGGER.info("Unhandled command: " + command);
113                break;
114            }
115
116        } catch (IllegalArgumentException e) {
117            LOGGER.debug("Illegal argument", e);
118        }
119    }
120
121    public void broadcast(String message) {
122        synchronized (sessions) {
123            for (IoSession session : sessions) {
124                if (session.isConnected()) {
125                    session.write("BROADCAST OK " + message);
126                }
127            }
128        }
129    }
130
131    @Override
132    public void sessionClosed(IoSession session) throws Exception {
133        String user = (String) session.getAttribute("user");
134        users.remove(user);
135        sessions.remove(session);
136        broadcast("The user " + user + " has left the chat session.");
137    }
138
139    public boolean isChatUser(String name) {
140        return users.contains(name);
141    }
142
143    public int getNumberOfUsers() {
144        return users.size();
145    }
146
147    public void kick(String name) {
148        synchronized (sessions) {
149            for (IoSession session : sessions) {
150                if (name.equals(session.getAttribute("user"))) {
151                    session.closeNow();
152                    break;
153                }
154            }
155        }
156    }
157}