MINA(5)CHAT Example
Try to learn from the sample D:\book\mina\apache-mina-2.0.4\src\mina-example
serverContext.xml
ChatProtocolHandler.java
SpringMain.java
SwingChatClient.java
I move them into my project easynio. And make the MINA chat demo and Caculate demo working fine together.
Changes in Spring Configuration:
mina-context.xml
...snip...
<bean id="chatHandler" class="com.sillycat.easynio.plugins.mina.businesshandlers.ChatHandler" />
<bean id="chatAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
destroy-method="unbind" init-method="bind" >
<property name="defaultLocalAddress" value=":12346" />
<property name="handler" ref="chatHandler" />
<property name="reuseAddress" value="true" />
<property name="filterChainBuilder" ref="filterChainBuilder" />
</bean>
I configured the port to 12346 to accept the chat command from the client side.
Some java classes are copied from the sample, I did not change them.
package com.sillycat.easynio.plugins.mina.businesshandlers;
public class ChatCommand {
public static final int LOGIN = 0;
public static final int QUIT = 1;
public static final int BROADCAST = 2;
private final int num;
private ChatCommand(int num) {
this.num = num;
}
public int toInt() {
return num;
}
public static ChatCommand valueOf(String s) {
s = s.toUpperCase();
if ("LOGIN".equals(s)) {
return new ChatCommand(LOGIN);
}
if ("QUIT".equals(s)) {
return new ChatCommand(QUIT);
}
if ("BROADCAST".equals(s)) {
return new ChatCommand(BROADCAST);
}
throw new IllegalArgumentException("Unrecognized command: " + s);
}
}
package com.sillycat.easynio.plugins.mina.businesshandlers;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.logging.MdcInjectionFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ChatHandler extends IoHandlerAdapter {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Set<IoSession> sessions = Collections.synchronizedSet(new HashSet<IoSession>());
private final Set<String> users = Collections.synchronizedSet(new HashSet<String>());
public void exceptionCaught(IoSession session, Throwable cause) {
logger.warn("Unexpected exception.", cause);
session.close(true);
}
public void messageReceived(IoSession session, Object message) {
logger.info("received: " + message);
String theMessage = (String) message;
String[] result = theMessage.split(" ", 2);
String theCommand = result[0];
try {
ChatCommand command = ChatCommand.valueOf(theCommand);
String user = (String) session.getAttribute("user");
switch (command.toInt()) {
case ChatCommand.QUIT:
session.write("QUIT OK");
session.close(true);
break;
case ChatCommand.LOGIN:
if (user != null) {
session.write("LOGIN ERROR user " + user + " already logged in.");
return;
}
if (result.length == 2) {
user = result[1];
} else {
session.write("LOGIN ERROR invalid login command.");
return;
}
// check if the user name is already used
if (users.contains(user)) {
session.write("LOGIN ERROR the name " + user + " is already used.");
return;
}
sessions.add(session);
session.setAttribute("user", user);
MdcInjectionFilter.setProperty(session, "user", user);
// Allow all users
users.add(user);
session.write("LOGIN OK");
broadcast("The user " + user + " has joined the chat session.");
break;
case ChatCommand.BROADCAST:
if (result.length == 2) {
broadcast(user + ": " + result[1]);
}
break;
default:
logger.info("Unhandled command: " + command);
break;
}
} catch (IllegalArgumentException e) {
logger.debug("Illegal argument", e);
}
}
public void broadcast(String message) {
synchronized (sessions) {
for (IoSession session : sessions) {
if (session.isConnected()) {
session.write("BROADCAST OK " + message);
}
}
}
}
public void sessionClosed(IoSession session) throws Exception {
String user = (String) session.getAttribute("user");
users.remove(user);
sessions.remove(session);
broadcast("The user " + user + " has left the chat session.");
}
public boolean isChatUser(String name) {
return users.contains(name);
}
public int getNumberOfUsers() {
return users.size();
}
public void kick(String name) {
synchronized (sessions) {
for (IoSession session : sessions) {
if (name.equals(session.getAttribute("user"))) {
session.close(true);
break;
}
}
}
}
}
After I start the server side, I can use command line to connect to the server side via telnet.
>telnet localhost 12346
>login hello
LOGIN OK
BROADCAST OK The user hello has joined the chat session.
>broadcast I will check the server
BROADCAST OK hello: I will check the server
>quit
QUIT OK
From the mx4j, I can manage my bean via this URL:
http://localhost:8000/mbean?objectname=com.sillycat%3AchatHandler%3DChatHandlerJMX
references:
http://mina.apache.org/user-guide.html
http://blog.csdn.net/xiejn/article/details/789454
http://liangwj72.iteye.com/blog/123842
http://mx4j.sourceforge.net/
http://www.blogjava.net/freeman1984/archive/2011/02/15/344370.html
http://www.mularien.com/blog/2007/11/09/5-minute-guide-to-spring-and-jmx/
http://blog.csdn.net/shirdrn/article/details/6358688
http://topmanopensource.iteye.com/blog/832848
http://topmanopensource.iteye.com/blog/832851
http://topmanopensource.iteye.com/blog/832855
Try to learn from the sample D:\book\mina\apache-mina-2.0.4\src\mina-example
serverContext.xml
ChatProtocolHandler.java
SpringMain.java
SwingChatClient.java
I move them into my project easynio. And make the MINA chat demo and Caculate demo working fine together.
Changes in Spring Configuration:
mina-context.xml
...snip...
<bean id="chatHandler" class="com.sillycat.easynio.plugins.mina.businesshandlers.ChatHandler" />
<bean id="chatAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
destroy-method="unbind" init-method="bind" >
<property name="defaultLocalAddress" value=":12346" />
<property name="handler" ref="chatHandler" />
<property name="reuseAddress" value="true" />
<property name="filterChainBuilder" ref="filterChainBuilder" />
</bean>
I configured the port to 12346 to accept the chat command from the client side.
Some java classes are copied from the sample, I did not change them.
package com.sillycat.easynio.plugins.mina.businesshandlers;
public class ChatCommand {
public static final int LOGIN = 0;
public static final int QUIT = 1;
public static final int BROADCAST = 2;
private final int num;
private ChatCommand(int num) {
this.num = num;
}
public int toInt() {
return num;
}
public static ChatCommand valueOf(String s) {
s = s.toUpperCase();
if ("LOGIN".equals(s)) {
return new ChatCommand(LOGIN);
}
if ("QUIT".equals(s)) {
return new ChatCommand(QUIT);
}
if ("BROADCAST".equals(s)) {
return new ChatCommand(BROADCAST);
}
throw new IllegalArgumentException("Unrecognized command: " + s);
}
}
package com.sillycat.easynio.plugins.mina.businesshandlers;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.logging.MdcInjectionFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ChatHandler extends IoHandlerAdapter {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Set<IoSession> sessions = Collections.synchronizedSet(new HashSet<IoSession>());
private final Set<String> users = Collections.synchronizedSet(new HashSet<String>());
public void exceptionCaught(IoSession session, Throwable cause) {
logger.warn("Unexpected exception.", cause);
session.close(true);
}
public void messageReceived(IoSession session, Object message) {
logger.info("received: " + message);
String theMessage = (String) message;
String[] result = theMessage.split(" ", 2);
String theCommand = result[0];
try {
ChatCommand command = ChatCommand.valueOf(theCommand);
String user = (String) session.getAttribute("user");
switch (command.toInt()) {
case ChatCommand.QUIT:
session.write("QUIT OK");
session.close(true);
break;
case ChatCommand.LOGIN:
if (user != null) {
session.write("LOGIN ERROR user " + user + " already logged in.");
return;
}
if (result.length == 2) {
user = result[1];
} else {
session.write("LOGIN ERROR invalid login command.");
return;
}
// check if the user name is already used
if (users.contains(user)) {
session.write("LOGIN ERROR the name " + user + " is already used.");
return;
}
sessions.add(session);
session.setAttribute("user", user);
MdcInjectionFilter.setProperty(session, "user", user);
// Allow all users
users.add(user);
session.write("LOGIN OK");
broadcast("The user " + user + " has joined the chat session.");
break;
case ChatCommand.BROADCAST:
if (result.length == 2) {
broadcast(user + ": " + result[1]);
}
break;
default:
logger.info("Unhandled command: " + command);
break;
}
} catch (IllegalArgumentException e) {
logger.debug("Illegal argument", e);
}
}
public void broadcast(String message) {
synchronized (sessions) {
for (IoSession session : sessions) {
if (session.isConnected()) {
session.write("BROADCAST OK " + message);
}
}
}
}
public void sessionClosed(IoSession session) throws Exception {
String user = (String) session.getAttribute("user");
users.remove(user);
sessions.remove(session);
broadcast("The user " + user + " has left the chat session.");
}
public boolean isChatUser(String name) {
return users.contains(name);
}
public int getNumberOfUsers() {
return users.size();
}
public void kick(String name) {
synchronized (sessions) {
for (IoSession session : sessions) {
if (name.equals(session.getAttribute("user"))) {
session.close(true);
break;
}
}
}
}
}
After I start the server side, I can use command line to connect to the server side via telnet.
>telnet localhost 12346
>login hello
LOGIN OK
BROADCAST OK The user hello has joined the chat session.
>broadcast I will check the server
BROADCAST OK hello: I will check the server
>quit
QUIT OK
From the mx4j, I can manage my bean via this URL:
http://localhost:8000/mbean?objectname=com.sillycat%3AchatHandler%3DChatHandlerJMX
references:
http://mina.apache.org/user-guide.html
http://blog.csdn.net/xiejn/article/details/789454
http://liangwj72.iteye.com/blog/123842
http://mx4j.sourceforge.net/
http://www.blogjava.net/freeman1984/archive/2011/02/15/344370.html
http://www.mularien.com/blog/2007/11/09/5-minute-guide-to-spring-and-jmx/
http://blog.csdn.net/shirdrn/article/details/6358688
http://topmanopensource.iteye.com/blog/832848
http://topmanopensource.iteye.com/blog/832851
http://topmanopensource.iteye.com/blog/832855