IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
한국 developerWorks   >   Open developerWorks  > developerworks

이클립스 SWT 애플리케이션과 웹 페이지 간 세션 동기화 기법



박용우박용우 yongwoopark@paran.com

건국대학교 전자계산학과와 동대학원 박사과정을 졸업하고 펜타시스템테크놀러지, XCE 등에서 XML 및 모바일 분야 개발에 전념해 왔다. 2005년 11월부터 신한은행의 통합운영관리 프로젝트에서는 이클립스 SWT를 이용하여 거래 추적 시스템의 일부인 실시간 모니터링 클라이언트를 개발했다. 2007년 4월부터는 현대해상의 차세대 프로젝트에서도 이클립스 SWT를 이용하여 시스템 모니터링을 위한 다양한 리치 클라이언트 애플리케이션을 개발할 계획이다. 내용 중 궁금한 사항은 필자의 이메일로 문의하기 바란다.


난이도 : 중급
2007년 4월24일


[오픈 디벨로퍼웍스]는 여러분이 직접 필자로 참가하는 코너입니다. 이 글에서는 이클립스 SWT 웹 파일 다운로드 애플리케이션 개발에 대해 알아봅니다.

이클립스 SWT는 이클립스 RCP(Rich Client Platform)를 구성하는 여러 컴포넌트 중에서 리치 클라이언트 애플리케이션을 개발하기 위한 가장 핵심이 되는 병기다. 이클립스 RCP를 기반으로 SWT와 JFace를 이용하여 개발할 수 있는 애플리케이션은 프로덕트(Product)와 플러그인(Plug-in) 등 두 가지 형태다. 그러나 이클립스 SWT만을 이용해서도 리치 클라이언트 애플리케이션을 개발할 수 있다.
이렇게 개발된 애플리케이션은 이클립스 RCP 기반의 프로덕트나 플러그인과는 달리 훨씬 가볍다. 수십에서 크게는 100메가바이트 이상이 되는 이클립스 RCP의 모든 기능이 필요하지 않고, 단지 2메가바이트를 넘지 않는 swt.jar 파일과 대상 운영체제를 위한 네이티브 라이브러리만 있으면 되기 때문이다. 이러한 이유로 이클립스 SWT를 이용하여 개발한 리치 클라이언트 애플리케이션은 자바 웹스타트 기술을 이용하여 웹에서 배포하고 실행할 수 있는 최적의 솔루션이다. 요즈음 윈도우 비스타가 출시되면서 기존에 액티브X를 이용하여 개발한 여러 컴포넌트들이 제대로 동작하지 않을 수 있다는 매우 심각한 문제가 있는데, 이러한 이슈를 한방에 날려버릴 수 있는 매우 강력하고 효율적인 솔루션이라 생각된다.
이렇게 웹스타트 기술을 이용함으로써 이클립스 SWT를 이용하여 개발한 리치 클라이언트 애플리케이션을 웹과 연동할 수 있는데, 이 때 웹 페이지와 실행된 이클립스 SWT 리치 클라이언트 애플리케이션 간에 세션을 동기화해 주는 것이 반드시 필요하다. 따라서 이 글에서는 이클립스 SWT 애플리케이션을 웹에서 실행할 때 어떻게 기존 웹 페이지와 세션을 동기화할 수 있는지에 대해 살펴보자.


웹스타트를 이용하여 배포하기

예를 들어, 파일을 다운로드할 수 있는 애플리케이션을 이클립스 SWT를 이용하여 개발하고, 웹스타트 기술을 이용하여 웹에서 배포했다고 하자. 이클립스 SWT 파일 다운로드 애플리케이션을 웹스타트 기술을 이용하여 웹에서 실행하면 다음의 흐름도와 같이 실행된다.



웹스타트 흐름도
그림 1. 웹스타트 흐름도


웹 브라우저가 보여주고 있는 웹 페이지 내에서 JNLP 페이지에 대한 링크를 클릭하면, ① 웹 브라우저는 서버에 JNLP 페이지를 요청하여 가져오고, ② JNLP 페이지의 마임(mime) 타입이 ‘application/x-java-jnlp-file’이므로, 웹 브라우저는 웹스타트 클라이언트에 응답을 전달하며, ③ 자바 웹스타트 클라이언트는 전달받은 JNLP 페이지를 해석하여 애플리케이션 실행에 필요한 정보를 사용자에게 보여주고, 애플리케이션에서 요구한 자바 런타임을 체크한 후, ④ 이미지, 애플리케이션 파일들을 서버에 요청하여 다운로드 한 후 실행한다. 이 때, JNLP 페이지 내에 애플리케이션을 실행할 때 전달할 매개변수를 설정하고 있으면 프로그램을 실행하면서 명령행 매개변수로 전달한다. 웹스타트에 대한 더 자세한 사항에 대해 살펴보려면 다음 사이트를 참고하기 바란다. http://java.sun.com/products/javawebstart/

이렇게 웹에서 실행된 파일 다운로드 애플리케이션에서는 사용자 인증, 세션에 저장된 여러 데이터 사용 등을 위해 반드시 기존 웹 페이지와 세션을 동기화해야 한다. 이를 위해, 필자가 제안하는 방법은 기존 웹 페이지에서 세션 아이디와 세션 객체를 저장하고, 세션 아이디를 파일 다운로드 애플리케이션을 실행하면서 명령행 매개변수로 전달하는 것이다. 파일 다운로드 애플리케이션에서는 명령행 매개변수로 전달받은 세션 아이디를 서버에 전달하여 해당 세션 객체를 가져와 세션 객체 내의 모든 데이터를 자신의 세션에 복사하면 된다.
지금부터 웹스타트를 이용하여 프로그램을 실행할 때 명령행 매개변수를 전달하는 방법과 세션 아이디로 세션 객체를 가져와 데이터를 모두 복사하는 방법에 대해 살펴보자.



위로


JNLP 페이지에서 명령행 매개변수 설정하기

자바 프로그램을 웹스타트 방식으로 배포하려면 JNLP 파일이 필요하다. 파일 다운로드 애플리케이션을 웹스타트 방식으로 배포하기 위해 만든 JNLP 파일이 ‘fd-ywpark.jnlp’라고 하자. JNLP 페이지에서는 웹스타트를 이용하여 자바 애플리케이션을 실행할 때 명령행 매개변수를 설정할 수 있다. 이는 JNLP 페이지를 만들 때 다음과 같이 실행하려는 애플리케이션을 설정하는 노드(application-desc)가 있는데, 하위 노드(argument)에 명령행 매개변수들을 나열해 주면 된다.

Listing 1. 웹스타트 방식으로 실행할 애플리케이션에 대한 명령행 매개변수 설정(${fd}/fd/jnlp/fd/fd-ywpark.jnlp)
  

<application-desc main-class="org.rndclub.fd.main.FileDownload">
  <argument>id=ywpark</argument>
  <argument>sessionId=00D144AEB77892EAF8151889755FD379</argument>
  <argument>serverUrl=http://127.0.0.1:8080/fd</argument>
  <argument>downUrl=/jsp/DownloadList.jsp?id=ywpark</argument>
  <argument>labelUrl=/jsp/LabelList.jsp?id=ywpark</argument>
  <argument>loginUrl=/jsp</argument>
</application-desc>


위와 같이 세션 아이디와 같은 정보를 JNLP 페이지에서 명령행 매개변수로 동적으로 설정해야 하는데, 이를 위해서는 JNLP 페이지를 동적으로 생성해 주어야 한다.



위로



JNLP 페이지 동적으로 생성하기

