package Communication.Messages.Service;
import Common.Utils;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap;
public abstract class MessageSession
{
private final ConcurrentHashMap messageHandlers = new ConcurrentHashMap<>();
public final ConcurrentHashMap properties = new ConcurrentHashMap<>();
public abstract boolean isClosed();
public abstract DataInputStream getReceiveStream() throws IOException;
protected abstract void sendImpl(final Object o, final Object messageHandler, final Method send) throws IOException, InvocationTargetException, IllegalAccessException;
public abstract InetSocketAddress getSocketAddress();
private Object getMessageHandler(Object data) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
return this.getMessageHandler(data.getClass());
}
private Object getMessageHandler(Class data) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
return this.getMessageHandlerObject(MessageFactory.getInstance().getMessageHandlerClass(data));
}
private Object getMessageHandler(String name) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
return this.getMessageHandlerObject(MessageFactory.getInstance().getMessageHandlerClass(name));
}
private Object getMessageHandlerObject(Class c) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Object o;
if ((o = this.messageHandlers.get(c)) == null)
{
o = c.getConstructor().newInstance();
this.messageHandlers.put(c, o);
}
return o;
}
public final synchronized void send(Object o) throws IOException
{
try {
final Object messageHandler = this.getMessageHandler(o);
Method send = MessageFactory.getInstance().getReceiveMethod(messageHandler.getClass());
this.sendImpl(o, messageHandler, send);
} catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public final synchronized void send(Object... objs) throws IOException
{
for (Object o : objs) {
this.send(o);
}
}
public void receive() throws IOException
{
final DataInputStream dis;
try
{
dis = this.getReceiveStream();
byte[] messageNameBytes = new byte[dis.readInt()];
dis.read(messageNameBytes);
final String messageName = new String(messageNameBytes, Utils.getDefaultCharset());
final Object messageHandler = this.getMessageHandler(messageName);
new Thread(() -> {
try
{
MessageFactory.getInstance().getReceiveMethod(messageHandler.getClass()).invoke(messageHandler, dis, this);
}
catch (Exception e)
{
e.printStackTrace();
}
}).start();
}
catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e)
{
// should not occur
throw new RuntimeException(e);
}
}
}