1.优化 cim 的android sdk,大幅提高长连接的存活率

2.大幅优化服务端的长连接管理,最短的时间获知客户端的连接状态
3.优化mina版 工程代码结构,更加清晰
4.更新了相关文档
This commit is contained in:
远方夕阳 2015-10-26 15:44:00 +08:00
parent 7b1519ea70
commit e49d5ea415
611 changed files with 2675 additions and 2903 deletions

Binary file not shown.

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="C:/dev/Android-SDK-Windows/platforms/android-19/android.jar"/>
<classpathentry kind="lib" path="D:/cim-system/cim-server/WebRoot/WEB-INF/lib/log4j.jar"/>
<classpathentry kind="lib" path="D:/cim-system/cim-server/WebRoot/WEB-INF/lib/mina-core-2.0.9.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>cim-android-sdk</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.genuitec.eclipse.ast.deploy.core.DeploymentBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.genuitec.eclipse.ast.deploy.core.deploymentnature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,3 @@
#Wed Oct 15 09:31:41 CST 2014
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -1,12 +1,14 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android; package com.farsunset.cim.client.android;
import android.content.Context; import android.content.Context;
/**
* class CIMCacheTools {
* @author 3979434
*
*/
class CIMDataConfig {
public static String CIM_CONFIG_INFO = "CIM_CONFIG_INFO"; public static String CIM_CONFIG_INFO = "CIM_CONFIG_INFO";

View File

@ -1,26 +1,40 @@
package com.farsunset.cim.client.android; /**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.mina.core.future.ConnectFuture; import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.future.WriteFuture; import org.apache.mina.core.future.WriteFuture;
import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LoggingFilter; import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector; import org.apache.mina.transport.socket.nio.NioSocketConnector;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import com.farsunset.cim.nio.constant.CIMConstant; import android.util.Log;
import com.farsunset.cim.nio.filter.ClientMessageCodecFactory;
import com.farsunset.cim.nio.mutual.Message; import com.farsunset.cim.client.constant.CIMConstant;
import com.farsunset.cim.nio.mutual.ReplyBody; import com.farsunset.cim.client.exception.CIMSessionDisableException;
import com.farsunset.cim.nio.mutual.SentBody; import com.farsunset.cim.client.exception.NetWorkDisableException;
import com.farsunset.cim.client.exception.WriteToClosedSessionException;
import com.farsunset.cim.client.filter.ClientMessageCodecFactory;
import com.farsunset.cim.client.model.Message;
import com.farsunset.cim.client.model.ReplyBody;
import com.farsunset.cim.client.model.SentBody;
/** /**
* 连接服务端管理cim核心处理类管理连接以及消息处理 * 连接服务端管理cim核心处理类管理连接以及消息处理
@ -29,9 +43,9 @@ import com.farsunset.cim.nio.mutual.SentBody;
*/ */
class CIMConnectorManager { class CIMConnectorManager {
final static String TAG = CIMConnectorManager.class.getSimpleName();
private NioSocketConnector connector; private NioSocketConnector connector;
private ConnectFuture connectFuture; private ConnectFuture connectFuture;
private IoSession session;
Context context; Context context;
@ -66,18 +80,23 @@ class CIMConnectorManager {
private ExecutorService executor; private ExecutorService executor;
private CIMConnectorManager(Context ctx) { private CIMConnectorManager(Context ctx) {
context = ctx; context = ctx;
executor = Executors.newFixedThreadPool(3); executor = Executors.newFixedThreadPool(3);
connector = new NioSocketConnector(); connector = new NioSocketConnector();
connector.setConnectTimeoutMillis(10 * 1000); connector.setConnectTimeoutMillis(10 * 1000);
connector.getSessionConfig().setBothIdleTime(180); connector.getSessionConfig().setTcpNoDelay(true);
connector.getSessionConfig().setKeepAlive(true); connector.getSessionConfig().setReadBufferSize(2048);
connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ClientMessageCodecFactory())); connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ClientMessageCodecFactory()));
KeepAliveFilter keepAliveaHandler = new KeepAliveFilter(new ClientKeepAliveFactoryImpl(), IdleStatus.BOTH_IDLE);
keepAliveaHandler.setForwardEvent(true);
connector.getFilterChain().addLast("heartbeat", keepAliveaHandler);
connector.setHandler(iohandler); connector.setHandler(iohandler);
} }
public synchronized static CIMConnectorManager getManager(Context context) { public synchronized static CIMConnectorManager getManager(Context context) {
@ -94,12 +113,10 @@ class CIMConnectorManager {
if(isConnected()){ if(isConnected()){
return ; return ;
} }
InetSocketAddress remoteSocketAddress = new InetSocketAddress(cimServerHost, cimServerPort); InetSocketAddress remoteSocketAddress = new InetSocketAddress(cimServerHost, cimServerPort);
connectFuture = connector.connect(remoteSocketAddress); connectFuture = connector.connect(remoteSocketAddress);
connectFuture.awaitUninterruptibly(); connectFuture.awaitUninterruptibly();
session = connectFuture.getSession(); connectFuture.getSession();
} catch (Exception e) { } catch (Exception e) {
Intent intent = new Intent(); Intent intent = new Intent();
@ -107,7 +124,7 @@ class CIMConnectorManager {
intent.putExtra("exception", e); intent.putExtra("exception", e);
context.sendBroadcast(intent); context.sendBroadcast(intent);
System.out.println("******************CIM连接服务器失败 "+cimServerHost+":"+cimServerPort); Log.i(TAG, "******************CIM连接服务器失败 "+cimServerHost+":"+cimServerPort);
} }
@ -126,8 +143,8 @@ class CIMConnectorManager {
return; return;
} }
Future<?> future = executor.submit(new Runnable() { Future<?> future = executor.submit(new Runnable() {
@Override @Override
public void run() { public void run() {
syncConnection(cimServerHost, cimServerPort); syncConnection(cimServerHost, cimServerPort);
} }
@ -142,6 +159,8 @@ class CIMConnectorManager {
connect(cimServerHost,cimServerPort); connect(cimServerHost,cimServerPort);
e.printStackTrace(); e.printStackTrace();
} }
} }
public void send(final SentBody body) { public void send(final SentBody body) {
@ -154,6 +173,7 @@ class CIMConnectorManager {
android.os.Message msg = new android.os.Message(); android.os.Message msg = new android.os.Message();
msg.getData().putSerializable("body", body); msg.getData().putSerializable("body", body);
IoSession session = getCurrentSession();
if(session!=null && session.isConnected()) if(session!=null && session.isConnected())
{ {
WriteFuture wf = session.write(body); WriteFuture wf = session.write(body);
@ -183,19 +203,21 @@ class CIMConnectorManager {
} }
public void destroy() { public void destroy() {
if (manager.session != null) { IoSession session = getCurrentSession();
manager.session.close(false); if (session != null) {
manager.session.removeAttribute("account"); session.close(false);
session.removeAttribute("account");
} }
if (manager.connector != null && !manager.connector.isDisposed()) { if (connector != null && !connector.isDisposed()) {
manager.connector.dispose(); connector.dispose();
} }
manager = null; manager = null;
} }
public boolean isConnected() { public boolean isConnected() {
if (session == null || connector == null) { IoSession session = getCurrentSession();
if (session == null ) {
return false; return false;
} }
return session.isConnected() ; return session.isConnected() ;
@ -212,19 +234,33 @@ class CIMConnectorManager {
public void closeSession() public void closeSession()
{ {
IoSession session = getCurrentSession();
if(session!=null) if(session!=null)
{ {
session.close(false); session.close(false);
} }
} }
public IoSession getCurrentSession()
{
if(connector.getManagedSessionCount()>0)
{
for(Long key:connector.getManagedSessions().keySet())
{
return connector.getManagedSessions().get(key);
}
}
return null;
}
IoHandlerAdapter iohandler = new IoHandlerAdapter() { IoHandlerAdapter iohandler = new IoHandlerAdapter() {
@Override @Override
public void sessionCreated(IoSession session) throws Exception { public void sessionCreated(IoSession session) throws Exception {
System.out.println("******************CIM连接服务器成功:"+session.getLocalAddress());
Log.i(TAG, "******************CIM连接服务器成功:"+session.getLocalAddress());
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_CONNECTION_SUCCESS); intent.setAction(ACTION_CONNECTION_SUCCESS);
@ -240,25 +276,19 @@ class CIMConnectorManager {
@Override @Override
public void sessionClosed(IoSession session) throws Exception { public void sessionClosed(IoSession session) throws Exception {
System.out.println("******************CIM与服务器断开连接:"+session.getLocalAddress()); Log.i(TAG, "******************CIM与服务器断开连接:"+session.getLocalAddress());
if(CIMConnectorManager.this.session.getId()==session.getId())
{
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_CONNECTION_CLOSED); intent.setAction(ACTION_CONNECTION_CLOSED);
context.sendBroadcast(intent); context.sendBroadcast(intent);
}
} }
@Override @Override
public void sessionIdle(IoSession session, IdleStatus status) public void sessionIdle(IoSession session, IdleStatus status)
throws Exception { throws Exception {
System.out.println("******************CIM与服务器连接空闲:"+session.getLocalAddress()); Log.i(TAG, "******************CIM与服务器连接空闲:"+session.getLocalAddress());
SentBody sent = new SentBody();
sent.setKey(CIMConstant.RequestKey.CLIENT_HEARTBEAT);
send(sent);
} }
@Override @Override
@ -294,15 +324,14 @@ class CIMConnectorManager {
} }
@Override @Override
public void messageSent(IoSession session, Object message) public void messageSent(IoSession session, Object message) throws Exception {
throws Exception { if(message instanceof SentBody)
{
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_SENT_SUCCESS); intent.setAction(ACTION_SENT_SUCCESS);
intent.putExtra("sentBody", (SentBody) message); intent.putExtra("sentBody", (SentBody) message);
context.sendBroadcast(intent); context.sendBroadcast(intent);
}
} }
}; };
@ -316,5 +345,27 @@ class CIMConnectorManager {
return false; return false;
} }
public class ClientKeepAliveFactoryImpl implements KeepAliveMessageFactory {
@Override
public Object getRequest(IoSession arg0) {
return null;
}
@Override
public Object getResponse(IoSession arg0, Object arg1) {
return CIMConstant.CMD_HEARTBEAT_RESPONSE;
}
@Override
public boolean isRequest(IoSession arg0, Object arg1) {
return CIMConstant.CMD_HEARTBEAT_REQUEST.equals(arg1);
}
@Override
public boolean isResponse(IoSession arg0, Object arg1) {
return false;
}
}
} }

View File

@ -1,3 +1,9 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android; package com.farsunset.cim.client.android;
import java.util.List; import java.util.List;
@ -10,16 +16,16 @@ import android.content.Intent;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Handler; import android.os.Handler;
import com.farsunset.cim.nio.constant.CIMConstant;
import com.farsunset.cim.nio.mutual.Message; import com.farsunset.cim.client.constant.CIMConstant;
import com.farsunset.cim.nio.mutual.ReplyBody; import com.farsunset.cim.client.exception.CIMSessionDisableException;
import com.farsunset.cim.nio.mutual.SentBody; import com.farsunset.cim.client.model.Message;
import com.farsunset.cim.client.model.ReplyBody;
import com.farsunset.cim.client.model.SentBody;
/** /**
* 消息入口所有消息都会经过这里 * 消息入口所有消息都会经过这里
* @author 3979434
*
*/ */
public abstract class CIMEnventListenerReceiver extends BroadcastReceiver implements OnCIMMessageListener { public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver implements CIMEventListener {
public Context context; public Context context;
@ -28,74 +34,112 @@ public abstract class CIMEnventListenerReceiver extends BroadcastReceiver impl
context = ctx; context = ctx;
/*
* 操作事件广播用于提高service存活率
*/
if(it.getAction().equals(Intent.ACTION_USER_PRESENT)
||it.getAction().equals(Intent.ACTION_POWER_CONNECTED)
||it.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)
)
{
startPushService();
}
/*
* 设备网络状态变化事件
*/
if(it.getAction().equals(CIMConnectorManager.ACTION_NETWORK_CHANGED)) if(it.getAction().equals(CIMConnectorManager.ACTION_NETWORK_CHANGED))
{ {
ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService("connectivity"); ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
android.net.NetworkInfo info = connectivityManager.getActiveNetworkInfo(); android.net.NetworkInfo info = connectivityManager.getActiveNetworkInfo();
onDevicesNetworkChanged(info); onDevicesNetworkChanged(info);
} }
/*
* cim断开服务器事件
*/
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_CLOSED)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_CLOSED))
{ {
dispatchConnectionClosed(); if(CIMConnectorManager.netWorkAvailable(context))
{
CIMPushManager.init(context);
}
onCIMConnectionClosed();
} }
/*
* cim连接服务器失败事件
*/
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_FAILED)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_FAILED))
{ {
onConnectionFailed((Exception) it.getSerializableExtra("exception")); onConnectionFailed((Exception) it.getSerializableExtra("exception"));
} }
/*
* cim连接服务器成功事件
*/
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_SUCCESS)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_SUCCESS))
{ {
dispatchConnectionSucceed();
CIMPushManager.bindAccount(context);
onCIMConnectionSucceed();
} }
/*
* 收到推送消息事件
*/
if(it.getAction().equals(CIMConnectorManager.ACTION_MESSAGE_RECEIVED)) if(it.getAction().equals(CIMConnectorManager.ACTION_MESSAGE_RECEIVED))
{ {
filterType999Message((Message)it.getSerializableExtra("message")); filterType999Message((Message)it.getSerializableExtra("message"));
} }
/*
* 获取收到replybody成功事件
*/
if(it.getAction().equals(CIMConnectorManager.ACTION_REPLY_RECEIVED)) if(it.getAction().equals(CIMConnectorManager.ACTION_REPLY_RECEIVED))
{ {
onReplyReceived((ReplyBody)it.getSerializableExtra("replyBody")); onReplyReceived((ReplyBody)it.getSerializableExtra("replyBody"));
} }
/*
* 获取sendbody发送失败事件
*/
if(it.getAction().equals(CIMConnectorManager.ACTION_SENT_FAILED)) if(it.getAction().equals(CIMConnectorManager.ACTION_SENT_FAILED))
{ {
onSentFailed((Exception) it.getSerializableExtra("exception"),(SentBody)it.getSerializableExtra("sentBody")); onSentFailed((Exception) it.getSerializableExtra("exception"),(SentBody)it.getSerializableExtra("sentBody"));
} }
/*
* 获取sendbody发送成功事件
*/
if(it.getAction().equals(CIMConnectorManager.ACTION_SENT_SUCCESS)) if(it.getAction().equals(CIMConnectorManager.ACTION_SENT_SUCCESS))
{ {
onSentSucceed((SentBody)it.getSerializableExtra("sentBody")); onSentSucceed((SentBody)it.getSerializableExtra("sentBody"));
} }
/*
* 获取cim数据传输异常事件
*/
if(it.getAction().equals(CIMConnectorManager.ACTION_UNCAUGHT_EXCEPTION)) if(it.getAction().equals(CIMConnectorManager.ACTION_UNCAUGHT_EXCEPTION))
{ {
onUncaughtException((Exception)it.getSerializableExtra("exception")); onUncaughtException((Exception)it.getSerializableExtra("exception"));
} }
/*
* 获取cim连接状态事件
*/
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_STATUS)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_STATUS))
{ {
onConnectionStatus(it.getBooleanExtra(CIMPushManager.KEY_CIM_CONNECTION_STATUS, false)); onConnectionStatus(it.getBooleanExtra(CIMPushManager.KEY_CIM_CONNECTION_STATUS, false));
} }
} }
private void dispatchConnectionClosed() {
if(CIMConnectorManager.netWorkAvailable(context))
{
CIMPushManager.init(context);
}
onConnectionClosed();
}
protected boolean isInBackground(Context context) { protected boolean isInBackground(Context context) {
List<RunningTaskInfo> tasksInfo = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1); List<RunningTaskInfo> tasksInfo = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1);
if (tasksInfo.size() > 0) { if (tasksInfo.size() > 0) {
@ -109,7 +153,18 @@ public abstract class CIMEnventListenerReceiver extends BroadcastReceiver impl
return true; return true;
} }
private void onConnectionFailed(Exception e){
private void startPushService()
{
Intent intent = new Intent(context, CIMPushService.class);
intent.putExtra(CIMPushManager.SERVICE_ACTION, CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE);
context.startService(intent);
}
private void onConnectionFailed(Exception e){
if(CIMConnectorManager.netWorkAvailable(context)) if(CIMConnectorManager.netWorkAvailable(context))
{ {
@ -129,13 +184,6 @@ public abstract class CIMEnventListenerReceiver extends BroadcastReceiver impl
}; };
private void dispatchConnectionSucceed() {
CIMPushManager.setAccount(context);
onConnectionSucceed();
}
private void onUncaughtException(Throwable arg0) {} private void onUncaughtException(Throwable arg0) {}
@ -152,11 +200,11 @@ public abstract class CIMEnventListenerReceiver extends BroadcastReceiver impl
onNetworkChanged(info); onNetworkChanged(info);
} }
private void filterType999Message(com.farsunset.cim.nio.mutual.Message message) private void filterType999Message(com.farsunset.cim.client.model.Message message)
{ {
if(CIMConstant.MessageType.TYPE_999.equals(message.getType())) if(CIMConstant.MessageType.TYPE_999.equals(message.getType()))
{ {
CIMDataConfig.putBoolean(context,CIMDataConfig.KEY_MANUAL_STOP,true); CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP,true);
} }
onMessageReceived(message); onMessageReceived(message);
@ -179,10 +227,13 @@ public abstract class CIMEnventListenerReceiver extends BroadcastReceiver impl
private void onSentSucceed(SentBody body){} private void onSentSucceed(SentBody body){}
@Override @Override
public abstract void onMessageReceived(com.farsunset.cim.nio.mutual.Message message); public abstract void onMessageReceived(com.farsunset.cim.client.model.Message message);
@Override @Override
public abstract void onReplyReceived(ReplyBody body); public abstract void onReplyReceived(ReplyBody body);
public abstract void onNetworkChanged(NetworkInfo info); public abstract void onNetworkChanged(NetworkInfo info);
public abstract void onCIMConnectionSucceed();
public abstract void onCIMConnectionClosed();
} }

