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); //채널 간의 연결 구현
// 부수 작업들
}
}