2011년 2월 18일 금요일

CXF의 Custom Invoker 개발

CXF에서 요청을 받아서 서비스를 실행하고 응답을 리턴하는 프로세스를 살펴 보면 필요에 따라 각각을 커스터마이즈 할 수 있다.
요청 프로세스는 inbound chain 이라 하여 아래의 단계를 거친다.
RECEIVE
(PRE/USER/POST)_STREAM
READ
(PRE/USER/POST)_PROTOCOL
UNMARSHAL
(PRE/USER/POST)_LOGICAL
PRE_INVOKE
INVOKE
POST_INVOKE

응답 프로세스는 outbound chain 이라 하여 아래의 단계를 거친다.
SETUP
(PRE/USER/POST)_LOGICAL
PREPARE_SEND
PRE_STREAM
PRE_PROTOCOL
WRITE
MARSHAL
(USER/POST)_PROTOCOL
(USER/POST)_STREAM
SEND

각 단계의 구현을 InInterceptor나 OutInterceptor를 이용하여 구현할 수 있다.

하지만 이번 포스트에서는 Invoker에 대해서만 설명하도록 한다.

Invoker란 inbound chain의 INVOKE 단계에서 호출되는 것으로 실제 서비스를 호출하는 기능을 담당한다. CXF는 기본적인 Invoker를 제공하지만 서비스 호출 전,후에 특별한 처리를 해야 한다면 별도의 Invoker를 개발하여 사용할 수 있다.

Invoker 설정
cxf 설정 파일에서 아래와 같이 지정한다.

  <jaxrs:server id="restfulServer" address="/rest">
    <jaxrs:features>
      <cxf:logging/>
    </jaxrs:features>
    <jaxrs:invoker>
      <ref bean="baseInvoker"/>
    </jaxrs:invoker>
    
    <jaxrs:serviceBeans>
      <ref bean="userRestfulService"/>
    </jaxrs:serviceBeans>
  </jaxrs:server>

Customized Invoker 개발
아래의 소스는 JAXRS에서 기본적으로 사용하는 JAXRSInvoker를 상속받아서 구현한 것으로 에러 처리 기능이 추가된 Invoker라 할 수 있다.

JAX-RS 서비스에서 정상처리된 경우에는 서비스가 리턴한 객체를 리턴하지만 서비스 처리도중 에러가 발생하는 경우에는 에러 코드와 에러 메시지를 엔티티로 포함하고 있는 Response 객체를 리턴한다.

package com.archnal.sample.cxf;

import java.util.Locale;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Response;

import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.jaxrs.JAXRSInvoker;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.MessageContentsList;
import org.springframework.stereotype.Service;

import com.archnal.sample.exception.BaseException;
import com.archnal.sample.exception.StatusCode;
import com.archnal.sample.exception.StatusMessageBuilder;

@Service("baseInvoker")
public class BaseInvoker extends JAXRSInvoker {
  @Resource(name="statusMessageBuilder")
  private StatusMessageBuilder statusMessageBuilder;
  
  @Override
  public Object invoke(Exchange exchange, Object request) {
    Response response = null;

    HttpServletRequest servletRequest = 
      (HttpServletRequest)exchange.getInMessage().get("HTTP.REQUEST");

    Locale clientLocale = null;
    if(servletRequest != null) {
      clientLocale = servletRequest.getLocale();
    }
    try {
      Object object = super.invoke(exchange, request);
      return object;
    } catch(Fault fault) {
      Throwable cause = fault.getCause();
      if(cause.getClass().isAssignableFrom(BaseException.class)) {
        response = Response.serverError().entity(create((BaseException) cause, clientLocale)).build();
        
      } else {
        response = Response.serverError().entity(create(cause, clientLocale)).build();
      }
    }
    
    return new MessageContentsList(response);
  }

  private ResponseResult create(BaseException ex, Locale locale) {
    ResponseResult header = new ResponseResult();
    header.setSuccess(false);
    header.setStatusCode(ex.getStatusCode().getCode());
    header.setMessage(statusMessageBuilder.getErrorMessage(ex, locale));
    
    return header;
  }
  
  private ResponseResult create(Throwable th, Locale locale) {
    
    ResponseResult header = new ResponseResult();
    header.setSuccess(false);
    header.setStatusCode(StatusCode.UNKNOWN.getCode());
    header.setMessage(statusMessageBuilder.getErrorMessage(StatusCode.UNKNOWN, locale));
    
    return header;
    
  }
}

댓글 없음:

댓글 쓰기