View File

@ -1,23 +1,20 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android; package com.farsunset.cim.client.android;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import com.farsunset.cim.nio.mutual.Message; import com.farsunset.cim.client.model.Message;
import com.farsunset.cim.nio.mutual.ReplyBody; import com.farsunset.cim.client.model.ReplyBody;
/** /**
*CIM 主要事件接口 *CIM 主要事件接口
* 类名称OnCIMMessageListener
* 类描述
* 创建人 3979434
* 修改人 3979434
* 修改时间 2014-4-28 下午5:07:47
* 修改备注
* @version 1.0.0
*
*/ */
public interface OnCIMMessageListener public interface CIMEventListener
{ {
@ -25,36 +22,36 @@ public interface OnCIMMessageListener
* 当收到服务端推送过来的消息时调用 * 当收到服务端推送过来的消息时调用
* @param message * @param message
*/ */
public abstract void onMessageReceived(Message message); public void onMessageReceived(Message message);
/** /**
* 当调用CIMPushManager.sendRequest()向服务端发送请求获得相应时调用 * 当调用CIMPushManager.sendRequest()向服务端发送请求获得相应时调用
* @param replybody * @param replybody
*/ */
public abstract void onReplyReceived(ReplyBody replybody); public void onReplyReceived(ReplyBody replybody);
/** /**
* 当手机网络发生变化时调用 * 当手机网络发生变化时调用
* @param networkinfo * @param networkinfo
*/ */
public abstract void onNetworkChanged(NetworkInfo networkinfo); public void onNetworkChanged(NetworkInfo networkinfo);
/** /**
* 获取到是否连接到服务端 * 获取到是否连接到服务端
* 通过调用CIMPushManager.detectIsConnected()来异步获取 * 通过调用CIMPushManager.detectIsConnected()来异步获取
* *
*/ */
public abstract void onConnectionStatus(boolean isConnected); public void onConnectionStatus(boolean isConnected);
/** /**
* 连接服务端成功 * 连接服务端成功
*/ */
public abstract void onConnectionSucceed(); public void onCIMConnectionSucceed();
/** /**
* 连接断开 * 连接断开
*/ */
public abstract void onConnectionClosed(); public void onCIMConnectionClosed();
} }

View File