파일 다운로드 애플리케이션을 웹스타트 방식으로 실행하기 위해서는 반드시 JNLP 파일이 있어야 한다. 지금까지 애플리케이션을 실행하기 위해 필요한 자원 파일들, 명령행 매개변수 등에 대해 설정하는 방법에 대해서도 함께 살펴보았다.
그런데 파일 다운로드 애플리케이션을 웹스타트 방식으로 실행할 때 설정한 명령행 매개변수들은 JNLP 파일을 요청할 때마다 동적으로 생성해야 하는 것들이다. 사용자 아이디, 세션 아이디, 서버 정보, 다운로드 파일 정보 URL, 레이블 정보 URL 등 현재 웹에서 파일 다운로드 애플리케이션을 실행하고자 요청한 사용자가 누군가에 따라 그 때 그 때 동적으로 생성해야 하는 정보인 것이다.
그러나 JNLP 페이지는 HTML 페이지처럼 정적으로 만들게 되는데, 이러한 동적인 정보를 설정하는 것이 가능할까? 이러한 문제에 대한 다양한 해결 방법을 고민해 보았지만 웹스타트 기술 홈페이지에서는 기발한 해결책을 찾을 수 없었다. 그래서 필자가 나름대로 고민하면서 테스트를 해 보고 찾아낸 방법이 JNLP 페이지를 동적으로 생성하는 것이었다. 다음과 같다.

  1. JSP 페이지에서 JNLP 페이지에 대한 요청을 받는다.
  2. 동적인 데이터들을 문자열 객체로 생성한다.
  3. JNLP 페이지에 해당하는 문자열을 만들고, 필요한 부분에 동적 데이터를 추가한다.
  4. 이렇게 만든 JNLP 페이지에 해당하는 문자열을 파일에 저장한다. 사용자마다 다른 파일을 만들기 위해 JNLP 파일의 이름에 사용자 아이디를 추가한다. 예를 들어, ‘fd-ywpark.jnlp’와 같다.
  5. 파일로 저장된 JNLP 페이지로 리다이렉트한다.

위와 같은 방법을 고안해 테스트해 보았더니 아주 성공적으로 수행됐다. 또한, 서버에서 리다이렉트하는 것을 웹 브라우저는 알지 못하고, JSP 페이지에 대한 요청을 했어도 리턴되는 응답 페이지의 마임 타입이 JNLP(application/x-java-jnlp-file)이기 때문에 웹 브라우저는 웹스타트 클라이언트에게 처리하도록 하게 된다. 이를 위해 ‘fd.jsp’ 페이지를 만들어 주었는데, 먼저 JSP 페이지에서 다음과 같이 JNLP 페이지를 위한 문자열을 생성한다.

Listing 2. 동적으로 JNLP 페이지 생성 - JNLP 페이지를 위한 문자열 객체 생성(${fd}/fd/jnlp/fd.jsp)
  

<%@ page contentType="text/html; charset=euc-kr" %>
<%@ page import="java.io.*"%>
<%
  ...
	// (1) 새롭게 생성할 JNLP 페이지 데이터를 위한 문자열 생성
  String jnlpStr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
                 …
       +"<application-desc main-class=\"org.rndclub.fd.main.FileDownload\">\n"
                +"	    <argument>id="+id+"</argument>\n"
                +"	    <argument>sessionId="+sessionId+"</argument>\n"
                  ...
                +"	    <argument>loginUrl="+loginUrl+"</argument>\n"
                +"    </application-desc>\n"
                +"</jnlp>\n";
  ...
%>


다음으로, 이렇게 생성한 문자열을 다음과 같이 서버의 특정 위치에 파일로 저장하고 해당 파일로 리다이렉트하도록 해 주면 된다.

Listing 3. 동적으로 JNLP 페이지 생성 - 동적으로 생성한 JNLP 파일로 리다이렉트(${fd}/fd/jnlp/fd.jsp)
  

<%@ page contentType="text/html; charset=euc-kr" %>
<%@ page import="java.io.*"%>
<%
  ...
  try {
    // (2) 동적으로 생성한 JNLP 페이지 데이터를 파일에 저장
    String jnlpRealPath = realPath + "jnlp" 
                        + File.separator + "fd" 
                        + File.separator + jnlpName;   // 저장할 파일 이름 생성
    File jnlpFile = new File(jnlpRealPath);
    FileWriter writer = new FileWriter(jnlpFile);
    PrintWriter fout = new PrintWriter(writer);
    fout.println(jnlpStr);   // 파일에 저장
    fout.close();   // 파일 닫기
    
    // (3) 새롭게 생성되어 저장된 JNLP 파일로 리다이렉트
    String redirectUrl = contextPath+"/jnlp/fd/"+jnlpName;   // 생성한 파일의 URL
    response.sendRedirect(redirectUrl);   // 리다이렉트
  } catch(Exception e) {
    e.printStackTrace();
  }
%>


