package com.cari.voip.keyboard.stack;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Semaphore;
import com.cari.voip.keyboard.stack.events.*;
import com.cari.voip.keyboard.stack.parsers.*;
public class PacketReader {
private CCKPConnection connection;
private Thread readerThread;
private Thread executorThread;
private PacketParser parser;
private boolean done;
private final BlockingQueue<Packet> queue;
protected final Map<TrapEventListener,TrapEventListenerWrapper> trapEventListeners =
new ConcurrentHashMap<TrapEventListener,TrapEventListenerWrapper>();
protected final Map<ReplyListener,ReplyListenerWrapper> replyListeners =
new ConcurrentHashMap<ReplyListener,ReplyListenerWrapper>();
protected final Collection<PacketParseExceptionListener> packetParseExceptionListeners =
new CopyOnWriteArrayList<PacketParseExceptionListener>();
private static int invalidPacket = 0;
protected PacketReader(CCKPConnection connection){
this.queue = new ArrayBlockingQueue<Packet>(500,true);
this.connection = connection;
init();
}
protected void init() {
done = false;
this.readerThread = new Thread(){
public void run(){
parsePackets(this);
}
};
this.readerThread.setName("CCKP Packet Reader");
this.readerThread.setDaemon(true);
this.executorThread = new Thread(){
public void run(){
executePackets(this);
}
};
this.executorThread.setName("CCKP Packets Executor");
this.executorThread.setDaemon(true);
}
public void resetParser() {
this.parser = this.connection.parser;
}
public void startup() {
resetParser();
this.readerThread.start();
this.executorThread.start();
}
public void shutdown(){
done = true;
synchronized(queue){
queue.notifyAll();
}
/*try {
this.readerThread.join();
//this.executorThread.join();
} catch (InterruptedException e) {
}*/
}
public void cleanup(){
this.trapEventListeners.clear();
this.replyListeners.clear();
}
protected void parsePackets(Thread thread) {
while(!done && this.readerThread == thread){
if(this.parser != null){
try{
Packet packet = this.parser.getNextPacket();
if(packet != null){
try{
this.queue.put(packet);
synchronized(queue){
queue.notifyAll();
}
}
catch(InterruptedException e){
}
}
//else{
// System.out.print("\nnull packet");
//}
}
catch(PacketParseException e){
this.notifyPacketParseException(e);
}
}
}
}
protected void executePackets(Thread thread) {
while(!done && this.executorThread == thread){
Packet packet = this.nextPacket();
if(packet != null){
executePacket(packet);
}
}
}
protected Packet nextPacket(){
Packet packet = null;
while(!done && (packet = this.queue.poll()) == null){
try{
synchronized(queue){
queue.wait();
}
}catch(InterruptedException ie){
//do nothing
}
}
return packet;
}
protected void executePacket(Packet packet) {
if(packet.isReply()){
Packet cmd = this.connection.packetWriter.nextPacketSended();
if(cmd != null ){
ReplyListener replyListener = cmd.getReplyHandler();
if(replyListener != null ){
replyListener.processReply(cmd,packet);
}
this.fireReplyListeners(cmd,packet);
}
}
else if(packet.isTrap()){
this.fireTrapEventListeners(packet);
}
}
public void addReplyListeners(ReplyListener replyListener,PacketFilter packetFilter){
this.replyListeners.put(replyListener,
new ReplyListenerWrapper(replyListener,packetFilter));
}
public void removeReplyListeners(ReplyListener replyListener){
this.replyListeners.remove(replyListener);
}
public void addTrapEventListeners(TrapEventListener trapEventListener,PacketFilter packetFilter){
this.trapEventListeners.put(trapEventListener,
new TrapEventListenerWrapper(trapEventListener,packetFilter));
}
public void removeTrapEventListeners(TrapEventListener trapEventListener){
this.trapEventListeners.remove(trapEventListener);
}
protected void fireReplyListeners(Packet command, Packet reply) {
for(ReplyListenerWrapper replyListenerWrapper:this.replyListeners.values()){
replyListenerWrapper.notifyListener(command, reply);
}
}
protected void fireTrapEventListeners(Packet event) {
for(TrapEventListenerWrapper trapEventListenerWrapper:this.trapEventListeners.values()){
trapEventListenerWrapper.notifyListener(event);
}
}
public void addPacketParseExceptionListener(PacketParseExceptionListener listener){
this.packetParseExceptionListeners.add(listener);
}
public void removePacketParseExceptionListener(PacketParseExceptionListener listener){
this.packetParseExceptionListeners.remove(listener);
}
public void notifyPacketParseException(PacketParseException e){
invalidPacket++;
for(PacketParseExceptionListener listener : this.packetParseExceptionListeners){
try{
listener.precessPacketParseException(e);
}
catch(Exception e2){
e2.printStackTrace();
}
}
//if(invalidPacket >= CCKPConfiguration.getInvalidPacketsNumber2shutdown()){
this.connection.notifyConnectionError(e);
//}
}
}