HOME PCB
..MessageFactory.javaMessageService.javaMessageSession.javaMessageSessionImpl.javaQueueSendingThread.javaReceivingThread.javaSendObject.javaSendingThread.javaStandardReceivingThread.java
package Communication.Messages.Service;

import Communication.Messages.Handler.MessageHandler;
import Communication.Messages.Handler.Receive;
import Communication.Messages.Handler.Send;
import Communication.Messages.TCP.TCPSession;
import Communication.Messages.UDP.UDPSession;
import org.reflections.Reflections;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.DatagramSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.concurrent.ConcurrentHashMap;

public class MessageFactory
{
    private final ConcurrentHashMap messageHandlersByData = new ConcurrentHashMap<>();
    private final ConcurrentHashMap messageHandlersByName = new ConcurrentHashMap<>();
    private final ConcurrentHashMap sessions = new ConcurrentHashMap<>();
    private final ConcurrentHashMap sends = new ConcurrentHashMap<>();
    private final ConcurrentHashMap receives = new ConcurrentHashMap<>();

    private int maxSize = 0;

    private int maxNameLength = 0;

    // set default timeout to five minutes
    private int sessionTimeoutMilli = 1000 * 60 * 5;

    private static MessageFactory instance = null;

    private MessageFactory()
    {
        Reflections reflections = new Reflections();

        for (Class c : reflections.getTypesAnnotatedWith(MessageHandler.class))
        {
            MessageHandler messageHandler = getMessageHandler(c);

            if (!this.messageHandlersByData.containsKey(messageHandler.data()))
            {
                this.messageHandlersByData.put(messageHandler.data(), c);
            }
            else
            {
                throw new RuntimeException(this.messageHandlersByData.get(messageHandler.data()).getName() + " handles the same data as " + c.getName());
            }

            if (!this.messageHandlersByName.containsKey(messageHandler.name()))
            {
                this.messageHandlersByName.put(messageHandler.name(), c);
            }
            else
            {
                throw new RuntimeException(this.messageHandlersByName.get(messageHandler.name()).getName() + " has the same name as " + c.getName());
            }

            this.maxSize = this.maxSize > messageHandler.maxSize() ? this.maxSize : messageHandler.maxSize();
            this.maxNameLength = this.maxNameLength > messageHandler.name().length() ? this.maxNameLength : messageHandler.name().length();
        }
    }

    public static MessageFactory getInstance()
    {
        if (instance == null)
        {
            instance = new MessageFactory();
        }
        return instance;
    }

    public Class getMessageHandlerClass(Class data)
    {
        return this.messageHandlersByData.get(data);
    }

    public Class getMessageHandlerClass(String name)
    {
        return this.messageHandlersByName.get(name);
    }

    public int getMaxSize()
    {
        return this.maxSize;
    }

    public int getMaxNameLength() {
        return this.maxNameLength;
    }

    public static MessageHandler getMessageHandler(Class c)
    {
        return (MessageHandler) c.getAnnotation(MessageHandler.class);
    }

    public MessageSession getSession(Socket sock)
    {
        MessageSession session;
        if ((session = this.sessions.get(sock.getRemoteSocketAddress())) == null)
        {
            session = new TCPSession(sock);
            this.sessions.put(sock.getRemoteSocketAddress(), session);
        }
        return session;
    }

    public MessageSession getSession(DatagramSocket sock)
    {
        MessageSession session;
        if ((session = this.sessions.get(sock.getRemoteSocketAddress())) == null)
        {
            session = new UDPSession(sock);
            this.sessions.put(sock.getRemoteSocketAddress(), session);
        }
        return session;
    }

    public MessageSession getSession(SocketAddress address)
    {
        return this.sessions.get(address);
    }

    public Method getSendMethod(Class messageHandlerClass) throws NoSuchMethodException
    {
        Method method;
        if ((method = this.sends.get(messageHandlerClass)) == null)
        {
            method = getAnnotatedMethod(messageHandlerClass, Send.class);
            this.sends.put(messageHandlerClass, method);
        }
        return method;
    }

    public Method getReceiveMethod(Class messageHandlerClass) throws NoSuchMethodException
    {
        Method method;
        if ((method = this.receives.get(messageHandlerClass)) == null)
        {
            method = getAnnotatedMethod(messageHandlerClass, Receive.class);
            this.receives.put(messageHandlerClass, method);
        }
        return method;
    }

    private static Method getAnnotatedMethod(Class messageHandlerClass, Class annotationClass) throws NoSuchMethodException {
        Method foundMethod = null;

        for (Method method : messageHandlerClass.getMethods())
        {
            if (method.isAnnotationPresent(annotationClass))
            {
                foundMethod = method;
                break;
            }
        }

        if (foundMethod == null)
        {
            throw new NoSuchMethodException(annotationClass.getName() + " not present for Any method in " + messageHandlerClass.getName());
        }
        return foundMethod;
    }
}