Jump to content

[Java]Annotation Identified Packet Handlers

- - - - -

  • Please log in to reply
No replies to this topic

#1
Generic

Generic

    Newbie

  • Members
  • PipPip
  • 26 posts
HandlerManager.java
package annotationassociate;

import annotationassociate.Main.Client;
import annotationassociate.Main.DataPacket;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author Jay
 */
public class HandlerManager {

    public static enum HandlerList {
        MOVEMENT("path.to.Handler");
        
        private final String className;

        private HandlerList(String className) {
            this.className = className;
        }

        public String getName() {
            return className;
        }
    }

    private static Map<Integer, Method> handlers = new HashMap<Integer, Method>();

    static {
        try {
            initialize();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static void initialize() throws ClassNotFoundException {
        for (HandlerList handler : HandlerList.values()) {
            Class c = Class.forName(handler.getName());
            for (Method method : c.getMethods()) {
                PacketIdentifier annotation = method.getAnnotation(PacketIdentifier.class);
                if (annotation != null) {
                    if (isValidMethod(method)) {
                        if (handlers.containsKey(annotation.packetId())) {
                            System.out.println("Duplicate handler for packetId: " + annotation.packetId());
                        } else {
                            handlers.put(annotation.packetId(), method);
                        }
                    } else {
                        System.out.println("Failed to add handler with method name of: " + method.getName() + " in " + handler.getName());
                    }
                }
            }
        }
    }

    private static boolean isValidMethod(Method method) {
        Class[] types = method.getParameterTypes();
        return types.length == 2 && types[0].equals(Client.class) && types[1].equals(DataPacket.class);
    }

    /**
     * @param client The client to be passed to the handler
     * @param data The DataPacket to be passed to the handler
     * @param packetId 1/2/4 byte identifier which can be specified by the user.
     */
    public static void handle(Client client, DataPacket data, int packetId) {
        Method method = handlers.get(packetId);
        try {
            if (method != null) {
                method.invoke(null, client, data);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
PacketIdentifier.java
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package annotationassociate;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *
 * @author Jay
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PacketIdentifier {
    int packetId();
}

This lets you identify methods to be used as packet handlers instead of using a switch statement/list of objects that inherit from something and putting them in a HashMap. This was just for fun, but I hope someone can find some use for it. If you want to change what's considered a valid handler look at isValidMethod inside of HandlerManager.

Handler example for a chat server using netty:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package chatservernew.net.handlers;

import chatservernew.net.Client;
import chatservernew.net.Opcodes;
import chatservernew.net.ServerHandler;
import chatservernew.util.PacketIdentifier;
import chatservernew.util.PacketTools;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;

/**
 *
 * @author Jay
 */
public class AuthHandler {
    @PacketIdentifier(packetId = Opcodes.RECV_LOGIN)
    public static void handleLogin(Client client, ChannelBuffer buffer) {
        String nick = PacketTools.readString(buffer);
        ChannelBuffer out = ChannelBuffers.buffer(2);
        out.writeByte(Opcodes.SEND_LOGIN);
        if (!ServerHandler.getNickConnections().containsKey(nick)) {
            ServerHandler.getNickConnections().put(nick, client);
            out.writeByte(1);
        } else {
            out.writeByte(0);
        }
        client.getChannel().write(out);
    }

    @PacketIdentifier(packetId = Opcodes.RECV_AUTHENTICATED)
    public static void handleAuthenticated(Client client, ChannelBuffer buffer) {
        ChannelBuffer out = ChannelBuffers.dynamicBuffer(32);
        out.writeByte(Opcodes.SEND_USERS);
        StringBuilder sb = new StringBuilder();
        for (String str : ServerHandler.getNickConnections().keySet()) {
            sb.append(str);
            sb.append(" ");
        }
        PacketTools.writeString(out, sb.toString().trim());
        client.getChannel().write(out);
    }

    @PacketIdentifier(packetId = Opcodes.RECV_CHAT)
    public static void handleChat(Client client, ChannelBuffer buffer) {
        String msg = PacketTools.readString(buffer);
        ChannelBuffer out = ChannelBuffers.buffer(msg.length() + 3);
        out.writeByte(Opcodes.SEND_CHAT);
        PacketTools.writeString(out, msg);
        for (Client user : ServerHandler.getNickConnections().values()) {
            user.getChannel().write(out);
        }
    }
}

Where the DataPacket is replaced with ChannelBuffer

Post questions/opinions. Thanks :)

Edited by Generic, 26 December 2010 - 11:51 PM.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users