/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.pieShare.pieTools.piePlate.service.loophole;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashMap;
import org.pieShare.pieTools.piePlate.model.message.loopHoleMessages.RegisterMessage;
import org.pieShare.pieTools.piePlate.model.message.loopHoleMessages.api.IUdpMessage;
import org.pieShare.pieTools.piePlate.service.loophole.api.ILoopHoleFactory;
import org.pieShare.pieTools.piePlate.service.loophole.api.ILoopHoleService;
import org.pieShare.pieTools.piePlate.service.serializer.api.ISerializerService;
import org.pieShare.pieTools.piePlate.service.serializer.exception.SerializerServiceException;
import org.pieShare.pieTools.piePlate.task.LoopHoleConnectionTask;
import org.pieShare.pieTools.piePlate.task.LoopHoleListenerTask;
import org.pieShare.pieTools.pieUtilities.service.beanService.IBeanService;
import org.pieShare.pieTools.pieUtilities.service.idService.api.IIDService;
import org.pieShare.pieTools.pieUtilities.service.pieExecutorService.PieExecutorService;
import org.pieShare.pieTools.pieUtilities.service.pieExecutorService.PieExecutorTaskFactory;
import org.pieShare.pieTools.pieUtilities.service.pieLogger.PieLogger;
/**
*
* @author Richard
*/
public class LoopHoleService implements ILoopHoleService {
private int localPort;
private String localIP;
private DatagramSocket socket = null;
private String serverIP;
private int serverPort;
private IBeanService beanService;
private IIDService idService;
private PieExecutorTaskFactory executorFactory;
private ISerializerService serializerService;
private HashMap<String, LoopHoleConnectionTask> waitForAckQueue;
private String localLoopHoleID;
private String name;
private PieExecutorService executorService;
private LoopHoleListenerTask listenerTask;
private ILoopHoleFactory loopHoleFactory;
private boolean localLoopHoleComplete;
private boolean clientLoopHoleComplete;
private InetSocketAddress clientAddress;
public LoopHoleService() {
serverPort = 6312;
serverIP = "server.piesystems.org";
InetAddress IP = null;
try {
IP = InetAddress.getLocalHost();
} catch (UnknownHostException ex) {
PieLogger.error(this.getClass(), "Error getting IP Address of client", ex);
}
localIP = IP.getHostAddress();
//Will be set by setter from factory
this.localPort = -1;
localLoopHoleComplete = false;
clientLoopHoleComplete = false;
}
@Override
public void init() {
PieLogger.info(this.getClass(), String.format("LoopHoleService startet at IP: %s, Port: %s.", localIP, localPort));
try {
this.socket = new DatagramSocket(localPort);
} catch (SocketException ex) {
PieLogger.error(this.getClass(), "Error creating DatagramSocket of client", ex);
}
localLoopHoleID = idService.getNewID();
waitForAckQueue = new HashMap<>();
listenerTask = beanService.getBean(LoopHoleListenerTask.class);
listenerTask.setSocket(socket);
executorService.execute(listenerTask);
register();
}
@Override
public void setLocalPort(int port) {
this.localPort = port;
}
public void setExecutorService(PieExecutorService executorService) {
this.executorService = executorService;
}
public void setLoopHoleFactory(ILoopHoleFactory loopHoleFactory) {
this.loopHoleFactory = loopHoleFactory;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getLocalLoopID() {
return this.localLoopHoleID;
}
public void setSerializerService(ISerializerService serializerService) {
this.serializerService = serializerService;
}
public void setExecutorFactory(PieExecutorTaskFactory executorFactory) {
this.executorFactory = executorFactory;
}
public void setIdService(IIDService idService) {
this.idService = idService;
}
public void setBeanService(IBeanService beanService) {
this.beanService = beanService;
}
@Override
public synchronized void ackArrived(String fromid) {
if (waitForAckQueue.containsKey(fromid)) {
waitForAckQueue.get(fromid).ackArrived();
removeTaskFromAckWaitQueue(fromid);
}
}
private synchronized void loopHoleComplete() {
if (clientLoopHoleComplete && localLoopHoleComplete) {
listenerTask.stop();
socket.close();
loopHoleFactory.addLocalUsedPort(localPort);
loopHoleFactory.newClientAvailable(clientAddress, socket);
}
}
@Override
public void clientCompletedLoopHole() {
clientLoopHoleComplete = true;
loopHoleComplete();
}
@Override
public void removeTaskFromAckWaitQueue(String id) {
waitForAckQueue.remove(id);
}
@Override
public void addInWaitFromAckQueu(String id, LoopHoleConnectionTask task) {
waitForAckQueue.put(id, task);
}
@Override
public void newClientAvailable(InetSocketAddress address) {
clientAddress = address;
localLoopHoleComplete = true;
loopHoleComplete();
}
@Override
public void register() {
RegisterMessage message = beanService.getBean(RegisterMessage.class);
message.setPrivateHost(localIP);
message.setPrivatePort(localPort);
message.setName(name);
message.setLocalLoopID(localLoopHoleID);
loopHoleFactory.insertLoopHoleService(message.getLocalLoopID(), this);
loopHoleFactory.sendToServer(socket, message);
}
@Override
public synchronized void send(IUdpMessage msg, InetSocketAddress address) {
try {
msg.setSenderID(loopHoleFactory.getClientID());
byte[] bytes = serializerService.serialize(msg);
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address.getAddress(), address.getPort());
socket.send(packet);
Thread.sleep(500);
} catch (SerializerServiceException ex) {
PieLogger.error(this.getClass(), "Error serializing message", ex);
} catch (UnknownHostException ex) {
PieLogger.error(this.getClass(), "UnknownHostException", ex);
} catch (IOException ex) {
PieLogger.error(this.getClass(), "IOException", ex);
} catch (InterruptedException ex) {
PieLogger.error(this.getClass(), "InterruptedException", ex);
}
}
@Override
public void sendToServer(IUdpMessage msg) {
this.loopHoleFactory.sendToServer(socket, msg);
}
}