이렇게 동적으로 JNLP 파일을 생성함으로써, 사용자가 실행하고 있는 웹과 웹스타트로 실행된 자바 애플리케이션 간에 필요한 모든 데이터를 공유할 수 있다. 특히, 세션 아이디를 공유하는 것은 무엇보다도 심각한 문제를 해결할 수 있는 열쇠가 됐다. 다시 말해 웹에 생성된 세션 아이디를 자바 애플리케이션에 전달함으로써 웹 브라우저와 웹스타트 방식으로 실행된 자바 애플리케이션은 웹의 세션을 공유하는 것이 가능해졌다. 웹 브라우저와 자바 애플리케이션 간에 세션을 공유한다는 것은 무엇보다도 사용자 인증(SSO) 문제를 해결할 수 있다는 것이기 때문에 아주 중요하다고 할 수 있을 것이다. 사용자 인증 여부는 세션에 정보를 저장해 놓기 때문이다.



위로



웹 애플리케이션과 세션 동기화

웹 브라우저를 두 개 띄워도 세션을 공유하는 것이 불가능한 것이 당연한데, 어떻게 웹 브라우저와 웹스타트 방식으로 실행한 자바 프로그램 간에 감히 세션을 공유한단 말인가? 필자는 또 한 번 고민하게 됐고, 몇 가지 테스트 끝에 이를 해결할 수 있는 가장 단순하면서도 강력한 방안을 찾았다.
바로, 동적으로 JNLP 페이지를 생성하는 JSP 페이지에서 사용하는 세션 객체를 저장해 놓고, 자바 웹 스타트 방식으로 실행되는 자바 애플리케이션에 명령행 매개변수의 하나로서 세션 아이디를 전달하는 것이다. 그리고 웹스타트 방식으로 실행된 자바 프로그램에서는 HttpClient 객체를 이용하여 서버에 커넥션을 생성하면서 세션 아이디를 전달함으로써 로그인 페이지에서 세션 아이디에 해당하는 세션 객체를 찾아, 웹스타트로 실행된 자바 프로그램과 맺은 세션에 모든 데이터를 복사하는 것이다.
그렇다면, 세션 객체를 어디에 저장해 놓고 세션 아이디를 이용하여 공유할 수 있을까? JSP 에서는 페이지(page), 요청(request), 세션(session), 애플리케이션(application) 단위의 저장 공간을 제공하고 있다. 웹 브라우저와 웹스타트 방식으로 실행된 자바 애플리케이션 간에는 동일한 웹 애플리케이션을 사용하므로, 애플리케이션 단위의 저장 공간에 세션 객체를 저장하면 된다. 따라서 JNLP 페이지를 동적으로 생성하는 ‘fd.jsp’ 페이지에서는 다음과 같이 세션 아이디를 이용하여 세션 객체를 애플리케이션 객체에 저장하면 된다. 세션 객체에 저장하는 데이터들은 테스트용이므로 독자들은 필요에 맞게 사용하기 바란다.

Listing 4. 동적으로 JNLP 페이지 생성 - 공유할 세션 객체를 애플리케이션 객체에 저장(${fd}/fd/jnlp/fd.jsp)
  

<%@ page contentType="text/html; charset=euc-kr" %>
<%@ page import="java.io.*"%>
<%
  // (1) 세션 객체에 데이터 저장 (테스트용)
  session.setAttribute("id", id);
  session.setAttribute("sessionId", sessionId);
  …
  // (2) 애플리케이션 객체에 세션 아이디를 이용하여 세션 객체 저장
  application.setAttribute(sessionId, session);
%>


이렇게 웹 브라우저에서 생성한 세션 객체를 웹 애플리케이션의 애플리케이션 객체에 저장했다. 다음으로 웹스타트 방식으로 실행된 파일 다운로드 애플리케이션에서는 JNLP 페이지에서는 세션 아이디 값을 명령행 매개변수로 전달받았으므로, 이 값을 이용하여 프로그램 시작시에 서버와 커넥션을 맺을 때 다음과 같이 로그인을 하게 된다.

Listing 5. FileDownload 클래스에서 서버와 커넥션 생성 및 로그인하기(${FileDownload}/org/rndclub/fd/main/FileDownload.java)
  

