/*
* Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software;Designed and Developed mainly by many Chinese
* opensource volunteers. you can redistribute it and/or modify it under the
* terms of the GNU General Public License version 2 only, as published by the
* Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Any questions about this component can be directed to it's project Web address
* https://code.google.com/p/opencloudb/.
*
*/
package com.talent.nio.communicate.send;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.talent.nio.api.Packet;
import com.talent.nio.communicate.ChannelContext;
import com.talent.nio.communicate.handler.PacketHandlerProxy;
import com.talent.nio.communicate.handler.intf.BlockSupportPacketHandler;
import com.talent.nio.communicate.handler.intf.MessageChangeListener;
import com.talent.nio.communicate.util.StatUtils;
/**
*
* @author 谭耀武
* @date 2012-08-09
*
*/
public class SendUtils
{
private static final Logger log = LoggerFactory.getLogger(SendUtils.class);
/**
* key: ChannelContext; value:消息量
*/
private static Map<ChannelContext, AtomicLong> mapOfSocketChannelContextAndMsgCount = new HashMap<ChannelContext, AtomicLong>();
/**
* key: ChannelContext; value:任务被提交的次数
*/
private static Map<ChannelContext, AtomicLong> mapOfSocketChannelContextAndSubmitCount = new HashMap<ChannelContext, AtomicLong>();
/**
* key: ChannelContext; value:消息量(字节)
*/
private static Map<ChannelContext, AtomicLong> mapOfSocketChannelContextAndMsgSize = new HashMap<ChannelContext, AtomicLong>();
/**
*
* @author tanyaowu
* @param ChannelContext
* @return
*/
public static void resumeCount(ChannelContext channelContext)
{
StatUtils.resumeCount(channelContext.getSendRunnable(), mapOfSocketChannelContextAndMsgCount.get(channelContext),
mapOfSocketChannelContextAndSubmitCount.get(channelContext), mapOfSocketChannelContextAndMsgSize.get(channelContext));
}
/**
* 从缓存中删除channelContext对应的记录
*
* @param channelContext
* @return
*/
public static void removeStat(ChannelContext channelContext)
{
synchronized (mapOfSocketChannelContextAndMsgCount)
{
mapOfSocketChannelContextAndMsgCount.remove(channelContext);
mapOfSocketChannelContextAndSubmitCount.remove(channelContext);
mapOfSocketChannelContextAndMsgSize.remove(channelContext);
}
}
/**
* 保存统计量
*
* @param channelContext
* @param msgCount
* @param submitCount
* @param msgSize
*/
public static void recordStat(ChannelContext channelContext, AtomicLong msgCount, AtomicLong submitCount, AtomicLong msgSize)
{
synchronized (channelContext)
{
mapOfSocketChannelContextAndMsgCount.put(channelContext, msgCount);
mapOfSocketChannelContextAndSubmitCount.put(channelContext, submitCount);
mapOfSocketChannelContextAndMsgSize.put(channelContext, msgSize);
}
}
public static AtomicLong getRecordMsgCount(ChannelContext channelContext)
{
return mapOfSocketChannelContextAndMsgCount.get(channelContext);
}
public static AtomicLong getRecordSubmitCount(ChannelContext channelContext)
{
return mapOfSocketChannelContextAndSubmitCount.get(channelContext);
}
public static AtomicLong getRecordMsgSize(ChannelContext channelContext)
{
return mapOfSocketChannelContextAndMsgSize.get(channelContext);
}
/**
* 发送数据前,先检查链路的一些情况
*
* @param packet
* @param channelContext
* @param isNeedAppOn
* @return
* @throws Exception
*/
private static boolean checkBeforeSend(Packet packet, ChannelContext channelContext, boolean isNeedAppOn) throws Exception
{
if (packet == null)
{
log.error("{} is null", Packet.class.getSimpleName());
}
if (channelContext == null)
{
log.error("{} is null", ChannelContext.class.getSimpleName());
throw new Exception(ChannelContext.class.getSimpleName() + " is null");
}
if (isNeedAppOn && (!channelContext.isAppOn()))
{
log.error("isNeedAppOn: " + isNeedAppOn + ", link is off, the state is " + channelContext.getConnectionState());
throw new Exception("isNeedAppOn: " + isNeedAppOn + ", link is off, the state is " + channelContext.getConnectionState());
}
return true;
}
@SuppressWarnings("finally")
public static Packet synSend(Packet packet, boolean isNeedAppOn, long timeout, ChannelContext channelContext) throws Exception
{
try
{
packet.setSyn(true);
send(packet, isNeedAppOn, channelContext);
synchronized (packet)
{
try
{
log.debug("waiting syn message...");
packet.wait(timeout);
} catch (InterruptedException e)
{
log.error("", e);
}
}
} catch (Exception e)
{
log.error("", e);
} finally
{
PacketHandlerProxy packetHandlerProxy = (PacketHandlerProxy) channelContext.getPacketHandler();
Packet receivedPacket = packetHandlerProxy.removeSynSeqNo(packet.getSeqNo());
if (receivedPacket == null)
{
log.error("receivedPacket is null");
return null;
}
if (receivedPacket != packet)
{
log.debug("successful for synSending, packet is {}", packet);
return receivedPacket;
} else
{
log.error("timeout for synSending, packet is {}", packet);
return null;
}
}
}
public static boolean asySend(Packet packet, boolean isNeedAppOn, ChannelContext channelContext) throws Exception
{
packet.setSyn(false);
return send(packet, isNeedAppOn, channelContext);
}
private static boolean send(Packet packet, boolean isNeedAppOn, ChannelContext channelContext) throws Exception
{
if (!isNeedAppOn)
{
return PacketSender.send(packet, channelContext);
} else
{
if (checkBeforeSend(packet, channelContext, isNeedAppOn))
{
return PacketSender.send(packet, channelContext);
} else
{
return false;
}
}
}
@SuppressWarnings("finally")
public static List<Packet> blockSend(Packet packet, MessageChangeListener msgChangeListener, boolean isNeedAppOn, long timeout,
ChannelContext channelContext) throws Exception
{
final BlockSupportPacketHandler packetHandler = (BlockSupportPacketHandler) channelContext.getPacketHandler();
try
{
packetHandler.setMsgChangeListener(msgChangeListener);
synchronized (packetHandler)
{
int count = 0;
while (packetHandler.isRunning())
{
count++;
if (count * 500 >= timeout)
{
log.warn("wait timeout");
break;
}
log.debug("packetHandler.isRunning() = true");
Thread.sleep(500);
}
packetHandler.setRunning(true);
send(packet, isNeedAppOn, channelContext);
synchronized (packet)
{
try
{
log.debug("waiting blocking message");
packet.wait(timeout);
} catch (Exception e)
{
log.error(e.getMessage(), e);
}
}
}
} catch (Exception e)
{
throw e;
} finally
{
new Thread(new Runnable()
{
@Override
public void run()
{
try
{
Thread.sleep(1000 * 5);
} catch (InterruptedException e)
{
log.error(e.getMessage(), e);
}
BlockSupportPacketHandler.removeKey(packetHandler);
packetHandler.setRunning(false);
}
}).start();
Packet receivedPacket = BlockSupportPacketHandler.getKey(packetHandler);
if (receivedPacket == null)
{
log.error("receivedPacket is null");
throw new Exception("receivedPacket is null");
}
if (receivedPacket != packet)
{
log.info("successful for blockSending, packet is {}", packet);
return packetHandler.getReceivedPackets();
} else
{
log.error("timeout for blockSending, packet is " + packet);
throw new Exception("timeout for blockSending, packet is " + packet);
}
}
}
}