All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.datasecs.hydra.shared.protocol.impl.HydraProtocol Maven / Gradle / Ivy

The newest version!
package de.datasecs.hydra.shared.protocol.impl;

import de.datasecs.hydra.shared.handler.Session;
import de.datasecs.hydra.shared.handler.listener.HydraSessionConsumer;
import de.datasecs.hydra.shared.handler.listener.HydraSessionListener;
import de.datasecs.hydra.shared.protocol.Protocol;
import de.datasecs.hydra.shared.protocol.packets.Packet;
import de.datasecs.hydra.shared.protocol.packets.PacketId;
import de.datasecs.hydra.shared.protocol.packets.StandardPacket;
import de.datasecs.hydra.shared.protocol.packets.listener.HydraPacketListener;
import de.datasecs.hydra.shared.protocol.packets.listener.PacketHandler;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.DatagramPacket;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Created with love by DataSecs on 29.09.2017.
 */
public class HydraProtocol implements Protocol {

    private Map> packets = new HashMap<>();

    private Map, Byte> packetBytes = new HashMap<>();

    private Map, Method> packetListenerMethods = new HashMap<>();

    private Set sessions = new HashSet<>();

    private Session clientSession;

    private HydraPacketListener packetListener;

    private HydraSessionListener sessionListener;

    private HydraSessionConsumer sessionConsumer;

    public HydraProtocol() {
        // Register StandardPacket to be ready out of the box
        registerPacket(StandardPacket.class);
    }

    @Override
    public Packet createPacket(byte id) {
        try {
            return packets.get(id).newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            System.err.printf("Packet %s.class might hasn't got an empty constructor!%n\n", packets.get(id).getSimpleName());
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public byte getPacketId(Packet packet) {
        return packetBytes.get(packet.getClass());
    }

    @Override
    public void registerPacket(Class clazz) {
        if (clazz == null) {
            throw new IllegalArgumentException("clazz can't be null!");
        }

        PacketId packetId = clazz.getAnnotation(PacketId.class);

        if (packetId == null) {
            throw new NullPointerException(String.format("Annotation of packet %s.class not found. Annotation might not be present!", clazz.getSimpleName()));
        }

        byte id = packetId.value();

        if (packets.containsKey(id)) {
            throw new IllegalArgumentException(String.format("Packet with id %s is already registered!", id));
        }

        packets.put(id, clazz);
        packetBytes.put(clazz, id);
    }

    @Override
    public void registerListener(HydraPacketListener packetListener) {
        if (packetListener == null) {
            throw new IllegalArgumentException("packetListener can't be null!");
        }

        this.packetListener = packetListener;

        for (Method method : packetListener.getClass().getMethods()) {
            if (method.isAnnotationPresent(PacketHandler.class)) {
                if (method.getParameterCount() == 2) {
                    Class clazz = method.getParameterTypes()[0];
                    if (Packet.class.isAssignableFrom(clazz)) {
                        if (!packetListenerMethods.containsKey(clazz)) {
                            packetListenerMethods.put(clazz, method);
                        } else {
                            throw new IllegalArgumentException(String.format("It's not possible to assign multiple PacketHandler methods for packet %s.class", clazz.getSimpleName()));
                        }
                    } else {
                        throw new IllegalArgumentException(String.format("%s is not a deriving class of Packet.class. Make sure the first argument is a deriving class of Packet.class. The first argument of the PacketHandler method is the packet it is supposed to handle!", clazz.getSimpleName()));
                    }
                } else {
                    throw new IllegalArgumentException("There are just 2 arguments allowed for a PacketHandler method!");
                }
            }
        }
    }

    @Override
    public void callPacketListener(Packet packet, Session session) {
        try {
            packetListenerMethods.get(packet.getClass()).invoke(packetListener, packet.getClass().cast(packet), session);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();

            StringBuilder error = new StringBuilder("\n\nThe following packets are registered, but do not have a listener:\n");
            for (Class p : packets.values()) {
                if (!packetListenerMethods.containsKey(p)) {
                    error.append(" - ").append(p.getSimpleName()).append(".class").append("\n");
                }
            }
            error.append("Not using a listener for a packet may cause an exception.\n");

            error.append("Other important data:\n");
            error.append("Packet: ").append(packet).append("\n");
            error.append("Packet class: ").append(packet.getClass()).append("\n");
            error.append("Packet listener: ").append(packetListener).append("\n");
            error.append("Casted packet: ").append(packet.getClass().cast(packet)).append("\n");
            error.append("Result from packetListener method search (if this is null you do not have a listener for the packet): ").append(packetListenerMethods.get(packet.getClass()));

            System.err.println(error.toString());
        }
    }

    @Override
    public void callPacketListener(DatagramPacket packet, Session session) {

    }

    @Override
    public void addSessionListener(HydraSessionListener sessionListener) {
        this.sessionListener = sessionListener;
    }

    @Override
    public void callSessionListener(boolean connected, Session session) {
        if (connected) {
            sessionListener.onConnected(session);
        } else {
            sessionListener.onDisconnected(session);
        }
    }

    @Override
    public void addSessionConsumer(HydraSessionConsumer sessionConsumer) {
        this.sessionConsumer = sessionConsumer;
    }

    @Override
    public void callSessionConsumer(boolean connected, Session session) {
        if (connected) {
            sessionConsumer.getOnConnectedConsumer().accept(session);
        } else {
            sessionConsumer.getOnDisconnectedConsumer().accept(session);
        }
    }

    @Override
    public void setClientSession(Session clientSession) {
        this.clientSession = clientSession;
    }

    @Override
    public Session getClientSession() {
        return clientSession;
    }

    @Override
    public void addSession(Session session) {
        sessions.add(session);
    }

    @Override
    public void removeSession(Session session) {
        sessions.remove(session);
    }

    @Override
    public Map> getRegisteredPackets() {
        return packets;
    }

    @Override
    public Map, Method> getRegisteredPacketListenerMethods() {
        return packetListenerMethods;
    }

    @Override
    public Set getSessions() {
        return sessions;
    }

    @Override
    public HydraSessionListener getSessionListener() {
        return sessionListener;
    }

    public HydraSessionConsumer getSessionConsumer() {
        return sessionConsumer;
    }

    @Override
    public HydraPacketListener getPacketListener() {
        return packetListener;
    }

    @Override
    public String toString() {
        return "HydraProtocol{" +
                "registered packets=" + packets +
                ", registered packetListenerMethods=" + packetListenerMethods +
                '}';
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy