package com.taobao.zeus.socket.master;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import com.taobao.zeus.schedule.mvc.ScheduleInfoLog;
import com.taobao.zeus.socket.SocketLog;
import com.taobao.zeus.socket.master.reqresp.MasterBeHeartBeat;
import com.taobao.zeus.socket.master.reqresp.MasterBeUpdate;
import com.taobao.zeus.socket.master.reqresp.MasterBeWebCancel;
import com.taobao.zeus.socket.master.reqresp.MasterBeWebDebug;
import com.taobao.zeus.socket.master.reqresp.MasterBeWebExecute;
import com.taobao.zeus.socket.protocol.Protocol.Operate;
import com.taobao.zeus.socket.protocol.Protocol.Request;
import com.taobao.zeus.socket.protocol.Protocol.Response;
import com.taobao.zeus.socket.protocol.Protocol.SocketMessage;
import com.taobao.zeus.socket.protocol.Protocol.WebOperate;
import com.taobao.zeus.socket.protocol.Protocol.WebRequest;
import com.taobao.zeus.socket.protocol.Protocol.WebResponse;
import com.taobao.zeus.socket.protocol.Protocol.SocketMessage.Kind;
public class MasterHandler extends SimpleChannelUpstreamHandler{
private CompletionService<ChannelResponse> completionService=new ExecutorCompletionService<ChannelResponse>(Executors.newCachedThreadPool());
private class ChannelResponse{
Channel channel;
WebResponse resp;
public ChannelResponse(Channel channel,WebResponse resp){
this.channel=channel;
this.resp=resp;
}
}
private MasterContext context;
public MasterHandler(MasterContext context){
this.context=context;
new Thread(){
public void run() {
while(true){
try {
Future<ChannelResponse> f=completionService.take();
ChannelResponse resp=f.get();
resp.channel.write(wapper(resp.resp));
} catch (Exception e) {
ScheduleInfoLog.error("master handler,future take", e);
}
}
};
}.start();
}
private SocketMessage wapper(WebResponse resp){
return SocketMessage.newBuilder().setKind(Kind.WEB_RESPONSE).setBody(resp.toByteString()).build();
}
private MasterBeHeartBeat beHeartBeat=new MasterBeHeartBeat();
private MasterBeUpdate beUpdate=new MasterBeUpdate();
private MasterBeWebCancel beWebCancel=new MasterBeWebCancel();
private MasterBeWebExecute beWebExecute=new MasterBeWebExecute();
private MasterBeWebDebug beDebug=new MasterBeWebDebug();
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
final Channel channel=ctx.getChannel();
SocketMessage sm=(SocketMessage) e.getMessage();
if(sm.getKind()==Kind.REQUEST){
final Request request=Request.newBuilder().mergeFrom(sm.getBody()).build();
if(request.getOperate()==Operate.HeartBeat){
beHeartBeat.beHeartBeat(context, channel, request);
}
}else if(sm.getKind()==Kind.WEB_REUQEST){
final WebRequest request=WebRequest.newBuilder().mergeFrom(sm.getBody()).build();
if(request.getOperate()==WebOperate.ExecuteJob){
completionService.submit(new Callable<ChannelResponse>() {
public ChannelResponse call() throws Exception {
return new ChannelResponse(channel,beWebExecute.beWebExecute(context,request));
}
});
}else if(request.getOperate()==WebOperate.CancelJob){
completionService.submit(new Callable<ChannelResponse>() {
public ChannelResponse call() throws Exception {
return new ChannelResponse(channel,beWebCancel.beWebCancel(context,request));
}
});
}else if(request.getOperate()==WebOperate.UpdateJob){
completionService.submit(new Callable<ChannelResponse>() {
public ChannelResponse call() throws Exception {
return new ChannelResponse(channel,beUpdate.beWebUpdate(context,request));
}
});
}else if(request.getOperate()==WebOperate.ExecuteDebug){
completionService.submit(new Callable<ChannelResponse>() {
public ChannelResponse call() throws Exception {
return new ChannelResponse(channel, beDebug.beWebExecute(context, request));
}
});
}
}else if(sm.getKind()==Kind.RESPONSE){
for(ResponseListener lis:new ArrayList<ResponseListener>(listeners)){
lis.onResponse(Response.newBuilder().mergeFrom(sm.getBody()).build());
}
}else if(sm.getKind()==Kind.WEB_RESPONSE){
for(ResponseListener lis:new ArrayList<ResponseListener>(listeners)){
lis.onWebResponse(WebResponse.newBuilder().mergeFrom(sm.getBody()).build());
}
}
super.messageReceived(ctx, e);
}
@Override
public void channelConnected(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
context.getWorkers().put(ctx.getChannel(), new MasterWorkerHolder(ctx.getChannel()));
Channel channel=ctx.getChannel();
SocketAddress addr=channel.getRemoteAddress();
SocketLog.info("worker connected , :"+addr.toString());
super.channelConnected(ctx, e);
}
@Override
public void channelDisconnected(ChannelHandlerContext ctx,
ChannelStateEvent e) throws Exception {
SocketLog.info("worker disconnect :"+ctx.getChannel().getRemoteAddress().toString());
context.getMaster().workerDisconnectProcess(ctx.getChannel());
super.channelDisconnected(ctx, e);
}
private List<ResponseListener> listeners=new CopyOnWriteArrayList<ResponseListener>();
public void addListener(ResponseListener listener){
listeners.add(listener);
}
public void removeListener(ResponseListener listener){
listeners.remove(listener);
}
public static interface ResponseListener{
public void onResponse(Response resp);
public void onWebResponse(WebResponse resp);
}
}