Hello, Freakin world!

[채팅앱][클라이언트] EventHandler 코드 작성하기 본문

Toy Project/채팅 앱 만들기

[채팅앱][클라이언트] EventHandler 코드 작성하기

johnna_endure 2020. 3. 1. 04:18

메서드 설명

- getHandlerMap() 

이 메서드는 클래스 내에 존재하는 @Event 애너테이션이 달린 메서드들을 자신의 메서드명(event명)으로 매핑한 맵을 반환한다. (내가 임의로 메서드명과 이벤트명이 같아지도록 구현함) 

 

그 과정에서 Stream api와 Reflection api를 사용했다.

 

- delegate() 

handler 맵을 순회하면서 전달받은 key에 포함된 eventName 값을 이용해 이와 일치하는 Method를 찾는다.

그리고 찾은 method를 호출한다. 

 

 

또 다른 중요 키포인트

이 클래스는 외부에 delegate() 만을 노출한다.

 

직접적으로 핸들러가 호출되는 일은 없다.

 

이는 클래스 사용자가 어떤 api를 쓸지 고민할 필요가 없게 만든다. 

 

 

후~ 뼈대 작업이 끝났다. 이제 테스트를 추가하면서 필요한 핸들러들을 추가하면 된다!!!

 

 

public class EventHandler {
    private Map<String, Method> handlerMap;
    private Selector selector; 

    public void setSelector(Selector selector) {
        this.selector = selector;
    }

    public EventHandler() {
        handlerMap = getHandlerMap();
    }

    private Map<String, Method> getHandlerMap() {
        Method[] methods = this.getClass().getDeclaredMethods();
        for (Method m : methods) { m.setAccessible(true); }

        return Arrays.stream(methods)
                .filter(method -> method.isAnnotationPresent(Event.class))
                .collect(Collectors.toMap(
                        method -> method.getName().toLowerCase(),
                        method -> method));
    }
    /*
    map 을 이용해서 key 에 맞는 핸들러 매핑. key 에는 eventName:String 값이 등록되어있다.
     */
    public void delegate(SelectionKey key) {
        //  이 부분은 JSON 으로 바꿔야한다. write 의 경우 eventName 이외에 message 도 보내야한다.
        String attachedEventName = (String) key.attachment();
        String lowerCaseEventName = attachedEventName.toLowerCase();

        Method method = handlerMap.keySet().stream()
                .filter(eventNameKey -> eventNameKey.equals(lowerCaseEventName))
                .map(eventNameKey -> handlerMap.get(eventNameKey))
                .findFirst().orElseThrow(() -> new RuntimeException("조건에 맞는 핸들러를 찾을 수 없습니다."));

        invoke(method, key);
    }

    private void invoke(Method method, SelectionKey key){
        try {
            method.invoke(this, key);
        } catch (Exception e) { // <- 수정 필요함. 편의를 위해 최상위 예외로 캐치
            e.printStackTrace();
            throw new RuntimeException("핸들러 invoke 오류");
        }
    }

    @Event(eventName = "connect")
    private void connect(SelectionKey key) {
        SocketAddress serverAddress = new InetSocketAddress("localhost", 9000);
        boolean isConnected = NioOperations.connect(key,serverAddress); //채널 간의 연결 구현

        // 부수 작업들
    }


}

 

 

Comments