import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.channel.AdaptiveReceiveBufferSizePredictor;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory;
import org.jboss.netty.channel.socket.DatagramChannel;
import org.jboss.netty.channel.socket.DatagramChannelFactory;
import org.jboss.netty.channel.socket.oio.OioDatagramChannelFactory;
import org.jboss.netty.util.AlarmManagerTimer;
import org.jboss.netty.util.AlarmManagerTimerFactory;
import com.lenovo.lsf.push.log.PushLog;
import com.lenovo.lsf.push.log.PushLog.LEVEL;
import com.lenovo.lsf.push.net.handler.PushUDPHandler;
import com.lenovo.lsf.push.net.pipeline.PushUDPPipelineFactory;
import com.lenovo.lsf.push.net.protobuf.PushUDPCommandProtos.COMMAND_TYPE;
import com.lenovo.lsf.push.net.protobuf.PushUDPCommandProtos.PUSH_UDP_COMMAND;
import com.lenovo.lsf.push.net.protobuf.PushUDPCommandProtos.PUSH_UDP_COMMAND.TTL_INIT;
import com.lenovo.lsf.push.net.protobuf.PushUDPCommandProtos.PUSH_UDP_COMMAND.TTL_INIT.Builder;
import com.lenovo.lsf.push.util.DeviceUtil;
import com.lenovo.lsf.push.util.PushWakeLock;
import com.lenovo.lsf.sdac.SDACDeviceInfo;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class PushMessageUDPImpl extends PushDAONetAware implements IPushMessage {
private Context context;
private static ConnectionlessBootstrap bootstrap;
private ChannelFuture channelFuture;
private static DatagramChannel databramChannel;
private String lastNetType="";
private String lastIPAddress="";
private String HOST;
private int PORT;
private String requestURI;
public static final String PUSH_UDP_WAKE_LOCK = "PUSH_UDP_WAKE_LOCK";
public static final int INIT_UDP_FAIL_COUNT = 0;
private int udpFailCount = INIT_UDP_FAIL_COUNT;
public static final int MAX_UDP_INIT_COUNT = 5;
public static String last_local_ip = null;
public static int ttl = 25;
private PushMessageUDPDelayRetryProxy delayProxy;
private PushUDPIntervalTunningManager tunningManager;
private AlarmManagerTimerFactory timerFactory;
//用来生成唯一的PushUDPCommand id
private static AtomicInteger requstCode = new AtomicInteger(0);
//id max
private final int MAX_TIMER = 256;
private boolean isTTLInitRunning = false;
private boolean udpInitialized = false;
public PushMessageUDPImpl(Context context) {
super(context);
// TODO Auto-generated constructor stub
this.context = context;
delayProxy = new PushMessageUDPDelayRetryProxy();
tunningManager = new PushUDPIntervalTunningManager();
timerFactory = new AlarmManagerTimerFactory(PushService.ACTION_INTERNAL_UDP_ALARM_TIMER);
}
public int getUdpFailCount() {
return udpFailCount;
}
public void setUdpFailCount(int udpFailCount) {
this.udpFailCount = udpFailCount;
}
@Override
public void resetDayPollCount() {
// TODO Auto-generated method stub
}
@Override
public void resetFailCount() {
// TODO Auto-generated method stub
udpFailCount = INIT_UDP_FAIL_COUNT;
}
@Override
public void online() {
// TODO Auto-generated method stub
start();
}
@Override
public void offline() {
// TODO Auto-generated method stub
stop();
}
public boolean isTTLInitRunning() {
return isTTLInitRunning;
}
public void setTTLInitRunning(boolean isTTLInitRunning) {
this.isTTLInitRunning = isTTLInitRunning;
}
@Override
public void start() {
// TODO Auto-generated method stub
if(isSwitchOn() && isNetAvailable() && !isEmpty()){
String currentNetType = getNetType();
String currentIPAddress = getIpAddress();
PushLog.log(context, LEVEL.INFO, "PushMessageUDPImpl.start", "lastNetType:"+lastNetType+", currentNetType:"+currentNetType);
PushLog.log(context, LEVEL.INFO, "PushMessageUDPImpl.start", "lastIPAddress:"+lastIPAddress+", currentIPAddress:"+currentIPAddress);
lastNetType = currentNetType;
lastIPAddress = currentIPAddress;
requestURI = getPushUDPRequestUrl();
if(requestURI != null && requestURI.indexOf(":") != -1) {
HOST = requestURI.substring(0, requestURI.indexOf(":"));
String portStr = requestURI.substring(requestURI.indexOf(":") + 1, requestURI.length());
try{
PORT = Integer.parseInt(portStr);
} catch (NumberFormatException e) {
e.printStackTrace();
}
PushLog.log(context, PushLog.LEVEL.INFO, "PushMessageUDPImpl.start",
"HOST:" + HOST+"PORT:"+PORT);
}
/*
if (currentIPAddress != null
&& !currentIPAddress.equals(lastIPAddress)) {
initTTL();
}
*/
if(!isTTLInitRunning()) {
initTTL();
}
}else{
Intent i = PushService.newIntent(context,PushService.ACTION_INTERNAL_UDP_STOP_ALL);
//context.sendBroadcast(i);
i = PushIntentAware.awareIntent(context, i);
context.startService(i);
}
}
void initTTL() {
setTTLInitRunning(true);
setUdpInitialized(false);
PushWakeLock.acquire(context, PUSH_UDP_WAKE_LOCK, 30);
DatagramChannelFactory f = new OioDatagramChannelFactory(
Executors.newCachedThreadPool());
bootstrap = new ConnectionlessBootstrap(f);
// Configure the pipeline factory.
bootstrap.setPipelineFactory(new PushUDPPipelineFactory(
context,timerFactory.getNewAlarmManagerTimer(context), this));
// Enable broadcast
bootstrap.setOption("broadcast", "false");
bootstrap.setOption("receiveBufferSizePredictorFactory",
new FixedReceiveBufferSizePredictorFactory(102400));
databramChannel = (DatagramChannel) bootstrap
.bind(new InetSocketAddress(0));
write();
}
void write() {
// write TTL_INIT to server
PUSH_UDP_COMMAND command = getInitTTLCommand(getUDPPushCommandId());
PushLog.log(context, PushLog.LEVEL.INFO,
"PushMessageUDPImpl.write", "send ttl init to server>>>>>>>>>>>>ttlInit:"+command.getTtlInit().getTtl());
channelFuture = databramChannel.write(command,
new InetSocketAddress(HOST,PORT));
channelFuture.addListener(new ChannelFutureListener(){
@Override
public void operationComplete(ChannelFuture future)
throws Exception {
// TODO Auto-generated method stub
if (!future.isSuccess()) {
timerFactory.destroyAlarmManagerTimer(context);
setTTLInitRunning(false);
if(future != null){
Channel channel = future.getChannel();
if(channel != null){
channel.close();
// Wait for the server to close the connection.
channel.getCloseFuture().awaitUninterruptibly();
}
}
PushLog.log(context, LEVEL.INFO, "PushMessageUDPImpl.sendTTLInitRequest", "connect fail begin to release wake lock!!!");
PushWakeLock.release(context,PUSH_UDP_WAKE_LOCK);
}
}
});
}
public PUSH_UDP_COMMAND getInitTTLCommand(int id){
// build TTL_INIT command
Builder builder = TTL_INIT.newBuilder();
String st = getSt();
builder.setSt(st==null ? "":st);
builder.setTtl(ttl);
try{
String netType = DeviceUtil.getNetType(context);
if(netType != null && !netType.equals("")) {
if(netType.equals("wifi"))
builder.setNetType(DeviceUtil.WIFI);
else if(netType.equals("mobile"))
builder.setNetType(DeviceUtil.MOBILE);
}
} catch (Exception e){
e.printStackTrace();
}
try{
String optCode = SDACDeviceInfo.getInstance().getSdacInfo(context)
.getSystemID();
if(optCode != null && !optCode.equals("")) {
int code = Integer.parseInt(optCode);
builder.setOptCode(code);
}
} catch (Exception e){
e.printStackTrace();
}
try{
String cellId = DeviceUtil.getCellId(context);
if(cellId != null && !cellId.equals("")) {
int cId = Integer.parseInt(cellId);
builder.setNetType(cId);
}
} catch (Exception e){
e.printStackTrace();
}
TTL_INIT ttlInit = builder.build();
PUSH_UDP_COMMAND command = PUSH_UDP_COMMAND.newBuilder().setId(id)
.setType(COMMAND_TYPE.TTL_INIT).setVer(PushUDPHandler.COMMAND_VERSION).setTtlInit(ttlInit).build();
return command;
}
@Override
public void stop() {
// TODO Auto-generated method stub
if(isTTLInitRunning()) {
delayProxy.cancelUDPPushRetryAlarm(context);
setTTLInitRunning(false);
resetFailCount();
PushLog.log(context, PushLog.LEVEL.INFO, "PushMessageUDPImpl.stop",
"PushMessageUDPImpl.stop");
timerFactory.destroyAlarmManagerTimer(context);
if(channelFuture != null){
Channel channel = channelFuture.getChannel();
if(channel != null){
PushLog.log(context, LEVEL.INFO, "PushMessageUDPImpl.stop", "channel has been closed by future !!!");
channel.close();
// Wait for the server to close the connection.
channel.getCloseFuture().awaitUninterruptibly();
}
}
}
}
@Override
public void udpAvaliable() {
// TODO Auto-generated method stub
}
@Override
public void udpUnAvaliable() {
// TODO Auto-generated method stub
}
@Override
public void expire(int requestCode) {
// TODO Auto-generated method stub
AlarmManagerTimer timer = timerFactory.getAlarmManagerTimer(context);
// TODO Auto-generated method stub
if(timer != null){
timer.expire(requestCode);
}else{
PushLog.log(context, LEVEL.INFO, "PushMessageUDPImpl.expire()", "push service instance has been recreated, restart initTTL !!!");
setTTLInitRunning(false);
if(channelFuture != null){
Channel channel = channelFuture.getChannel();
if(channel != null){
channel.close();
// Wait for the server to close the connection.
channel.getCloseFuture().awaitUninterruptibly();
}
}
Intent i = PushService.newIntent(context,PushService.ACTION_INTERNAL_UDP_START_ALL);
//context.sendBroadcast(i);
i = PushIntentAware.awareIntent(context, i);
context.startService(i);
}
}
@Override
public void switchOn() {
// TODO Auto-generated method stub
setSwitch(context, true);
}
@Override
public void switchOff() {
// TODO Auto-generated method stub
setSwitch(context, false);
}
public AlarmManagerTimerFactory getTimerFactory() {
return timerFactory;
}
public void setTimerFactory(AlarmManagerTimerFactory timerFactory) {
this.timerFactory = timerFactory;
}
public PushMessageUDPDelayRetryProxy getDelayProxy() {
return delayProxy;
}
public void setDelayProxy(PushMessageUDPDelayRetryProxy delayProxy) {
this.delayProxy = delayProxy;
}
public PushUDPIntervalTunningManager getTunningManager() {
return tunningManager;
}
public void setTunningManager(PushUDPIntervalTunningManager tunningManager) {
this.tunningManager = tunningManager;
}
public boolean isUdpInitialized() {
return udpInitialized;
}
public void setUdpInitialized(boolean udpInitialized) {
this.udpInitialized = udpInitialized;
}
private String getPushUDPRequestUrl() {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = (Future<String>) executor
.submit(new Callable<String>() {
@Override
public String call() throws Exception {
String addr = getServerAddr("rpsb002");
if(addr == null) {
PushLog.log(context, LEVEL.INFO, "PushMessageUDPImpl.getPushUDPRequestUrl", "get server address failed");
}else{
PushLog.log(context, LEVEL.INFO, "PushMessageUDPImpl.getPushUDPRequestUrl", "url:"+addr);
}
StringBuilder sb = new StringBuilder(addr==null ? "":addr);
PushLog.log(context, LEVEL.INFO, "PushMessageUDPImpl.getPushUDPRequestUrl", "command line is:" + sb.toString());
return sb.toString();
}
});
try {
String pushURI = future.get();
return pushURI;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
//生成全局唯一UDPPushCommand id
public int getUDPPushCommandId() {
int code = requstCode.getAndIncrement();
if (code > MAX_TIMER) {
code = 0;
requstCode = new AtomicInteger(0);
}
return code;
}
@Override
public void resetUdpAvaliable() {
// TODO Auto-generated method stub
}
}