태그 : resin

자바 서블릿 컨테이너의 Comet 지원 3 - Resin

이전글

Resin 은 버전 3.1에서 Comet 모델을 지원한다.  Tomcat 과 마찬가지로 javax.servlet.Servlet 을 확장한 인터페이스를 제공하는 방식이다.  com.caucho.servlet.comet.CometServlet 이 그것인데 이 인터페이스에는 다음과 같은 메서드들이 있다.

public interface CometServlet extends Servlet {
  boolean service(ServletRequest request, ServletResponse response,
                            CometController controller) throws ServletException, IOException;
  boolean resume(ServletRequest request, ServletResponse response,
                             CometController controller) throws ServletException, IOException;
}


Tomcat 과 마찬가지 방식으로 이 인터페이스를 구현한 서블릿은 요청을 처리할 때 기존 서블릿의 service 메서드를 호출하지 않고 이 인터페이스의 service 메서드를 호출한다.  service 메서드의 호출 결과가 true 가 되면 요청 처리는 suspend 되고 스레드는 풀로 되돌아간다.  CometController 의 wake 메서드를 호출하면 요청 처리는 재개되어 resume 메서드가 실행된다.  resume 메서드가 true 를 반환하면 또 다시 suspend 되어 wake 를 기다리게 되고 false 를 반환하면 요청 처리가 끝나게 된다.

service, resume 메서드에 인자로 들어오는 CometController 객체는 service, resume 그리고 다른 이벤트 대기 스레드 사이에서 공유하여 신호를 보낼 수 있고(wake 메서드) 서로간 데이타 교환을 할 수도 있다(setAttribute, getAttribute).

Jetty 나 Tomcat 과는 어떻게 다른지 같은 채팅 예제로 실제 사용법을 알아보겠다. ChatServlet 과 chat.jsp 는 Jetty 의 경우와 같고 BroadcasterServlet 은 다음과 같다.

BroadcasterServlet.java
...
@Override
public boolean service(ServletRequest request, ServletResponse response,
                            CometController controller) throws ServletException, IOException {
    HttpServletResponse res = (HttpServletResponse) response;
    res.setContentType("text/html; charset=utf-8");
    messageSender.addSession(controller);
    return true;
}

@Override
public boolean resume(ServletRequest request, ServletResponse response,
                             CometController controller) throws ServletException, IOException {
    messageSender.removeSession(controller);
    String message = (String) controller.getAttribute("message");
    HttpServletResponse res = (HttpServletResponse) response;
    PrintWriter out = res.getWriter();
    out.println(message);
    res.flushBuffer();
    return false;
}
...


service 메서드에서 최초 요청 처리를 처리하면서 인자로 넘어온 CometController 객체를 messageSender 객체에 저장하여 이벤트 처리 스레드로 넘긴다.  이후 CometController 의 wake 메서드가 호출되면 resume 이 실행되고 여기서 실제 데이타를 전송한다.  전송할 데이타는 이벤트 처리 스레드에서 CometController.setAttribute 으로 넘기고 여기서는 getAttribute 로 받는다.

다음은 MessageSender 클래스이다.

MessageSender.java
public class MessageSender implements Runnable {
  private final BlockingQueue<String> messages =
                         new LinkedBlockingQueue<String>();
  private final Set<CometController> sessions =
                         new CopyOnWriteArraySet<CometController>();

  private volatile boolean running = true;

  public void stop() {
    this.running = false;
  }

  public void sendMessage(String message) {
    try {
      messages.put(message);
    } catch (InterruptedException ignore) {
      // ignore
    }
  }

  public void addSession(CometController controller) {
    sessions.add(controller);
  }

  public void removeSession(CometController controller) {
    sessions.remove(controller);
  }

  @Override
  public void run() {
    while (running) {
      String message = null;
      try {
        message = messages.take();
      } catch (InterruptedException ignore) {
        // ignore
      }
      for (CometController controller : controllers) {
        controller.setAttribute("message", message);
        controller.wake();
      }
    }
  }
}


MessageSender 는 Jetty 의 경우와 비슷하다.  CometController 들을 sessions 에 저장해 두고 채팅 메시지가 들어오면 이를 CometController 에 저장(setAttribute) 한 후 wake 를 호출해서 요청 처리가 resume 되게 한다.

Resin 의 Comet 지원은 Jetty 와 비교하면 직관적으로 이해하기 쉽다.  또한 Tomcat 처럼 번거롭지도 않다.  세 서블릿 컨테이너의 Comet 지원 중에서 가장 사용하기가 쉬운 것 같다.

by Corund | 2008/08/01 09:35 | 트랙백 | 덧글(0)

◀ 이전 페이지다음 페이지 ▶