@ -0,0 +1,101 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import com.farsunset.cim.client.constant.CIMConstant;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
/**
* CIM 消息监听器管理
*/
public class CIMListenerManager {
private static ArrayList<CIMEventListener> cimListeners = new ArrayList<CIMEventListener>();
public static void registerMessageListener(CIMEventListener listener,Context mcontext) {
if (!cimListeners.contains(listener)) {
cimListeners.add(listener);
// 按照接收顺序倒序
Collections.sort(cimListeners, new CIMMessageReceiveComparator(mcontext));
}
}
public static void removeMessageListener(CIMEventListener listener) {
for (int i = 0; i < cimListeners.size(); i++) {
if (listener.getClass() == cimListeners.get(i).getClass()) {
cimListeners.remove(i);
}
}
}
public static ArrayList<CIMEventListener> getCIMListeners() {
return cimListeners;
}
/**
* 消息接收activity的接收顺序排序CIM_RECEIVE_ORDER倒序
*/
static class CIMMessageReceiveComparator implements Comparator<CIMEventListener>{
Context mcontext;
public CIMMessageReceiveComparator(Context ctx)
{
mcontext = ctx;
}
@Override
public int compare(CIMEventListener arg1, CIMEventListener arg2) {
Integer order1 = CIMConstant.CIM_DEFAULT_MESSAGE_ORDER;
Integer order2 = CIMConstant.CIM_DEFAULT_MESSAGE_ORDER;
ActivityInfo info;
if (arg1 instanceof Activity ) {
try {
info = mcontext.getPackageManager() .getActivityInfo(((Activity)(arg1)).getComponentName(), PackageManager.GET_META_DATA);
if(info.metaData!=null)
{
order1 = info.metaData.getInt("CIM_RECEIVE_ORDER");
}
} catch (Exception e) {}
}
if (arg1 instanceof Activity ) {
try {
info = mcontext.getPackageManager() .getActivityInfo(((Activity)(arg2)).getComponentName(), PackageManager.GET_META_DATA);
if(info.metaData!=null)
{
order2 = info.metaData.getInt("CIM_RECEIVE_ORDER");
}
} catch (Exception e) {}
}
return order2.compareTo(order1);
}
}
}

View File

