'2008/07/06'에 해당되는 글 1건
ActionAnnotations : Webwork Interceptor와 Annotation의 간단한 활용

Webwork의 Interceptor은 Webwork에서 중요한 위치를 차지 하고 있습니다. Webwork의 많은 기능이 Interceptor로 제공되어 있고, Webwork의 기능 확장은 거의 Interceptor로 이루어져 있습니다.
가령 Webwork에서 TypeConversion이 실패 했을 경우, 자동으로 Action.INPUT으로 forward됩니다. 어떤 페이지의 입력(request)가 실패하면 다시 사용자 입력을 받기 위해 입력 화면을 그려주듯이 말이죠. 처음에 이부분때문에 무척 당황했는데요.. 이 부분 역시 Interceptor으로 제공되어 있습니다. 즉 converionError이라는 Interceptor을 제거하면 위와 같은 행동을 하지 않게 됩니다. (기본적인 webwork의 interceptor stack에 포함되어 있습니다.)
프로젝트를 하면서 여러 액션에서 공통적으로-자주- 구성되는 루틴이 존재하게 됩니다. 가장 대표적인 예로는 사용자 인증과 권한에 대한 부분인데요. 대개의 경우 구현상속을 이용하여, 코드를 압축하거나, 위임을 하여 사용하기 편하게 제공하게 됩니다. (물론 서비스로 만들어서 사용 될수도 있지만, 여러 서비스를 사용한 액션처럼 구성하게 되겠지요.)
이번에 회사 동료와 버스를 타면서 논의 하다가 나온 아이디어는 (이것 말고 Interface 을 이용한 방법도 이야기 되었습니다.) Annotation을 가지고 Interceptor가 그러한 기능을 지원하는 건 어떠한가? 이었습니다.
간단한 예를 들자면,
- @MusyBeLogin(loginUrl="/auth/login.action")
- class BlogPostListAction extends ActionSupport {
- @LoginMember
-
private Member loginMember
@Permission
private Permission permission
...
이런식으로 구성하게 됩니다.
Annotation으로 BlogPostListAction에서의 필요한 여러 객체를 제공하거나(LoginMember,Permission),Action에 annotation된 조건이 아니라면 흐름을 제어하는 기능들을 할수 있습니다.
이런식의 구성이 좋은지는 아직 모르겠지만. (http://forum.ksug.org/viewtopic.php?f=5&t=76#p175) Action에 존재할수 있는 코드를 압축한다는 개념을 좀 간단하게 구현했다고 볼수 있습니다.
우선 간단하게 책임을 나누어서,
- public abstract class ActionAnnotationInterceptor extend AroundInterceptor {
- protected abstract ActionAnnotationHandling getHandling();
- @Override
- protected void before(ActionInvocation invocation)
- Object action = invocation.getAction();
- HttpServletRequest request = getHttpServletRequest(innovation);
- getHandlling().handling(action,request);
- }
- ...
ActionAnnotationInterceptor이라는 간단한 Interceptor을 만듭니다. 이 추상 클래스을 구현 상속한 객체에서 getHandling()을 구현합니다.
ActionAnnotationHandling은 말 그대로 ActionAnnotation을 핸들링하는 인터페이스입니다.
- public interface ActionAnnotationHandling {
- public void handling(Object action,HttpServletRequest request) throws Exception
- }
여러 Annotation을 각각 핸들링하는 객체를 포함하고는 ActionAnnotationHandlers 을 만들었습니다.
- public class ActionAnnotationHandlers implements ActionAnnotationHandling {
- public void handling(Object action,HttpServletRequest request) {
- for(ActionAnnotationHandling handling : handlers) {
- handler.handling(action,request);
- }
- }
- ....
- }
그리고 각각 ActionAnnotationHandler들의 공통적인 기능을 AbstractActionAnnotationHandler에 넣었습니다.
- public abstract class AbstractActionAnnotationHandler implements ActionAnnotationHandling {
- public boolean hasTypeAtAnnotation(Calss<? extends Object>klass,Class<? extends Annotation> annotationClass){
- if(kclass.isAnnotationPresent(annotationClass) { return true ;} return false;
- }
- ...
- public abstract void handling(Object action,HttpServletRequest request) throws Exception;
- ....
- }
그리고 각각 특정 AnnotationHandler을 작성했습니다. 여러 객체로 나누어서 작업하는게 불편해서 하나의 객체를 만들었는데요, action의 Type이나 fileld에 해당하는 annotation 이 존재하면 reflection api으로 필요한 객체를 넣어준다거나, 세션의 인증키가 맞지 않다면 예외상황을 발생하여 ExceptionHandler로 하여금 에러 페이지로 가도록 했습니다.
쓰다보니까 벌거 아니긴 해서 :-} 팀내에 아이디어 프로토타입으로 만들어 봤는데요.. 이미 프로젝트가 진행된지 절반은 되어서 (하지만 새로 사이트를 개발 들어가는 시점이긴 해서) 시간도 없고 이부분에 대한 비용이 많이 지출될거 같아서 이정도까지 해보았습니다.
지금 생각해보니, Handler으로 분리한게 좋은건지. 라는 생각도 드는 군요. Interceptor의 제어 흐름에서 멀어서져 특정 Annotation이흐름을 제어할때 쉽지 않을 듯 하고 , webwork은 ActionContext을 가지고 거의 모든 정보를 참조할수 있기 때문에 ActionAnnotationHandling.handling()에 HttpServletRequest을 넣어줄 필요는 없지 않을까 싶긴 하네요..
언제 다시 Webwork을 다시 사용하게 되면 그때 가서 다시 한번 끄집어 낼지도 모르겠습니다. :-)
이 글은 스프링노트에서 작성되었습니다.


이올린에 북마크하기
Prev
Rss Feed