package com.neverwinterdp.demandspike.yarn.worker;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.CharsetUtil;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import com.neverwinterdp.message.Message;
import com.neverwinterdp.netty.http.client.AsyncHttpClient;
import com.neverwinterdp.netty.http.client.ResponseHandler;
import com.neverwinterdp.sparkngin.Ack;
import com.neverwinterdp.util.JSONSerializer;
public class MessageSender {
private AsyncHttpClient client ;
private LinkedHashMap<String, Message> messages ;
private int bufferSize ;
private int errorCount ;
public MessageSender(String brokerConnect, int bufferSize) throws Exception {
System.out.println("BROKER CONNECT: " + brokerConnect);
String[] array = brokerConnect.split(":") ;
String host = array[0] ;
int port = Integer.parseInt(array[1]) ;
client = new AsyncHttpClient (host, port, new MessageResponseHandler()) ;
this.bufferSize = bufferSize ;
messages = new LinkedHashMap<String, Message>() ;
}
public int getErrorCount() { return errorCount ;}
public void send(Message message, long timeout) throws Exception {
synchronized(messages) {
if(messages.size() >= bufferSize) {
messages.wait(timeout);
if(messages.size() >= bufferSize) {
throw new TimeoutException("fail to send the message in " + timeout + "ms") ;
}
}
client.post("/message/json", message);
String messageId = message.getHeader().getKey() ;
messages.put(messageId, message) ;
}
}
public void onFailedMessage(Ack ack, Message message) {
errorCount++ ;
System.out.println("Failed message: " + ack.getMessageId() + ", message = " + ack.getMessage());
}
public Map<String, Message> getWaitingMessages() {
return this.messages ;
}
public void waitAndClose(long waitTime) throws InterruptedException {
if(messages.size() > 0) {
synchronized(messages) {
long stopTime = System.currentTimeMillis() + waitTime ;
while(stopTime > System.currentTimeMillis() && messages.size() > 0) {
long timeToWait = stopTime - System.currentTimeMillis() ;
messages.wait(timeToWait);
}
}
}
client.close();
}
public void close() {
if(messages.size() > 0) {
throw new RuntimeException("There are " + messages.size() + " messages waitting for ack") ;
}
client.close();
}
class MessageResponseHandler implements ResponseHandler {
public void onResponse(HttpResponse response) {
if(response instanceof HttpContent) {
HttpContent content = (HttpContent) response;
String json = content.content().toString(CharsetUtil.UTF_8);
Ack ack = JSONSerializer.INSTANCE.fromString(json, Ack.class) ;
String messageId = (String) ack.getMessageId() ;
Message message = messages.get(messageId) ;
if(!Ack.Status.OK.equals(ack.getStatus())) {
onFailedMessage(ack, message) ;
}
synchronized(messages) {
messages.remove(messageId) ;
messages.notify() ;
}
}
}
}
}