@ -1,19 +1,27 @@
package com.farsunset.cim.client.android;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import java.util.UUID;
import com.farsunset.cim.nio.constant.CIMConstant;
import com.farsunset.cim.nio.mutual.SentBody;
/** /**
* CIM 功能接口 * probject:cim-android-sdk
* @version 2.0.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.android;
import java.util.UUID;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.telephony.TelephonyManager;
import com.farsunset.cim.client.constant.CIMConstant;
import com.farsunset.cim.client.model.SentBody;
/**
* CIM 功能接口
*/
public class CIMPushManager { public class CIMPushManager {
static String ACTION_CONNECTION_KEEPALIVE ="ACTION_CONNECTION_KEEPALIVE"; static String ACTION_ACTIVATE_PUSH_SERVICE ="ACTION_ACTIVATE_PUSH_SERVICE";
static String ACTION_CONNECTION ="ACTION_CONNECTION"; static String ACTION_CONNECTION ="ACTION_CONNECTION";
@ -39,30 +47,32 @@ public class CIMPushManager {
*/ */
public static void init(Context context,String ip,int port){ public static void init(Context context,String ip,int port){
CIMDataConfig.putBoolean(context,CIMDataConfig.KEY_CIM_DESTORYED, false); CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED, false);
CIMDataConfig.putBoolean(context,CIMDataConfig.KEY_MANUAL_STOP, false); CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP, false);
CIMCacheTools.putString(context, CIMCacheTools.KEY_CIM_SERVIER_HOST, ip);
CIMCacheTools.putInt(context, CIMCacheTools.KEY_CIM_SERVIER_PORT, port);
Intent serviceIntent = new Intent(context, CIMPushService.class); Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(CIMDataConfig.KEY_CIM_SERVIER_HOST, ip); serviceIntent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST, ip);
serviceIntent.putExtra(CIMDataConfig.KEY_CIM_SERVIER_PORT, port); serviceIntent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, port);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_CONNECTION); serviceIntent.putExtra(SERVICE_ACTION, ACTION_CONNECTION);
context.startService(serviceIntent); context.startService(serviceIntent);
CIMDataConfig.putString(context, CIMDataConfig.KEY_CIM_SERVIER_HOST, ip);
CIMDataConfig.putInt(context, CIMDataConfig.KEY_CIM_SERVIER_PORT, port);
} }
protected static void init(Context context){ protected static void init(Context context){
boolean isManualStop = CIMDataConfig.getBoolean(context,CIMDataConfig.KEY_MANUAL_STOP); boolean isManualStop = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_MANUAL_STOP);
boolean isManualDestory = CIMDataConfig.getBoolean(context,CIMDataConfig.KEY_CIM_DESTORYED); boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualStop || isManualDestory) if(isManualStop || isManualDestory)
{ {
return ; return ;
} }
String host = CIMDataConfig.getString(context, CIMDataConfig.KEY_CIM_SERVIER_HOST); String host = CIMCacheTools.getString(context, CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port =CIMDataConfig.getInt(context, CIMDataConfig.KEY_CIM_SERVIER_PORT); int port =CIMCacheTools.getInt(context, CIMCacheTools.KEY_CIM_SERVIER_PORT);
init(context,host,port); init(context,host,port);
@ -73,38 +83,40 @@ public class CIMPushManager {
* 设置一个账号登录到服务端 * 设置一个账号登录到服务端
* @param account 用户唯一ID * @param account 用户唯一ID
*/ */
public static void setAccount(Context context,String account){ public static void bindAccount(Context context,String account){
boolean isManualDestory = CIMDataConfig.getBoolean(context,CIMDataConfig.KEY_CIM_DESTORYED); boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualDestory || account==null || account.trim().length()==0) if(isManualDestory || account==null || account.trim().length()==0)
{ {
return ; return ;
} }
CIMDataConfig.putBoolean(context,CIMDataConfig.KEY_MANUAL_STOP, false); CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP, false);
CIMDataConfig.putString(context,CIMDataConfig.KEY_ACCOUNT, account); CIMCacheTools.putString(context,CIMCacheTools.KEY_ACCOUNT, account);
String imei = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId(); String imei = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
imei += context.getPackageName(); imei += context.getPackageName();
SentBody sent = new SentBody(); SentBody sent = new SentBody();
sent.setKey(CIMConstant.RequestKey.CLIENT_BIND); sent.setKey(CIMConstant.RequestKey.CLIENT_BIND);
sent.put("account", account); sent.put("account", account);
sent.put("deviceId",UUID.nameUUIDFromBytes(imei.getBytes()).toString().replaceAll("-", "")); sent.put("deviceId",UUID.nameUUIDFromBytes(imei.getBytes()).toString().replaceAll("-", ""));
sent.put("channel", "android"); sent.put("channel", "android");
sent.put("device",android.os.Build.MODEL); sent.put("device",android.os.Build.MODEL);
sent.put("appVersion",getVersionName(context));
sent.put("osVersion",android.os.Build.VERSION.RELEASE);
sendRequest(context,sent); sendRequest(context,sent);
} }
protected static void setAccount(Context context){
protected static void bindAccount(Context context){
String account = CIMDataConfig.getString(context,CIMDataConfig.KEY_ACCOUNT); String account = CIMCacheTools.getString(context,CIMCacheTools.KEY_ACCOUNT);
setAccount(context,account); bindAccount(context,account);
} }
@ -116,8 +128,8 @@ public class CIMPushManager {
*/ */
public static void sendRequest(Context context,SentBody body){ public static void sendRequest(Context context,SentBody body){
boolean isManualStop = CIMDataConfig.getBoolean(context,CIMDataConfig.KEY_MANUAL_STOP); boolean isManualStop = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_MANUAL_STOP);
boolean isManualDestory = CIMDataConfig.getBoolean(context,CIMDataConfig.KEY_CIM_DESTORYED); boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualStop || isManualDestory) if(isManualStop || isManualDestory)
{ {
@ -137,12 +149,12 @@ public class CIMPushManager {
*/ */
public static void stop(Context context){ public static void stop(Context context){
boolean isManualDestory = CIMDataConfig.getBoolean(context,CIMDataConfig.KEY_CIM_DESTORYED); boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualDestory){ if(isManualDestory){
return ; return ;
} }
CIMDataConfig.putBoolean(context,CIMDataConfig.KEY_MANUAL_STOP, true); CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP, true);
Intent serviceIntent = new Intent(context, CIMPushService.class); Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_DISCONNECTION); serviceIntent.putExtra(SERVICE_ACTION, ACTION_DISCONNECTION);
@ -158,8 +170,8 @@ public class CIMPushManager {
public static void destory(Context context){ public static void destory(Context context){
CIMDataConfig.putBoolean(context,CIMDataConfig.KEY_CIM_DESTORYED, true); CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED, true);
CIMDataConfig.putString(context,CIMDataConfig.KEY_ACCOUNT, null); CIMCacheTools.putString(context,CIMCacheTools.KEY_ACCOUNT, null);
Intent serviceIntent = new Intent(context, CIMPushService.class); Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_DESTORY); serviceIntent.putExtra(SERVICE_ACTION, ACTION_DESTORY);
@ -174,18 +186,30 @@ public class CIMPushManager {
*/ */
public static void resume(Context context){ public static void resume(Context context){
boolean isManualDestory = CIMDataConfig.getBoolean(context,CIMDataConfig.KEY_CIM_DESTORYED); boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualDestory){ if(isManualDestory){
return ; return ;
} }
setAccount(context); bindAccount(context);
} }
public void detectIsConnected(Context context){ public static void detectIsConnected(Context context){
Intent serviceIntent = new Intent(context, CIMPushService.class); Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_CONNECTION_STATUS); serviceIntent.putExtra(SERVICE_ACTION, ACTION_CONNECTION_STATUS);
context.startService(serviceIntent); context.startService(serviceIntent);
} }
private static String getVersionName(Context context) {
String versionName = null;
try {
PackageInfo mPackageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
versionName = mPackageInfo.versionName;
} catch (NameNotFoundException e) {
}
return versionName;
}
} }

View File

@ -1,15 +1,11 @@
package com.farsunset.cim.client.android; package com.farsunset.cim.client.android;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.Intent; import android.content.Intent;
import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.util.Log; import android.util.Log;
import com.farsunset.cim.nio.mutual.SentBody; import com.farsunset.cim.client.model.SentBody;
/** /**
@ -19,18 +15,12 @@ import com.farsunset.cim.nio.mutual.SentBody;
*/ */
public class CIMPushService extends Service { public class CIMPushService extends Service {
protected final static int DEF_CIM_PORT = 28888;
CIMConnectorManager manager; CIMConnectorManager manager;
AlarmManager localAlarmManager;
private IBinder binder=new CIMPushService.LocalBinder();
PendingIntent localPendingIntent;
@Override @Override
public void onCreate() public void onCreate()
{ {
manager = CIMConnectorManager.getManager(this.getApplicationContext()); manager = CIMConnectorManager.getManager(this.getApplicationContext());
localPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, KeepAliveReceiver.class), PendingIntent.FLAG_CANCEL_CURRENT);
localAlarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
localAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 300000L + System.currentTimeMillis(),300000L, localPendingIntent);
} }
@ -41,18 +31,18 @@ import com.farsunset.cim.nio.mutual.SentBody;
if(intent==null) if(intent==null)
{ {
intent = new Intent(CIMPushManager.ACTION_CONNECTION); intent = new Intent(CIMPushManager.ACTION_CONNECTION);
String host = CIMDataConfig.getString(this, CIMDataConfig.KEY_CIM_SERVIER_HOST); String host = CIMCacheTools.getString(this, CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port =CIMDataConfig.getInt(this, CIMDataConfig.KEY_CIM_SERVIER_PORT); int port =CIMCacheTools.getInt(this, CIMCacheTools.KEY_CIM_SERVIER_PORT);
intent.putExtra(CIMDataConfig.KEY_CIM_SERVIER_HOST, host); intent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST, host);
intent.putExtra(CIMDataConfig.KEY_CIM_SERVIER_PORT, port); intent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, port);
} }
action = intent.getStringExtra(CIMPushManager.SERVICE_ACTION); action = intent.getStringExtra(CIMPushManager.SERVICE_ACTION);
if(CIMPushManager.ACTION_CONNECTION.equals(action)) if(CIMPushManager.ACTION_CONNECTION.equals(action))
{ {
String host = intent.getStringExtra(CIMDataConfig.KEY_CIM_SERVIER_HOST); String host = intent.getStringExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port = intent.getIntExtra(CIMDataConfig.KEY_CIM_SERVIER_PORT, 28888); int port = intent.getIntExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, DEF_CIM_PORT);
manager.connect(host,port); manager.connect(host,port);
} }
@ -68,8 +58,6 @@ import com.farsunset.cim.nio.mutual.SentBody;
if(CIMPushManager.ACTION_DESTORY.equals(action)) if(CIMPushManager.ACTION_DESTORY.equals(action))
{ {
localAlarmManager.cancel(localPendingIntent);
localPendingIntent.cancel();
manager.destroy(); manager.destroy();
this.stopSelf(); this.stopSelf();
android.os.Process.killProcess(android.os.Process.myPid()); android.os.Process.killProcess(android.os.Process.myPid());
@ -80,14 +68,14 @@ import com.farsunset.cim.nio.mutual.SentBody;
manager.deliverIsConnected(); manager.deliverIsConnected();
} }
if(CIMPushManager.ACTION_CONNECTION_KEEPALIVE.equals(action)) if(CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE.equals(action))
{ {
if(!manager.isConnected()) if(!manager.isConnected())
{ {
Log.d(CIMPushService.class.getSimpleName(), "isConnected() = false "); Log.d(CIMPushService.class.getSimpleName(), "cimpush isConnected() = false ");
String host = intent.getStringExtra(CIMDataConfig.KEY_CIM_SERVIER_HOST); String host = intent.getStringExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port = intent.getIntExtra(CIMDataConfig.KEY_CIM_SERVIER_PORT, 28888); int port = intent.getIntExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, DEF_CIM_PORT);
manager.connect(host,port); manager.connect(host,port);
}else }else
{ {
@ -102,14 +90,8 @@ import com.farsunset.cim.nio.mutual.SentBody;
@Override @Override
public IBinder onBind(Intent arg0) { public IBinder onBind(Intent arg0) {
return binder; return null;
} }
public class LocalBinder extends Binder{
public CIMPushService getService()
{
return CIMPushService.this;
}
}
} }

View File

@ -0,0 +1,68 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.constant;
/**
* 常量
*/
public interface CIMConstant {
public static String UTF8="UTF-8";
public static byte MESSAGE_SEPARATE='\b';
public static int CIM_DEFAULT_MESSAGE_ORDER=1;
public static class ReturnCode{
public static String CODE_404 ="404";
public static String CODE_403 ="403";
public static String CODE_405 ="405";
public static String CODE_200 ="200";
public static String CODE_206 ="206";
public static String CODE_500 ="500";
}
/**
* 服务端心跳请求命令
*/
public static final String CMD_HEARTBEAT_REQUEST="cmd_server_hb_request";
/**
* 客户端心跳响应命令
*/
public static final String CMD_HEARTBEAT_RESPONSE ="cmd_client_hb_response";
public static class RequestKey{
public static String CLIENT_BIND ="client_bind";
public static String CLIENT_LOGOUT ="client_logout";
public static String CLIENT_OFFLINE_MESSAGE ="client_get_offline_message";
}
public static class MessageType{
//用户会 踢出下线消息类型
public static String TYPE_999 ="999";
}
}

View File

@ -1,4 +1,10 @@
package com.farsunset.cim.client.android; /**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.exception;
public class CIMSessionDisableException extends Exception { public class CIMSessionDisableException extends Exception {

View File

@ -1,4 +1,10 @@
package com.farsunset.cim.client.android; /**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.exception;
public class NetWorkDisableException extends Exception { public class NetWorkDisableException extends Exception {

View File

@ -1,4 +1,10 @@
package com.farsunset.cim.client.android; /**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.exception;
import java.io.Serializable; import java.io.Serializable;

View File

@ -1,5 +1,10 @@
/**
package com.farsunset.cim.nio.filter; * probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.filter;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolCodecFactory;
@ -9,7 +14,6 @@ import org.apache.mina.filter.codec.ProtocolEncoder;
/** /**
* android客户端端消息 编码解码器 可以在 * android客户端端消息 编码解码器 可以在
* 关于消息加密与加密 可在 encoder时进行消息加密在ServerMessageCodecFactory的 decoder时对消息解密 * 关于消息加密与加密 可在 encoder时进行消息加密在ServerMessageCodecFactory的 decoder时对消息解密
* @author 3979434@qq.com
*/ */
public class ClientMessageCodecFactory implements ProtocolCodecFactory { public class ClientMessageCodecFactory implements ProtocolCodecFactory {

View File

@ -1,4 +1,10 @@
package com.farsunset.cim.nio.filter; /**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.filter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -12,16 +18,19 @@ import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import com.farsunset.cim.nio.constant.CIMConstant;
import com.farsunset.cim.nio.mutual.Message; import android.util.Log;
import com.farsunset.cim.nio.mutual.ReplyBody;
import com.farsunset.cim.client.constant.CIMConstant;
import com.farsunset.cim.client.model.Message;
import com.farsunset.cim.client.model.ReplyBody;
/** /**
* 客户端消息解码 * 客户端消息解码
* @author 3979434@qq.com
*
*/ */
public class ClientMessageDecoder extends CumulativeProtocolDecoder { public class ClientMessageDecoder extends CumulativeProtocolDecoder {
final static String TAG = ClientMessageDecoder.class.getSimpleName();
private IoBuffer buff = IoBuffer.allocate(320).setAutoExpand(true); private IoBuffer buff = IoBuffer.allocate(320).setAutoExpand(true);
@Override @Override
@ -48,12 +57,21 @@ public class ClientMessageDecoder extends CumulativeProtocolDecoder {
buff.flip(); buff.flip();
byte[] bytes = new byte[buff.limit()]; byte[] bytes = new byte[buff.limit()];
buff.get(bytes); buff.get(bytes);
String message = new String(bytes, "UTF-8"); String message = new String(bytes, CIMConstant.UTF8);
buff.clear(); buff.clear();
System.out.println("ClientMessageDecoder:" + message);
Object msg = mappingMessageObject(message); //打印出收到的消息
out.write(msg); Log.i(TAG,message);
try
{
Object msg = mappingMessageObject(message);
out.write(msg);
}catch(Exception e)
{
e.printStackTrace();
}
} }
return complete; return complete;
@ -61,10 +79,15 @@ public class ClientMessageDecoder extends CumulativeProtocolDecoder {
private Object mappingMessageObject(String message) throws Exception { private Object mappingMessageObject(String message) throws Exception {
if(CIMConstant.CMD_HEARTBEAT_REQUEST.equals(message))
{
return message;
}
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder(); DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = (Document) builder.parse(new ByteArrayInputStream(message.toString().getBytes("UTF-8"))); Document doc = (Document) builder.parse(new ByteArrayInputStream(message.getBytes(CIMConstant.UTF8)));
String name = doc.getDocumentElement().getTagName(); String name = doc.getDocumentElement().getTagName();
if (name.equals("reply")) { if (name.equals("reply")) {

View File

@ -1,4 +1,10 @@
package com.farsunset.cim.nio.filter; /**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.filter;
@ -7,24 +13,25 @@ import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter; import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput; import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import com.farsunset.cim.nio.constant.CIMConstant; import android.util.Log;
import com.farsunset.cim.client.constant.CIMConstant;
/** /**
* 客户端消息发送前进行编码,可在此加密消息 * 客户端消息发送前进行编码,可在此加密消息
* @author 3979434@qq.com
*
*/ */
public class ClientMessageEncoder extends ProtocolEncoderAdapter { public class ClientMessageEncoder extends ProtocolEncoderAdapter {
final static String TAG = ClientMessageEncoder.class.getSimpleName();
@Override @Override
public void encode(IoSession iosession, Object message, ProtocolEncoderOutput out) throws Exception { public void encode(IoSession iosession, Object message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(320).setAutoExpand(true); IoBuffer buff = IoBuffer.allocate(320).setAutoExpand(true);
//buff.putString( message.toString(), charset.newEncoder()); buff.put(message.toString().getBytes(CIMConstant.UTF8));
buff.put(message.toString().getBytes("UTF-8"));
buff.put(CIMConstant.MESSAGE_SEPARATE); buff.put(CIMConstant.MESSAGE_SEPARATE);
buff.flip(); buff.flip();
out.write(buff); out.write(buff);
//打印出收到的消息
Log.i(TAG,message.toString());
} }

View File

@ -1,17 +1,17 @@
package com.farsunset.cim.nio.mutual; /**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.model;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 消息对象 * 消息对象
* @author @author 3979434@qq.com
*
*/ */
public class Message implements Serializable { public class Message implements Serializable {
/**
* @author 3979434@qq.com
* 消息对象
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -1,18 +1,19 @@
package com.farsunset.cim.nio.mutual; /**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
/** /**
* 请求应答对象 * 请求应答对象
* @author 3979434@qq.com
* *
*/ */
public class ReplyBody implements Serializable { public class ReplyBody implements Serializable {
/**
* @author 3979434@qq.com
* 服务端返回消息对象
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**

View File

@ -1,17 +1,19 @@
package com.farsunset.cim.nio.mutual; /**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
/** /**
* java |android 客户端请求结构 * java |android 客户端请求结构
* @author 3979434@qq.com
* *
*/ */
public class SentBody implements Serializable { public class SentBody implements Serializable {
/**
* @author 3979434@qq.com 客户端发送消息对象
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private String key; private String key;

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="/ichat-server/WebRoot/WEB-INF/lib/mina-core-2.0.7.jar"/>
<classpathentry kind="lib" path="/ichat-server/WebRoot/WEB-INF/lib/log4j.jar"/>
<classpathentry kind="lib" path="D:/soft/adt-bundle-windows-x86_64-20140321/sdk/platforms/android-19/android.jar"/>
<classpathentry kind="lib" path="/ichat-server/WebRoot/WEB-INF/lib/commons-lang-2.3.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -1,40 +0,0 @@
package com.farsunset.cim.client.android;
import java.util.ArrayList;
import java.util.Collections;
import android.content.Context;
/**
* CIM 消息监听器管理
*
* @author 3979434@qq.com
*/
public class CIMListenerManager {
private static ArrayList<OnCIMMessageListener> cimListeners = new ArrayList<OnCIMMessageListener>();
public static void registerMessageListener(OnCIMMessageListener listener,Context mcontext) {
if (!cimListeners.contains(listener)) {
cimListeners.add(listener);
// 按照接收顺序倒序
Collections.sort(cimListeners, new CIMMessageReceiveComparator(mcontext));
}
}
public static void removeMessageListener(OnCIMMessageListener listener) {
for (int i = 0; i < cimListeners.size(); i++) {
if (listener.getClass() == cimListeners.get(i).getClass()) {
cimListeners.remove(i);
}
}
}
public static ArrayList<OnCIMMessageListener> getCIMListeners() {
return cimListeners;
}
}

View File

@ -1,59 +0,0 @@
package com.farsunset.cim.client.android;
import java.util.Comparator;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import com.farsunset.cim.nio.constant.CIMConstant;
/**
* 消息接收activity的接收顺序排序CIM_RECEIVE_ORDER倒序
* @author 3979434
*
*/
public class CIMMessageReceiveComparator implements Comparator<OnCIMMessageListener>{
Context mcontext;
public CIMMessageReceiveComparator(Context ctx)
{
mcontext = ctx;
}
@Override
public int compare(OnCIMMessageListener arg1, OnCIMMessageListener arg2) {
Integer order1 = CIMConstant.CIM_DEFAULT_MESSAGE_ORDER;
Integer order2 = CIMConstant.CIM_DEFAULT_MESSAGE_ORDER;
ActivityInfo info;
if (arg1 instanceof Activity ) {
try {
info = mcontext.getPackageManager() .getActivityInfo(((Activity)(arg1)).getComponentName(), PackageManager.GET_META_DATA);
if(info.metaData!=null)
{
order1 = info.metaData.getInt("CIM_RECEIVE_ORDER");
}
} catch (Exception e) {}
}
if (arg1 instanceof Activity ) {
try {
info = mcontext.getPackageManager() .getActivityInfo(((Activity)(arg2)).getComponentName(), PackageManager.GET_META_DATA);
if(info.metaData!=null)
{
order2 = info.metaData.getInt("CIM_RECEIVE_ORDER");
}
} catch (Exception e) {}
}
return order2.compareTo(order1);
}
}

View File

@ -1,24 +0,0 @@
package com.farsunset.cim.client.android;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/**
* @author 3979434
*
*/
public class KeepAliveReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent it) {
Log.d(KeepAliveReceiver.class.getSimpleName(), "onReceive()");
Intent intent = new Intent(context, CIMPushService.class);
intent.putExtra(CIMPushManager.SERVICE_ACTION, CIMPushManager.ACTION_CONNECTION_KEEPALIVE);
context.startService(intent);
}
}

View File

@ -1,15 +0,0 @@
package com.farsunset.cim.nio.handler;
/**
* 请求处理接口,所有的请求实现必须实现此接口
* @author 3979434@qq.com
*/
import com.farsunset.cim.nio.mutual.ReplyBody;
import com.farsunset.cim.nio.mutual.SentBody;
import com.farsunset.cim.nio.session.CIMSession;
public interface CIMRequestHandler {
public abstract ReplyBody process(CIMSession session,SentBody message);
}

View File

@ -1,32 +0,0 @@
package com.farsunset.cim.nio.handler;
import org.apache.log4j.Logger;
import com.farsunset.cim.nio.constant.CIMConstant;
import com.farsunset.cim.nio.mutual.ReplyBody;
import com.farsunset.cim.nio.mutual.SentBody;
import com.farsunset.cim.nio.session.CIMSession;
/**
*客户端心跳实现
*
* @author
*/
public class HeartbeatHandler implements CIMRequestHandler {
protected final Logger logger = Logger.getLogger(HeartbeatHandler.class);
public ReplyBody process(CIMSession session, SentBody message) {
logger.warn("heartbeat... from "+session.getRemoteAddress().toString());
ReplyBody reply = new ReplyBody();
reply.setKey(CIMConstant.RequestKey.CLIENT_HEARTBEAT);
reply.setCode(CIMConstant.ReturnCode.CODE_200);
session.setHeartbeat(System.currentTimeMillis());
return reply;
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/log4j.jar"/>
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/mina-core-2.0.9.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>cim-core</name> <name>cim-server-sdk</name>
<comment></comment> <comment></comment>
<projects> <projects>
</projects> </projects>

View File

@ -0,0 +1,3 @@
#Wed Oct 15 09:31:41 CST 2014
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -1,10 +1,13 @@
/**
package com.farsunset.cim.nio.constant; * probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.constant;
/** /**
* 常量 * 常量
*
* @author 3979434@qq.com
*/ */
public interface CIMConstant { public interface CIMConstant {
@ -25,18 +28,19 @@ public interface CIMConstant {
} }
public static String UTF8="UTF-8";
public static byte MESSAGE_SEPARATE='\b'; public static byte MESSAGE_SEPARATE='\b';
public static int CIM_DEFAULT_MESSAGE_ORDER=1; public static int CIM_DEFAULT_MESSAGE_ORDER=1;
public static final String SESSION_KEY ="account"; public static final String SESSION_KEY ="account";
public static final String HEARTBEAT_KEY ="heartbeat"; public static final String HEARTBEAT_KEY ="heartbeat";
/** /**
* FLEX 客户端socket请求发的安全策略请求需要特殊处理返回安全验证报文 * FLEX 客户端socket请求发的安全策略请求需要特殊处理返回安全验证报文
*/ */
@ -44,32 +48,25 @@ public interface CIMConstant {
public static final String FLEX_POLICY_RESPONSE ="<?xml version=\"1.0\"?><cross-domain-policy><site-control permitted-cross-domain-policies=\"all\"/><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0"; public static final String FLEX_POLICY_RESPONSE ="<?xml version=\"1.0\"?><cross-domain-policy><site-control permitted-cross-domain-policies=\"all\"/><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0";
/** /**
* 服务端心跳请求命令
*/
public static final String CMD_HEARTBEAT_REQUEST="cmd_server_hb_request";
/**
* 客户端心跳响应命令
*/
public static final String CMD_HEARTBEAT_RESPONSE ="cmd_client_hb_response";
/**
* 对应ichat spring-cim.xml > bean:mainIoHandler >handlers * 对应ichat spring-cim.xml > bean:mainIoHandler >handlers
* 服务端处理对应的handlers应该继承与com.farsunset.cim.nio.handle.AbstractHandler * 服务端处理对应的handlers应该继承与com.farsunset.cim.nio.handle.AbstractHandler
* @author xiajun
* *
*/ */
public static class RequestKey{
public static String CLIENT_BIND ="client_bind";
public static String CLIENT_HEARTBEAT="client_heartbeat";
public static String CLIENT_LOGOUT ="client_logout";
public static String CLIENT_DIY ="client_diy";
public static String CLIENT_OFFLINE_MESSAGE ="client_get_offline_message";
}
public static class SessionStatus{ public static class SessionStatus{
public static int STATUS_OK =0; public static int STATUS_OK =0;
@ -78,11 +75,11 @@ public interface CIMConstant {
} }
public static class MessageType{ public static class MessageType{
//账号在其他设备绑定时会收到该类型消息 //用户会 踢出下线消息类型
public static String TYPE_999 ="999"; public static String TYPE_999 ="999";
} }
} }

View File

@ -1,5 +1,10 @@
/**
package com.farsunset.cim.nio.filter; * probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.filter;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolCodecFactory;
@ -9,7 +14,6 @@ import org.apache.mina.filter.codec.ProtocolEncoder;
/** /**
* 服务端消息 编码解码器 可以在 * 服务端消息 编码解码器 可以在
* 关于消息加密与加密 可在 encoder时进行消息加密在ClientMessageCodecFactory的 decoder时对消息解密 * 关于消息加密与加密 可在 encoder时进行消息加密在ClientMessageCodecFactory的 decoder时对消息解密
* @author 3979434@qq.com
*/ */
public class ServerMessageCodecFactory implements ProtocolCodecFactory { public class ServerMessageCodecFactory implements ProtocolCodecFactory {

View File

@ -1,7 +1,12 @@
package com.farsunset.cim.nio.filter; /**
* probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.filter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.nio.charset.Charset;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
@ -15,17 +20,14 @@ import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import com.farsunset.cim.nio.constant.CIMConstant; import com.farsunset.cim.server.constant.CIMConstant;
import com.farsunset.cim.nio.mutual.SentBody; import com.farsunset.cim.server.model.SentBody;
/** /**
* 服务端接收消息解码可在此解密消息 * 服务端接收消息解码可在此解密消息
* @author 3979434@qq.com
*
*/ */
public class ServerMessageDecoder extends CumulativeProtocolDecoder { public class ServerMessageDecoder extends CumulativeProtocolDecoder {
protected final Logger logger = Logger.getLogger(ServerMessageDecoder.class); protected final Logger logger = Logger.getLogger(ServerMessageDecoder.class);
private final Charset charset = Charset.forName("UTF-8");
private IoBuffer buff = IoBuffer.allocate(320).setAutoExpand(true); private IoBuffer buff = IoBuffer.allocate(320).setAutoExpand(true);
@Override @Override
public boolean doDecode(IoSession iosession, IoBuffer iobuffer, ProtocolDecoderOutput out) throws Exception { public boolean doDecode(IoSession iosession, IoBuffer iobuffer, ProtocolDecoderOutput out) throws Exception {
@ -45,7 +47,7 @@ public class ServerMessageDecoder extends CumulativeProtocolDecoder {
complete = true; complete = true;
break; break;
} }
else { else {
buff.put(b); buff.put(b);
} }
} }
@ -54,35 +56,42 @@ public class ServerMessageDecoder extends CumulativeProtocolDecoder {
byte[] bytes = new byte[buff.limit()]; byte[] bytes = new byte[buff.limit()];
buff.get(bytes); buff.get(bytes);
String message = new String(bytes, "UTF-8"); String message = new String(bytes, CIMConstant.UTF8);
logger.warn("ServerMessageDecoder:" + message);
logger.debug(message);
buff.clear(); buff.clear();
try{ try{
SentBody body = new SentBody(); Object body = getSentBody(message);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new ByteArrayInputStream(bytes));
body.setKey(doc.getElementsByTagName("key").item(0).getTextContent());
NodeList dataNodeList = doc.getElementsByTagName("data");
if(dataNodeList!=null && dataNodeList.getLength()>0)
{
NodeList items = dataNodeList.item(0).getChildNodes();
for (int i = 0; i < items.getLength(); i++) {
Node node = items.item(i);
body.getData().put(node.getNodeName(), node.getTextContent());
}
}
out.write(body); out.write(body);
}catch(Exception e){ }catch(Exception e){
logger.warn(e.getMessage()); out.write(message);//解析xml失败 是返回原始的xml数据到上层处理,比如心跳响应flex sokcet的 安全验证请求xml
out.write(message);
} }
} }
return complete; return complete;
} }
public Object getSentBody(String message) throws Exception
{
SentBody body = new SentBody();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new ByteArrayInputStream(message.getBytes(CIMConstant.UTF8)));
body.setKey(doc.getElementsByTagName("key").item(0).getTextContent());
NodeList datas = doc.getElementsByTagName("data");
if(datas!=null&&datas.getLength()>0)
{
NodeList items = datas.item(0).getChildNodes();
for (int i = 0; i < items.getLength(); i++) {
Node node = items.item(i);
body.getData().put(node.getNodeName(), node.getTextContent());
}
}
return body;
}
} }

View File

@ -1,31 +1,35 @@
package com.farsunset.cim.nio.filter; /**
* probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.filter;
import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter; import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput; import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import com.farsunset.cim.nio.constant.CIMConstant; import com.farsunset.cim.server.constant.CIMConstant;
/** /**
* 服务端发送消息前编码可在此加密消息 * 服务端发送消息前编码可在此加密消息
* @author 3979434@qq.com
*
*/ */
public class ServerMessageEncoder extends ProtocolEncoderAdapter { public class ServerMessageEncoder extends ProtocolEncoderAdapter {
protected final Logger logger = Logger.getLogger(ServerMessageEncoder.class);
@Override @Override
public void encode(IoSession iosession, Object message, ProtocolEncoderOutput out) throws Exception { public void encode(IoSession iosession, Object message, ProtocolEncoderOutput out) throws Exception {
IoBuffer buff = IoBuffer.allocate(320).setAutoExpand(true); IoBuffer buff = IoBuffer.allocate(320).setAutoExpand(true);
buff.put(message.toString().getBytes("UTF-8")); buff.put(message.toString().getBytes(CIMConstant.UTF8));
buff.put(CIMConstant.MESSAGE_SEPARATE); buff.put(CIMConstant.MESSAGE_SEPARATE);
buff.flip(); buff.flip();
out.write(buff); out.write(buff);
logger.debug(message);
} }

View File

@ -1,5 +1,10 @@
/**
package com.farsunset.cim.nio.handler; * probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.handler;
import java.util.HashMap; import java.util.HashMap;
@ -8,26 +13,25 @@ import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import com.farsunset.cim.nio.constant.CIMConstant; import com.farsunset.cim.server.constant.CIMConstant;
import com.farsunset.cim.nio.mutual.ReplyBody; import com.farsunset.cim.server.model.ReplyBody;
import com.farsunset.cim.nio.mutual.SentBody; import com.farsunset.cim.server.model.SentBody;
import com.farsunset.cim.nio.session.CIMSession; import com.farsunset.cim.server.session.CIMSession;
/** /**
* *
* 客户端请求的入口所有请求都首先经过它分发处理 * 客户端请求的入口所有请求都首先经过它分发处理
* @author farsunset (3979434@qq.com)
*/ */
public class MainIOHandler extends IoHandlerAdapter { public class CIMIoHandler extends IoHandlerAdapter {
protected final Logger logger = Logger.getLogger(MainIOHandler.class);
protected final Logger logger = Logger.getLogger(CIMIoHandler.class);
private final static String CIMSESSION_CLOSED_HANDLER_KEY = "client_cimsession_closed";
private HashMap<String, CIMRequestHandler> handlers = new HashMap<String, CIMRequestHandler>(); private HashMap<String, CIMRequestHandler> handlers = new HashMap<String, CIMRequestHandler>();
public void sessionCreated(IoSession session) throws Exception { public void sessionCreated(IoSession session) throws Exception {
logger.warn("sessionCreated()... from "+session.getRemoteAddress().toString()); logger.debug("sessionCreated()... from "+session.getRemoteAddress());
} }
@ -38,7 +42,6 @@ public class MainIOHandler extends IoHandlerAdapter {
public void messageReceived(IoSession ios, Object message) public void messageReceived(IoSession ios, Object message)
throws Exception { throws Exception {
logger.debug("message: " + message.toString());
/** /**
* flex 客户端安全策略请求需要返回特定报文 * flex 客户端安全策略请求需要返回特定报文
@ -49,6 +52,11 @@ public class MainIOHandler extends IoHandlerAdapter {
return ; return ;
} }
if(!(message instanceof SentBody))
{
return ;
}
CIMSession cimSession =new CIMSession(ios); CIMSession cimSession =new CIMSession(ios);
ReplyBody reply = new ReplyBody(); ReplyBody reply = new ReplyBody();
SentBody body = (SentBody) message; SentBody body = (SentBody) message;
@ -66,12 +74,8 @@ public class MainIOHandler extends IoHandlerAdapter {
{ {
reply.setKey(key); reply.setKey(key);
cimSession.write(reply); cimSession.write(reply);
logger.debug("-----------------------process done. reply: " + reply.toString()); logger.info("-----------------------process done. reply: " + reply.toString());
} }
//设置心跳时间
cimSession.setAttribute(CIMConstant.HEARTBEAT_KEY, System.currentTimeMillis());
} }
/** /**
@ -80,8 +84,8 @@ public class MainIOHandler extends IoHandlerAdapter {
CIMSession cimSession =new CIMSession(ios); CIMSession cimSession =new CIMSession(ios);
try{ try{
logger.warn("sessionClosed()... from "+cimSession.getRemoteAddress()); logger.debug("sessionClosed()... from "+cimSession.getRemoteAddress());
CIMRequestHandler handler = handlers.get("sessionClosedHander"); CIMRequestHandler handler = handlers.get(CIMSESSION_CLOSED_HANDLER_KEY);
if(handler!=null && cimSession.containsAttribute(CIMConstant.SESSION_KEY)) if(handler!=null && cimSession.containsAttribute(CIMConstant.SESSION_KEY))
{ {
handler.process(cimSession, null); handler.process(cimSession, null);
@ -97,19 +101,7 @@ public class MainIOHandler extends IoHandlerAdapter {
*/ */
public void sessionIdle(IoSession session, IdleStatus status) public void sessionIdle(IoSession session, IdleStatus status)
throws Exception { throws Exception {
logger.warn("sessionIdle()... from "+session.getRemoteAddress().toString()); logger.debug("sessionIdle()... from "+session.getRemoteAddress());
if(!session.containsAttribute(CIMConstant.SESSION_KEY))
{
session.close(true);
}else
{
//如果5分钟之内客户端没有发送心态则可能客户端断网关闭连接
Object heartbeat = session.getAttribute(CIMConstant.HEARTBEAT_KEY);
if(heartbeat!=null && System.currentTimeMillis()-Long.valueOf(heartbeat.toString()) >= 300000)
{
session.close(false);
}
}
} }
/** /**
@ -124,9 +116,6 @@ public class MainIOHandler extends IoHandlerAdapter {
/** /**
*/ */
public void messageSent(IoSession session, Object message) throws Exception { public void messageSent(IoSession session, Object message) throws Exception {
//设置心跳时间
session.setAttribute(CIMConstant.HEARTBEAT_KEY, System.currentTimeMillis());
} }

View File

@ -0,0 +1,62 @@
package com.farsunset.cim.server.handler;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Map;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.filter.keepalive.KeepAliveRequestTimeoutHandler;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class CIMNioSocketAcceptor {
IoAcceptor acceptor;
IoHandler ioHandler;
int port;
private final int IDLE_TIME = 60;//
private final int TIME_OUT = 30;//
public void bind() throws IOException
{
acceptor = new NioSocketAcceptor();
acceptor.getSessionConfig().setReadBufferSize(1024);
((DefaultSocketSessionConfig)acceptor.getSessionConfig()).setTcpNoDelay(true);
acceptor.getFilterChain().addLast("executor",new ExecutorFilter());
acceptor.getFilterChain().addLast("logger",new LoggingFilter());
acceptor.getFilterChain().addLast("codec",new ProtocolCodecFilter(new com.farsunset.cim.server.filter.ServerMessageCodecFactory()));
KeepAliveMessageFactory heartBeatFactory = new ServerKeepAliveFactoryImpl();
KeepAliveFilter keepAliveFilter = new KeepAliveFilter(heartBeatFactory,IdleStatus.BOTH_IDLE,KeepAliveRequestTimeoutHandler.CLOSE,IDLE_TIME,TIME_OUT);
keepAliveFilter.setForwardEvent(true);
acceptor.getFilterChain().addLast("heartbeat",keepAliveFilter);
acceptor.setHandler(ioHandler);
acceptor.bind(new InetSocketAddress(port));
}
public void unbind()
{
acceptor.unbind();
}
public void setAcceptor(IoAcceptor acceptor) {
this.acceptor = acceptor;
}
public void setIoHandler(IoHandler ioHandler) {
this.ioHandler = ioHandler;
}
public void setPort(int port) {
this.port = port;
}
public Map<Long, IoSession> getManagedSessions()
{
return acceptor.getManagedSessions();
}
}

View File

@ -0,0 +1,20 @@
/**
* probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.handler;
/**
* 请求处理接口,所有的请求实现必须实现此接口
* @author 3979434@qq.com
*/
import com.farsunset.cim.server.model.ReplyBody;
import com.farsunset.cim.server.model.SentBody;
import com.farsunset.cim.server.session.CIMSession;
public interface CIMRequestHandler {
public abstract ReplyBody process(CIMSession session,SentBody message);
}

View File

@ -0,0 +1,29 @@
package com.farsunset.cim.server.handler;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import com.farsunset.cim.server.constant.CIMConstant;
public class ServerKeepAliveFactoryImpl implements KeepAliveMessageFactory {
@Override
public Object getRequest(IoSession arg0) {
return CIMConstant.CMD_HEARTBEAT_REQUEST;
}
@Override
public Object getResponse(IoSession arg0, Object arg1) {
return null;
}
@Override
public boolean isRequest(IoSession arg0, Object arg1) {
return false;
}
@Override
public boolean isResponse(IoSession arg0, Object arg1) {
return CIMConstant.CMD_HEARTBEAT_RESPONSE.equals(arg1);
}
}

View File

@ -0,0 +1,174 @@
/**
* probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.model;
import java.io.Serializable;
/**
* 消息对象
*/
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 消息类型用户自定义消息类别
*/
private String mid;
/**
* 消息类型用户自定义消息类别
*/
private String type;
/**
* 消息标题
*/
private String title;
/**
* 消息类容于type 组合为任何类型消息content 根据 format 可表示为 text,json ,xml数据格式
*/
private String content;
/**
* 消息发送者账号
*/
private String sender;
/**
* 消息发送者接收者
*/
private String receiver;
/**
* 文件 url
*/
private String file;
/**
* 文件类型
*/
private String fileType;
/**
* content 内容格式
*/
private String format = "txt";
private long timestamp;
public Message()
{
timestamp = System.currentTimeMillis();
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getReceiver() {
return receiver;
}
public void setReceiver(String receiver) {
this.receiver = receiver;
}
public String getFile() {
return file;
}
public void setFile(String file) {
this.file = file;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
buffer.append("<message>");
buffer.append("<mid>").append(mid).append("</mid>");
buffer.append("<type>").append(type).append("</type>");
buffer.append("<title>").append(this.getTitle()==null?"":this.getTitle()).append("</title>");
buffer.append("<content><![CDATA[").append(this.getContent()==null?"":this.getContent()).append("]]></content>");
buffer.append("<file>").append(this.getFile()==null?"":this.getFile()).append("</file>");
buffer.append("<fileType>").append(this.getFileType()==null?"":this.getFileType()).append("</fileType>");
buffer.append("<sender>").append(this.getSender()==null?"":this.getSender()).append("</sender>");
buffer.append("<receiver>").append(this.getReceiver()==null?"":this.getReceiver()).append("</receiver>");
buffer.append("<format>").append(this.getFormat()==null?"":this.getFormat()).append("</format>");
buffer.append("<timestamp>").append(timestamp).append("</timestamp>");
buffer.append("</message>");
return buffer.toString();
}
public String toXmlString()
{
return toString();
}
public String getMid() {
return mid;
}
public void setMid(String mid) {
this.mid = mid;
}
}

View File

@ -0,0 +1,124 @@
/**
* probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.model;
import java.io.Serializable;
import java.util.HashMap;
/**
* 请求应答对象
*
*/
public class ReplyBody implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 请求key
*/
private String key;
/**
* 返回码
*/
private String code;
/**
* 返回说明
*/
private String message;
/**
* 返回数据集合
*/
private HashMap<String, String> data;
private long timestamp;
public ReplyBody()
{
data = new HashMap<String, String>();
timestamp = System.currentTimeMillis();
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public void put(String k, String v) {
data.put(k, v);
}
public String get(String k) {
return data.get(k);
}
public void remove(String k) {
data.remove(k);
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public HashMap<String, String> getData() {
return data;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
buffer.append("<reply>");
buffer.append("<key>").append(this.getKey()).append("</key>");
buffer.append("<timestamp>").append(timestamp).append("</timestamp>");
buffer.append("<code>").append(code).append("</code>");
buffer.append("<data>");
for(String key:this.getData().keySet())
{
buffer.append("<"+key+">").append(this.get(key)).append("</"+key+">");
}
buffer.append("</data>");
buffer.append("</reply>");
return buffer.toString();
}
public String toXmlString()
{
return toString();
}
}

View File

@ -0,0 +1,84 @@
/**
* probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.model;
import java.io.Serializable;
import java.util.HashMap;
/**
* java |android 客户端请求结构
*
*/
public class SentBody implements Serializable {
private static final long serialVersionUID = 1L;
private String key;
private HashMap<String, String> data;
private long timestamp;
public SentBody() {
data = new HashMap<String, String>();
timestamp = System.currentTimeMillis();
}
public String getKey() {
return key;
}
public String get(String k) {
return data.get(k);
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public void setKey(String key) {
this.key = key;
}
public void put(String k, String v) {
data.put(k, v);
}
public void remove(String k) {
data.remove(k);
}
public HashMap<String, String> getData() {
return data;
}
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
buffer.append("<sent>");
buffer.append("<key>").append(key).append("</key>");
buffer.append("<timestamp>").append(timestamp).append("</timestamp>");
buffer.append("<data>");
for (String key : data.keySet()) {
buffer.append("<" + key + ">").append(data.get(key)).append(
"</" + key + ">");
}
buffer.append("</data>");
buffer.append("</sent>");
return buffer.toString();
}
public String toXmlString() {
return toString();
}
}

View File

@ -1,43 +1,60 @@
package com.farsunset.cim.nio.session; /**
* probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.session;
import java.io.Serializable; import java.io.Serializable;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
import org.apache.mina.core.future.WriteFuture;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import com.farsunset.cim.nio.constant.CIMConstant; import com.farsunset.cim.server.constant.CIMConstant;
/** /**
* IoSession包装类,集群时 将此对象存入表中 * IoSession包装类,集群时 将此对象存入表中
*
* @author 3979434@qq.com
*/ */
public class CIMSession implements Serializable{ public class CIMSession implements Serializable{
/** /**
* *
*/ */
private transient static final long serialVersionUID = 1L; private transient static final long serialVersionUID = 1L;
public transient static String ID = "ID"; public transient static String ID = "ID";
public transient static String HOST = "HOST"; public transient static String HOST = "HOST";
public transient static final int STATUS_ENABLE=0;
public transient static final int STATUS_DISENABLE=1;
public transient static final int APNS_ON=1;
public transient static final int APNS_OFF=0;
public transient static String CHANNEL_IOS = "ios";
public transient static String CHANNEL_ANDROID = "android";
public transient static String CHANNEL_WINDOWS = "windows";
public transient static String CHANNEL_WP = "wp";
private transient IoSession session; private transient IoSession session;
private String gid;//session全局ID private String gid;//session全局ID
private Long nid;//session在本台服务器上的ID private Long nid;//session在本台服务器上的ID
private String deviceId;//客户端ID (设备号码+应用包名) private String deviceId;//客户端ID (设备号码+应用包名),ios为devicetoken
private String host;//session绑定的服务器IP private String host;//session绑定的服务器IP
private String account;//session绑定的账号 private String account;//session绑定的账号
private String channel;//终端设备类型 private String channel;//终端设备类型
private String deviceModel;//终端设备型号 private String deviceModel;//终端设备型号
private String clientVersion;//终端应用版本
private String systemVersion;//终端系统版本
private Long bindTime;//登录时间 private Long bindTime;//登录时间
private Long heartbeat;//心跳时间 private Long heartbeat;//心跳时间
private Double longitude;//经度
private Double latitude;//维度
private String location;//位置
private int apnsAble;//apns推送状态
private int status;// 状态
public CIMSession(IoSession session) { public CIMSession(IoSession session) {
this.session = session; this.session = session;
this.nid = session.getId(); this.nid = session.getId();
@ -66,6 +83,33 @@ public class CIMSession implements Serializable{
public Double getLongitude() {
return longitude;
}
public void setLongitude(Double longitude) {
setAttribute("longitude", longitude);
this.longitude = longitude;
}
public Double getLatitude() {
return latitude;
}
public void setLatitude(Double latitude) {
setAttribute("latitude", latitude);
this.latitude = latitude;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
setAttribute("location", location);
this.location = location;
}
public String getGid() { public String getGid() {
return gid; return gid;
} }
@ -134,6 +178,29 @@ public class CIMSession implements Serializable{
setAttribute("bindTime", bindTime); setAttribute("bindTime", bindTime);
} }
public String getClientVersion() {
return clientVersion;
}
public void setClientVersion(String clientVersion) {
this.clientVersion = clientVersion;
setAttribute("clientVersion", clientVersion);
}
public String getSystemVersion() {
return systemVersion;
}
public void setSystemVersion(String systemVersion) {
this.systemVersion = systemVersion;
setAttribute("systemVersion", systemVersion);
}
public Long getHeartbeat() { public Long getHeartbeat() {
return heartbeat; return heartbeat;
} }
@ -150,14 +217,23 @@ public class CIMSession implements Serializable{
} }
public void setIoSession(IoSession session) { public int getApnsAble() {
this.session = session; return apnsAble;
} }
public IoSession getIoSession() { public void setApnsAble(int apnsAble) {
return session; this.apnsAble = apnsAble;
setAttribute("apnsAble", apnsAble);
} }
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
setAttribute("status", status);
}
public void setAttribute(String key, Object value) { public void setAttribute(String key, Object value) {
@ -189,14 +265,11 @@ public class CIMSession implements Serializable{
return null; return null;
} }
public boolean write(Object msg) { public void write(Object msg) {
if(session!=null) if(session!=null)
{ {
WriteFuture wf = session.write(msg); session.write(msg).isWritten();
wf.awaitUninterruptibly(5, TimeUnit.SECONDS);
return wf.isWritten();
} }
return false;
} }
public boolean isConnected() { public boolean isConnected() {
@ -238,6 +311,36 @@ public class CIMSession implements Serializable{
return false; return false;
} }
public void setIoSession(IoSession session) {
this.session = session;
}
public IoSession getIoSession() {
return session;
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("{");
buffer.append("\"").append("gid").append("\":").append("\"").append(gid).append("\"").append(",");
buffer.append("\"").append("nid").append("\":").append(nid).append(",");
buffer.append("\"").append("deviceId").append("\":").append("\"").append(deviceId).append("\"").append(",");
buffer.append("\"").append("host").append("\":").append("\"").append(host).append("\"").append(",");
buffer.append("\"").append("account").append("\":").append("\"").append(account).append("\"").append(",");
buffer.append("\"").append("channel").append("\":").append("\"").append(channel).append("\"").append(",");
buffer.append("\"").append("deviceModel").append("\":").append("\"").append(deviceModel).append("\"").append(",");
buffer.append("\"").append("status").append("\":").append(status).append(",");
buffer.append("\"").append("apnsAble").append("\":").append(apnsAble).append(",");
buffer.append("\"").append("bindTime").append("\":").append(bindTime).append(",");
buffer.append("\"").append("heartbeat").append("\":").append(heartbeat);
buffer.append("}");
return buffer.toString();
}
} }

View File

@ -1,16 +1,20 @@
/**
package com.farsunset.cim.nio.session; * probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.session;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.farsunset.cim.nio.constant.CIMConstant; import com.farsunset.cim.server.constant.CIMConstant;
/** /**
* 自带默认 session管理实现 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理 * 自带默认 session管理实现 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理
*服务器集群时 须要将CIMSession 信息存入数据库或者nosql 第三方存储空间中便于所有服务器都可以访问 *服务器集群时 须要将CIMSession 信息存入数据库或者nosql 第三方存储空间中便于所有服务器都可以访问
* @author farsunset (3979434@qq.com)
*/ */
public class DefaultSessionManager implements SessionManager{ public class DefaultSessionManager implements SessionManager{
@ -63,9 +67,9 @@ public class DefaultSessionManager implements SessionManager{
} }
public boolean containsCIMSession(CIMSession ios) public boolean containsCIMSession(String account)
{ {
return sessions.containsKey(ios.getAttribute(CIMConstant.SESSION_KEY)) || sessions.containsValue(ios); return sessions.containsKey(account);
} }
@ -75,7 +79,7 @@ public class DefaultSessionManager implements SessionManager{
{ {
for(String key:sessions.keySet()) for(String key:sessions.keySet())
{ {
if(sessions.get(key).equals(ios) || sessions.get(key).getNid()==ios.getNid()) if(sessions.get(key).equals(ios) || sessions.get(key).getGid()==ios.getGid())
{ {
return key; return key;
} }
@ -88,4 +92,16 @@ public class DefaultSessionManager implements SessionManager{
return null; return null;
} }
@Override
public void updateSession(CIMSession session) {
sessions.put(session.getAccount(), session);
}
@Override
public void setInvalid(String account) {
sessions.get(account).setStatus(CIMSession.STATUS_DISENABLE);
}
} }

View File

@ -1,5 +1,10 @@
/**
package com.farsunset.cim.nio.session; * probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.session;
import java.util.Collection; import java.util.Collection;
@ -7,7 +12,6 @@ import java.util.Collection;
/** /**
* 客户端的 session管理接口 * 客户端的 session管理接口
* 可自行实现此接口管理session * 可自行实现此接口管理session
* @author 3979434@qq.com
*/ */
public interface SessionManager { public interface SessionManager {
@ -18,6 +22,11 @@ public interface SessionManager {
*/ */
public void addSession(String account,CIMSession session); public void addSession(String account,CIMSession session);
/**
* 添加新的session
*/
public void updateSession(CIMSession session);
/** /**
* *
* @param account 客户端session的 key 一般可用 用户账号来对应session * @param account 客户端session的 key 一般可用 用户账号来对应session
@ -31,12 +40,6 @@ public interface SessionManager {
*/ */
public Collection<CIMSession> getSessions(); public Collection<CIMSession> getSessions();
/**
* 删除session
* @param session
*/
public void removeSession(CIMSession session) ;
/** /**
* 删除session * 删除session
@ -44,15 +47,17 @@ public interface SessionManager {
*/ */
public void removeSession(String account); public void removeSession(String account);
/**
* 删除session
* @param session
*/
public void setInvalid(String account);
/** /**
* session是否存在 * session是否存在
* @param session * @param session
*/ */
public boolean containsCIMSession(CIMSession ios); public boolean containsCIMSession(String account);
/**
* session获取对应的 用户 key
* @param session
*/
public String getAccount(CIMSession ios);
} }

View File

@ -6,6 +6,7 @@
<classpathentry kind="con" path="melibrary.com.genuitec.eclipse.j2eedt.core.MYECLIPSE_JAVAEE_5_CONTAINER"/> <classpathentry kind="con" path="melibrary.com.genuitec.eclipse.j2eedt.core.MYECLIPSE_JAVAEE_5_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/> <classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/> <classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
<classpathentry combineaccessrules="false" kind="src" path="/cim-server-sdk"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/Spring.aop-3.0.2.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/Spring.aop-3.0.2.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/Spring.asm-3.0.2.RELEASE.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/Spring.asm-3.0.2.RELEASE.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/Spring.beans-3.0.2.RELEASE.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/Spring.beans-3.0.2.RELEASE.jar"/>
@ -29,8 +30,8 @@
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/httpcore-4.3.2.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/httpcore-4.3.2.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/jstl-1.2.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/jstl-1.2.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/log4j.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/log4j.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/mina-core-2.0.7.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/mina-core-2.0.9.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/mina-integration-beans-2.0.0-RC1.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/mina-integration-beans-2.0.9.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/ognl-2.7.3.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/ognl-2.7.3.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/slf4j-api-1.7.5.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/slf4j-api-1.7.5.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/slf4j-nop-1.7.5.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/slf4j-nop-1.7.5.jar"/>
@ -38,6 +39,5 @@
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/struts2-core-2.1.8.1.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/struts2-core-2.1.8.1.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/xstream-1.3.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/xstream-1.3.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/xwork-core-2.1.6.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/xwork-core-2.1.6.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/cim-core-1.6.jar"/>
<classpathentry kind="output" path="WebRoot/WEB-INF/classes"/> <classpathentry kind="output" path="WebRoot/WEB-INF/classes"/>
</classpath> </classpath>

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project-module <project-module
type="WEB" type="WEB"
name="ichat-server" name="cim-server"
id="myeclipse.1329027071311" id="myeclipse.1329027071311"
context-root="/ichat-server" context-root="/cim-server"
j2ee-spec="5.0" j2ee-spec="5.0"
archive="ichat-server.war"> archive="cim-server.war">
<attributes> <attributes>
<attribute name="webrootdir" value="WebRoot" /> <attribute name="webrootdir" value="WebRoot" />
</attributes> </attributes>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>ichat-server</name> <name>cim-server</name>
<comment></comment> <comment></comment>
<projects> <projects>
</projects> </projects>

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
"
>
<!-- =============================================================== -->
<!-- MINA -->
<!-- =============================================================== -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.net.SocketAddress">
<bean class="org.apache.mina.integration.beans.InetSocketAddressEditor" />
</entry>
</map>
</property>
</bean>
<bean id="cimIoHandler" class="com.farsunset.cim.server.handler.CIMIoHandler" >
<property name="handlers">
<map>
<entry key="client_bind">
<bean class="com.farsunset.cim.handler.BindHandler" />
</entry>
<entry key="client_logout">
<bean class="com.farsunset.cim.handler.LogoutHandler" />
</entry>
<entry key="client_cimsession_closed">
<bean class="com.farsunset.cim.handler.SessionClosedHandler"/>
</entry>
<entry key="client_get_offline_message">
<bean class="com.farsunset.cim.handler.PushOfflineMessageHandler"/>
</entry>
</map>
</property>
</bean>
<bean id="CIMNioAcceptor" class="com.farsunset.cim.server.handler.CIMNioSocketAcceptor"
init-method="bind" destroy-method="unbind">
<property name="port" value="23456" />
<property name="ioHandler" ref="cimIoHandler" />
</bean>
<bean id="CIMSessionManager" class="com.farsunset.cim.server.session.DefaultSessionManager"/>
<!-- 集群服务器时 CIMSessionManager 配置
<bean id="CIMSessionManager" class="com.farsunset.lvxin.cim.session.ClusterSessionManager">
<property name="CIMSessionDao" ref="CIMSessionDaoImpl" />
</bean>
-->
</beans>

View File

@ -12,5 +12,5 @@
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
" "
> >
<bean id="contextHolder" class="com.farsunset.ichat.common.util.ContextHolder"/> <bean id="contextHolder" class="com.farsunset.cim.util.ContextHolder"/>
</beans> </beans>

View File

@ -13,11 +13,11 @@
" "
> >
<bean id="messagePusher" class="com.farsunset.ichat.cim.push.DefaultMessagePusher"> <bean id="messagePusher" class="com.farsunset.cim.push.DefaultMessagePusher">
<property name="sessionManager" ref="defaultSessionManager"/> <property name="sessionManager" ref="CIMSessionManager"/>
</bean> </bean>
<bean id="systemMessagePusher" class="com.farsunset.ichat.cim.push.SystemMessagePusher"> <bean id="systemMessagePusher" class="com.farsunset.cim.push.SystemMessagePusher">
<property name="sessionManager" ref="defaultSessionManager"/> <property name="sessionManager" ref="CIMSessionManager"/>
</bean> </bean>
</beans> </beans>

View File

@ -10,12 +10,12 @@
<constant name="struts.multipart.saveDir" value="/tmp"/> <constant name="struts.multipart.saveDir" value="/tmp"/>
<constant name="struts.multipart.parser" value="jakarta"/> <constant name="struts.multipart.parser" value="jakarta"/>
<package name="admin" extends="struts-default" namespace="/admin"> <package name="admin" extends="struts-default" namespace="/admin">
<action name="session_*" class="com.farsunset.ichat.admin.action.SessionAction" method="{1}"> <action name="session_*" class="com.farsunset.cim.admin.action.SessionAction" method="{1}">
<result name="list" type="dispatcher">/console/session/manage.jsp</result> <result name="list" type="dispatcher">/console/session/manage.jsp</result>
</action> </action>
</package> </package>
<package name="cgi" extends="struts-default" namespace="/cgi"> <package name="cgi" extends="struts-default" namespace="/cgi">
<action name="message_*" class="com.farsunset.ichat.api.action.MessageAction" method="{1}"></action> <action name="message_*" class="com.farsunset.cim.api.action.MessageAction" method="{1}"></action>
</package> </package>
</struts> </struts>

View File

@ -1,6 +1,6 @@
<%@ page language="java" pageEncoding="utf-8"%> <%@ page language="java" pageEncoding="utf-8"%>
<%@ page import="java.util.Collection"%> <%@ page import="java.util.Collection"%>
<%@ page import="com.farsunset.cim.nio.session.CIMSession"%> <%@ page import="com.farsunset.cim.server.session.CIMSession"%>
<% <%
String path = request.getContextPath(); String path = request.getContextPath();
String basePath = request.getScheme() + "://" String basePath = request.getScheme() + "://"
@ -56,7 +56,7 @@
function onImageError(obj) function onImageError(obj)
{ {
obj.src="<%=basePath%>/webclient/images/icon_head_default.png"; obj.src="<%=basePath%>/resource/img/icon.png";
} }
function openWebclient(){ function openWebclient(){
@ -92,6 +92,7 @@
<th width="4%">头像</th> <th width="4%">头像</th>
<th width="15%">账号</th> <th width="15%">账号</th>
<th width="10%">终端</th> <th width="10%">终端</th>
<th width="10%">应用版本</th>
<th width="10%">设备型号</th> <th width="10%">设备型号</th>
<th width="10%">在线时长</th> <th width="10%">在线时长</th>
<th width="28%">位置</th> <th width="28%">位置</th>
@ -117,6 +118,9 @@
<td> <td>
<%=ios.getChannel()%> <%=ios.getChannel()%>
</td> </td>
<td>
<%=ios.getClientVersion()==null?"":ios.getClientVersion()%>
</td>
<td> <td>
<%=ios.getDeviceModel()==null?"":ios.getDeviceModel()%> <%=ios.getDeviceModel()==null?"":ios.getDeviceModel()%>
</td> </td>

View File

@ -4,10 +4,11 @@
style="display: none; width: 500px; position: absolute;min-height: 600px;box-shadow: 0 0 10px -2px #0B203A;top:50px;left:50px;"> style="display: none; width: 500px; position: absolute;min-height: 600px;box-shadow: 0 0 10px -2px #0B203A;top:50px;left:50px;">
<div class="panel-heading" style="height: 80px;background: #428bca;line-height: 80px;padding: 0 10px;"> <div class="panel-heading" style="height: 80px;background: #428bca;line-height: 80px;padding: 0 10px;">
消息列表 消息列表
<span id="current_account" style="color: white;float: right;font-weight: bold;"></span> <span id="current_account" style="color: white;float: right;font-weight: bold;"></span>
</div> </div>
<div style="text-align: center;padding: 10px;">
请调用接口,或者在后台页面,推送一条消息到客户端
</div>
<div class="panel-body" id="messageList"> <div class="panel-body" id="messageList">

Some files were not shown because too many files have changed in this diff Show More