public static void connectSession() {
  client = new HttpClient();   // (1) HttpClient 객체를 생성
  HttpMethod method = null;
  try {
    // (1) 서버에 로그인 URL 및 매개변수 설정
    String url = (String) FileDownload.params.getParameter("serverUrl")
               + FileDownload.params.getParameter("loginUrl")
               + "?" + FileDownload.params.getParameter("sessionId");
    // (2) HTTP GET 방식으로 로그인 페이지 요청
    method = new GetMethod(url);
    int statusCode = client.executeMethod(method);
    String result = method.getResponseBodyAsString();
  } catch (Exception e) {
    e.printStackTrace();
    LoggerModel.log(e);
  } finally {
    if (method != null) {
      method.releaseConnection();   // (3) 반드시 GetMethod 객체의 연결을 해제
    }
  }
}


위와 같이 세션 아이디 값을 매개변수로 하여 서버의 로그인 페이지에 접속하면, 로그인 페이지에서는 다음과 같이 애플리케이션 객체에서 주어진 세션 아이디에 해당하는 세션 객체를 찾아와 세션 객체 내에 저장된 모든 데이터를 파일 다운로드 애플리케이션을 위한 세션 객체 내에 복사해 주면 된다.

Listing 6. 로그인 페이지에서 세션 데이터 동기화(${fd}/fd/jnlp/fd.jsp)
  

<%@ page contentType="text/xml; charset=euc-kr" %>
<%@ page import="java.util.Enumeration"%>
<%
  String sid = request.getParameter("sid");  // (1) 세션 아이디 매개변수를 얻어옴
  if((sid!=null)&&(!"".equals(sid))) {
    // (2) 애플리케이션 객체에서 세션 아이디에 해당하는 세션 객체를 가져옴
    HttpSession hs = (HttpSession) application.getAttribute(sid);
    if(hs != null) {
      application.removeAttribute(sid);   // (3) 애플리케이션 객체에서 세션 객체를 제거
      // (4) 세션 객체에 저장된 모든 데이터를, 파일 다운로드를 위한 세션 객체에 복사
      Enumeration e = hs.getAttributeNames() ;
      while(e.hasMoreElements()) {
        String name = (String)e.nextElement();
        Object value = hs.getAttribute(name);
        session.setAttribute(name, value);
      }
    }
  }
%>





위로


   소셜 북마크

   mar.gar.in mar.gar.in
    digg Digg
    del.icio.us del.icio.us
    Slashdot Slashdot

이렇게 생성한 파일 다운로드 애플리케이션에서 초기에 생성한 HttpClient 객체를 애플리케이션 내에서의 모든 웹 연결을 위해 공유하여 사용하게 된다. 지금까지 설명한 내용에 대해서는 함께 제공되는 다음 프로젝트 파일을 참고하기 바란다. 

  • fd.zip: 파일 다운로드 애플리케이션을 위한 웹 애플리케이션





위로


참고 자료





이제 전문가의 글을 단순히 ‘보는 것’에서, 직접 여러분이 developerWorks의 필자가 될 수 있습니다. IBM developerWorks를 통해 공유하고 싶은 지식이 있으신 분들은 원고 기획안을 접수해주세요. 채택되신 분께는 소정의 원고료를 드립니다.
Open developerWorks 신청하기   MS워드 아이콘   아래아한글 아이콘



[지난 Open dW 보기]
[이 기사에 대한 의견 쓰기 - 웹 개발 포럼]
[이 기사에 대한 의견 쓰기 - 자바 포럼]
사이트 여행

dW 커뮤니티
포럼 | 블로그 | Spaces
dW Student Community

로컬 컨텐츠

행사 및 세미나

기획 기사

개발자 입문

튜토리얼 및 교육

TOP 10 인기자료

SW 다운로드

RSS 피드

뉴스레터
  
자바스크립트가 작동이 중지되었습니다. 이 기능을 수행하시려면 브라우저에서 자바스크립스트를 작동시켜 주시거나 이곳을 클릭해주세요.
Special offers
Screencast
IBM SOA Sandbox 시험판
dW Student Community
로보코드
코드 트레이닝


    IBM 소개 개인정보 보호정책 문의