운영체제 : 윈도우 2000/XP, 유닉스 계열, 리눅스나 Mac OS X도 가능 개발도구 : 이클립스 3.1 기초지식 : 자바, 웹서비스, XML 응용분야 : 자바 플랫폼을 이용한 웹서비스 제공
특히 최근 POJO에 대한 지원이 J2SE 5.0의 어노테이션과 함께 상당히 각광을 받고 있는데, 이는 특정 인터페이스의 구현이나 클래스의 상속 없이도 임의의 클래스(즉 POJO)에 대한 메타데이터를 줄 수 있기 때문에, 컴포넌트를 돌리는 컨테이너가 쉽게 POJO를 통해 원하는 서비스를 제공할 수 있다는 장점에 기인한다. 예를 들어 MDB(Message Driven Bean)와 유사하게 JBoss EJB 3.0 PR4에서 제공하는 MDP(Message Driven POJO)의 경우 JBoss 고유의 어노테이션 타입을 써서 평범한 클래스를 JMS의 메시지 공급자가 소비자로 둔갑시킬 수 있다. 이밖에도 싱글턴 서비스를 가능하게 하는 서비스 POJO와 J2SE 5의 비동기 처리를 응용한 비동기 호출도 눈여겨 볼만하다.
다시 말하지만 이런 기능들은 EJB 3.0 표준은 아니지만, 반응이 좋다면 표준화되어 개발자들을 더욱 편안하게 해줄 것이다.
JAX-RPC 2.0과 JAXB 2.0의 RI 발표가 예상보다 지연되어, 이 원고를 작성하고 있는 시점(3월 3째 주)에도 썬에 문의해본 바에 따르면 몇 주 더 기다려야 한다니, 아마 이 번호가 출간된 즈음에는 접할 수 있을지도 모르겠다. 이러한 출시 일정의 지연에 의해 원래 웹 서비스 부분도 이번에 다루려 했으나 부득이하게 다음 달로 연기하게 되었음을 양해해주기 바란다.
JSF의 유일한 오픈소스 구현체인 아파치 MyFaces가 인큐베이터 기간을 마치고 정식 프로젝트로 출범했다. 보통 자바와 웹에 관련된 아파치 프로젝트는 자카르타에 속하는 것이 일반적인데, 이번 MyFaces의 경우는 매우 독특했다는 것이 필자의 개인적인 느낌이다. JSF는 J2EE 5.0의 필수 항목이기도 해서(JSTL 1.1도 들어간다), 그동안 자바 웹 GUI와 관련된 많은 프레임워크(심지어는 썬의 JSF 리드인 Craig McClanahan이 이끌고 있는 스트럿츠까지)과의 알력이 잠재하고 있다(이 주제에 대해서는 다음 달 씬 클라이언트를 다루면서 심층적으로 논의할 기회를 가져보길 희망한다). J2SE 5.0이 업데이트 2를 내놓았으므로 앞으로의 플랫폼 기준은 다음과 같이 되겠다.
EJB 컴포넌트
먼저 다음과 같은 가정을 하려 한다.
[1] JBoss 서버와 EJB 3.0 모듈은 설치되어 있다.
[2] 택시 예약 서비스의 홈 디렉토리를 TAXI_HOME이라고 부른다(실제 물리적인 위치는 어디라도 상관없다).
[3] 디렉토리 경로 구분자는 /를 쓴다(윈도우 사용자는 를 써야 할 때도 있을 것이다).
[4] 택시 예약 서비스의 EJB 컴포넌트 홈 디렉토리는 TAXI_HOME/ejb로 잡고, TAXI_EJB_HOME이라고 부른다.
[5] TAX_EJB_HOME의 디렉토리 구조는 JBoss EJB 3.0의 예제를 따른다.
미리 JBoss EJB 3.0의 세션 빈이나 엔티티 빈의 예제를 돌려보자. 여러 가지 환경 설정이나 기타 문제로 잘 되지 않으면 택시 예제로 나아갈 수 없으므로, JBoss EJB 3.0의 관련 문서나 포럼을 통해 반드시 해결하자. 필자의 경우에는 설치와 예제 실행이 매우 매끄러워 감명(?)을 받았다. 하지만 알 수 없는 것이 이 세상의 컴퓨터들이므로, 되도록 자신이 가지고 있는 기존의 JBoss 서버보다는 새로 JBoss 서버를 따로 설치하여 EJB 3.0을 올리는 것이 안전하겠다.

그러면, 택시 서비스를 위해 필요한 EJB 컴포넌트가 무엇일지 생각해 보자. 먼저, 다음에 준하는 세션 빈이 필요하다.
soa.service.TaxiBookService [인터페이스]
Taxi[] getAvailableTaxis(Location location, Calendar calendar)
void reserve(int taxiId)
Order[] viewOrders()
void cancelOrder(int orderId)
EJB 3.0에서는 하나의 세션 빈을 만들기 위해 총 2개의 자바 요소가 들어간다.
잘 보면 이전(2.1이하)의 EJB와는 달리 홈 인터페이스가 없다. 그리고 예전의 리모트(또는 로컬) 인터페이스격인 비즈니스 인터페이스나 빈 클래스도 특정 인터페이스나 클래스의 상속 없이 EJB 어노테이션으로 마감된다. 어찌 보면 자바의 RMI 모델과 매우 흡사한데, 그만큼 통쾌해진 면이 있다(이런 구석이 SOA의 사상과 잘 부합하기도 한다). 앞의 TaxiBookService의 실제 코드는 다음과 같이 비즈니스 인터페이스화한다.
package soa.service;
import java.util.Calendar;
import javax.ejb.Remote;
import soa.model.Location;
import soa.model.Order;
import soa.model.Taxi;
@Remote
public interface TaxiBookService {
Taxi[] getAvailableTaxis(Location location, Calendar calendar);
void reserve(int taxiId);
Order[] viewOrders();
void cancelOrder(int orderId);
}
물론 이 인터페이스가 컴파일되려면 Taxi, Location, Order 클래스가 정의되어 있어야 한다. 일단은 soa.model에 클래스 정의만 다음과 같은 식으로 해두자.
package soa.model;
import java.io.Serializable;
public class Location implements Serializable {
private static final long serialVersionUID = 3906368246629414451L;
}
원격 전달을 위해 Serializable을 구현해야 하며, J2SE 5.0에 와서는 serialVerionUID를 정의하기를 강력 권장하고 있어 이클립스에서도 자동 생성해주고 있다. 이런 암호 같은 코드는 윈도우 프로그래밍에서 본 기억(그쪽은 훨씬 긴데다가 영문자도 끼어 있었다)이 있긴 하다. 다음은 택시 예약 서비스의 빈 클래스이다.
package soa.service;
import java.util.Calendar;
import soa.model.Location;
import soa.model.Order;
import soa.model.Taxi;
import javax.ejb.Stateless;
@Stateless
public class TaxiBookServiceBean implements TaxiBookService {
public Taxi[] getAvailableTaxis(Location location, Calendar calendar) {
// TODO Auto-generated method stub
return null;
}
public void reserve(int taxiId) {
// TODO Auto-generated method stub
}
public Order[] viewOrders() {
// TODO Auto-generated method stub
return null;
}
public void cancelOrder(int orderId) {
// TODO Auto-generated method stub
}
}
이클립스의 자동완성 기능을 사용하면 이와 같이 알맹이 없이 할 일만 쭉 나온다. 딱 이 상태가 보통 영어로 더미(dummy)라고 하는 껍데기만 있는 상태이다. 이 정도만 해도 택시 예약 서비스 세션 빈의 빌드와 배치(deploy)는 된다. ‘이달의 디스켓’에 들어 있는 소스는 JBoss EJB 3.0의 세션 빈 예제에서 유도한 택시 EJB 컴포넌트 프로젝트용 build.xml이다.
기본적으로 JBOSS_HOME과 TESTNG_HOME이 환경변수로 잡혀 있어야 하는데, TESTNG_HOME은 TestNG라는 테스트 프레임워크의 홈 디렉토리이다. 이 새로운 테스트 프레임워크는 좀 생소할 수도 있는데, Cedric Beust라는 구글 소속(전에는 BEA에서 EJB 관련 일을 했었다) 개발자가 창안해낸 어노테이션 활용 테스트 프레임워크이다. NG(Next Generation)라는 접미사가 나타내듯 테스트 프레임워크계의 기성세대인 JUnit의 부족한 점을 극복하기 위한 시도인 셈이다. 아직 이클립스와 같은 툴의 지원이 부족하다는 점(현재 작업이 진행 중이라고 한다) 말고는 셸이나 Ant에서 쉽게 실행할 수 있어 불편한 점은 없다.


그러면 TestNG를 설치하고 나서 TESTNG_HOME을 설정한 후 다음의 테스트 클래스를 실행해 보자.
package soa.test;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import soa.model.Taxi;
import soa.service.TaxiBookService;
import com.beust.testng.annotations.Test;
public class TaxiBookServiceTest {
@Test(groups = {function}, enabled = true)
public void callGetAvailableTaxis() throws NamingException {
InitialContext ctx = new InitialContext();
TaxiBookService service = (TaxiBookService) ctx.lookup(TaxiBookService.class.getName());
Taxi[] availableTaxis = service.getAvailableTaxis(null, null);
assert availableTaxis == null;
}
}
현재 우리가 기대할 수 있는 서비스의 행동은 이 정도이다. 아무튼 이 테스트는 더미 빈 클래스에서도 잘 돌아가고 어서션(assertion)도 통과된다. 참고로 JNDI 접속 정보는 TAXI_EJB_HOME에 jndi.properties라고 두고 실행 시에 클래스 패스에 TAXI_EJB_HOME을 추가해주면 설정하는 방식을 취했다. 그럼 간단히 테스트를 추가해 보자. 일단 입력은 그대로 null들로 하고, 0개 이상의 Taxi 배열이 넘어오도록 하며, null은 반환되지 않도록 한다. 그러면 다음처럼 어서션을 바꿔야 할 것이다.
assert availableTaxis == null;
->
assert availableTaxis != null;
그리고 간단하게 Taxi 빈 클래스에 운전사의 이름을 나타내는 driverName 속성을 갖도록 한 후, callGetAvailableTaxis()에서 받아온 택시 목록에서 운전사 정보를 출력해 보자.
for (Taxi taxi : availableTaxis) {
System.out.println(Driver Name: + taxi.getDriverName());
}
이렇게 테스트를 바꿔서 실행해 보면, 당연히도 AssertionError가 나며 실패한다. TaxiBookServiceBean의 getAvailableTaxis 메쏘드가 해당 테스트의 기대에 부응하게 만들어 보자.
public Taxi[] getAvailableTaxis(Location location, Calendar calendar) {
// TODO Get list from DB
Taxi[] list = new Taxi[2];
list[0] = new Taxi();
list[0].setDriverName(Jack);
list[1] = new Taxi();
list[1].setDriverName(Bill);
return list;
}
리치 클라이언트의 재림
일단 택시 예약 서비스의 목록만 간단히 해둔 채 포커스를 클라이언트로 돌려보자. 이미 클라이언트와 서비스 간의 정보 교류에 대한 계약은 이뤄져서, 클라이언트에서 택시 목록을 보여주는 기능을 구현해보려 한다.
그 전에 잠시 현대 클라이언트의 역사에 대해 재조명하는 시간을 가져본다. 메임 프레임과 접속하는 녹색 터미널 단말기의 시대를 넘어 단말기가 PC 하드웨어로 상향 조정되면서 그에 걸 맞는 클라이언트 소프트웨어 개발이 꽃을 피우는데, 바로 ‘4GL의 번성’이라고 불리는 90년대 초반이다. MS의 비주얼 베이직을 비롯하여 델파이에 이르기까지, 기존 터미널에 준하는 입출력을 더욱 보강해준 4GL 기반 클라이언트는 기업 시장뿐 아니라 일반 사용자 시장을 석권해가려는 찰라, 90년대 중반부터 불어 닥친 인터넷과 웹 브라우저의 폭발적인 보급으로 점차 암운이 깔리기 시작한다.
웹 페이지, 웹 서버, CGI, 웹 애플리케이션으로 이어지는 씬 클라이언트는 웹 브라우저가 PC의 기본 애플리케이션이 되면서 ‘이보다 더 좋을 수 없는’ 클라이언트 실행 환경으로 자리잡고, 기업 내부의 인트라넷에까지 침투, 유지보수성(특히 버그 수정과 버전 갱신)과 무거운 동작성이라는 약점을 안고 있는 리치 클라이언트 시대의 종언을 구하게 한다.
21세기로 넘어오면서 많은 시스템들이 재개발되고, 리치 클라이언트는 점차 입지가 좁아짐과 동시에 씬 클라이언트에 많은 짐을 넘겨주며 쓸쓸히 역사의 뒤안길로 사라지는 듯 했으나, 씬 클라이언트의 한계가 드러나면서 서서히 재기의 기운이 감돌기 시작한다.
인터넷·웹 프로토콜에 기반한 씬 클라이언트의 가장 큰 문제점은 사용자 체험(user experience), 달리 말하면 사용자가 그 사용자 인터페이스(User Interface, 이하 UI)를 써보면서 느끼는 편리함, 아름다움, 즐거움, 매력 등이 부족하다는 것이다. 씬 클라이언트는 말 그대로 군살과 기름을 쫙 뺀 UI이다. 웹 브라우저는 HTML이라는 한정된 양식을 통해 정보 검색과 열람을 하도록 설계된 매우 제한된 사용자 환경이다. 그래서 빠르고, 처음에는 쓰기 쉽고, 이식도 편하다. 문제는 그 이후다. 하드웨어와 운영체계는 끊임없이 진보하는데, 우리는 여전히 웹 브라우저가 보여주는 HTML에 매달리고 있다. 제약을 뛰어넘기 위해 DHTML, 자바스크립트, 액티브X 컨트롤, 플래시가 범람하게 되고, 이는 결국 씬 클라이언트가 도로 무거워지면서 동시에 브라우저 간의 호환성, 또 브라우저에 깔려 있는 운영체계 간의 호환성을 무너뜨리는 혼란을 초래하게 된다.
<화면 2> 이클립스 리치 클라이언트 플랫폼 기반 애플리케이션리치 클라이언트는 달라지고 있다. 인터넷과 웹을 적극적으로 포용하며, 플래시는 부활의 첫 신호탄을 날렸다. 더 이상 사용자 경험을 희생하지 말자는 것이 리치 클라이언트의 호소이다. 좋은 PC에 좋은 그래픽카드, 그리고 넉넉한 메모리, 빠른 인터넷 회선, 게임을 하듯이 인터넷 뱅킹을 할 권리가 사용자에게는 있는 것이다. 단축키와 펑션 키도 효율적으로 이용할 수 있고, 매번 화면 전환에 서버와 통신하지 않아도 된다. 웹 브라우저의 웬지 미덥지 않은 보안 능력에 걱정할 필요도 없다.
그럼에도 불구하고, 씬 클라이언트는 나름대로 쓸모가 있(고도 많)다. 모 아니면 도, 흑 아니면 백이던 시대가 가고, 사용자의 단말기와 선택에 따라 더 혹은 덜 풍요로운 체험을 선사할 수 있다. 리치 클라이언트의 재래와 씬 클라이언트와의 공존은 SOA에 있어 XML의 사용과 함께 그 가능성이 더욱 넓어지고 있다. 양쪽 다 제공하면 좋겠다는 것은 누구나의 희망이다.
하지만 추가 작업은 둘째치고라도 각 클라이언트별로 서버와 어떻게 통신할지부터 따로따로 하려니 골치가 아프다. 거기에 리치 클라이언트는 소켓 통신으로 데이터 송수신 성능을 향상시킬 수 있지만 방화벽 제한에 따른 포트 문제가 닥쳐온다. 방화벽에 친화적이며 HTTP를 전송 프로토콜로 사용하면서 투명한 구조의 XML의 메시징이 리치 클라이언트와 환상적인 궁합이 되리라는 짐작은 쉽게 가능하며, 이미 매크로미디어의 플렉스(Flex)와 MS의 닷넷이 그 실제를 보여주고 있다.
자바의 리치 클라이언트 대표 표준 기술은 Swing이다. 자바 런타임에 기본 내장되어 있고, 속도와 모양새도 과거에 비하면 정말이지 많이 좋아졌다. 하지만 코어 플랫폼에 속한 까닭에 다른 자바 확장 기술에 비해 발전이 더디었고, 썬의 통제권에 놓여 혁신적인 시도에는 발목이 잡혔다. 그러는 와중에 IBM이 이클립스를 통해 선보인 SWT은 AWT와 스윙을 장점만을 살린 듯한 인상과 함께 이클립스 개발 환경을 통해 호평을 얻게 되었다.
필자는 Swing으로 몇 차례 프로젝트를 한 경험으로 표준 기술이라는 측면의 Swing의 장점을 높이 사지만, 『토탈 이클립스』라는 국내서의 베타 리뷰어를 하면서 SWT와 JFace(SWT는 AWT와 Java2D 등 GUI 기반과 Swing 컴포넌트의 기본층에, JFace는 Swing의 고급 컴포턴트 층에 해당한다고 볼 수 있다)의 강력함, 특히 각 운영체계와 위화감 없이 감응도 좋은 GUI 제공에 경탄을 금치 못했다. 바로 이런 운영체계 밀착이 Swing 진영의 십자포화를 맞는 곳이기도 하지만, 어차피 메이저 클라이언트 플랫폼인 윈도우에서의 사용자 체험이 더 진하게 다가옴도 부인하기 힘들다.
이클립스 RCP
그러면 먼저 이클립스에서 RCP 애플리케이션을 위한 프로젝트를 만들어보자. [New
프로젝트 이름은 taxi-rcp로 하고, Project contents에서 Use default를 체크하지 않고, 디렉토리를 TAXI_HOME 밑에 rcp 디렉토리(앞으로 TAXI_RCP_HOME)를 만들어 선택한다. Create OSGi bundle manifest를 체크하고 나서 다음으로 넘어가자.
다음 화면에서는 Plug-in ID는 soa.rcp, Plug-in Name은 Client Plug-in, Runtime Library는 client.jar, Plug-in Class의 class name을 soa.rcp.TaxiPlugin으로 하고, Rich Client Application에서 Yes를 선택한 후 다음으로 넘어간다. 다음 템플릿 선택 화면에서는 RCP application with a view를 선택한 후 다음으로 간다. 마지막 애플리케이션 정보 화면에서 Application window title은 Taxi Booking Client Application으로, Java package name은 soa.rcp을 입력하면 프로젝트 생성이 완료된다.
템플릿으로부터 만들어진 택시 예약 RCP 클라이언트를 실행해 보자. taxi_rpc 프로젝트를 선택한 후 컨텍스트 메뉴(마우스 오른쪽 버튼 클릭)에서 [Run As
<화면 3>과 같이 잘 나와 주면 RCP 애플리케이션 제작 준비는 마친 셈이다. 그런데, RCP 애플리케이션 개발과는 별도로 RCP 애플리케이션을 RCP 애플리케이션답게 만들어주는 것이 있으니 바로 제품 설정(Product Configuration)이다. 우선 이클립스의 Run... 메뉴에서 방금 실행했던 항목이 Eclipse Application(이나 숫자가 뒤에 붙어서)으로 추가되어 있을 것을 선택하여 이름을 Taxi client로 바꾼다. 그다음 [New
제품 설정을 마치고 나면 TaxiClient.product의 Overview 화면이 나오는데, 먼저 Product ID에서 New... 버튼을 눌러 제품 정의를 하자. Defining Plug-in에서는 Browse 버튼을 눌러 soa.rcp 플러그인을 선택한다. 다음 Product ID는 TaxiClient를 입력하고, Product Application에서 soa.rcp.application을 고른 후 마친다. 다음은 Product Name을 Taxi Booking Client이라고 준다.
여기까지 설정한 것을 간단히 테스트를 해보자. TaxiClient.product의 Overview에서 Testing 섹션의 Synchronize를 누르면 제품 정의에서 선택한 플러그인과 제품 설정을 맞춰준다. 다음으로, Launch the product를 누르면 아까 애플리케이션 실행과 똑같은 결과를 보게 된다.
마지막으로 택시 예약 RCP 클라이언트를 익스포트해서 패키지로 만들어 보자. Overview에서 Synchronize로 플러그인과 동기화한 후, 익스포트할 위치를 TAXI_RCP_HOME으로 잡아 주고, 파일 이름을 taxi-rcp-client라고 한 뒤 Export를 누르면 약 5메가 가량의 taxi-rcp-client.zip이 생긴다. 이 파일을 TAXI_HOME 밑에 푼 후 TAXI_HOME/eclipse 디렉토리에서 eclipse를 실행하면 아까 제품 실행과 똑같은 화면이 나온다. 지금까지 RCP 프로젝트 작성을 정리해보면 다음과 같다.
[1] [New
[2] taxi-rcp 프로젝트를 Eclipse 애플리케이션으로 실행한 후 해당 실행 항목의 이름을 Taxi client로 지어준다.
[3] [New
[4] TaxiClient.product에 필수 항목을 추가한다.
[5] 익스포트하여 패키징한다.
RCP 애플리케이션 개발 시에는 제품 설정을 건드릴 필요가 없다. 패키징하여 배포하는 시점에서 제품 설정의 효력이 발생함을 주의하자. 이렇게 패키징된 택시 예약 RCP 애플리케이션은 JVM만 깔려 있다면 어느 디렉토리에 풀어도 잘 실행되는 매우 훌륭한 소프트웨어 패키지이다. 추가 설정으로 JVM까지 포함할 수 있고 각 운영체계 별로 특화된 패키징(윈도우 운영체계에서는 Winamp가 쓰는 NSIS 인스톨러로 만드는 것도 가능하고, 자바 웹 스타드를 통할 수도 있다)도 지원하고 있다. 참고로 TaxiClient.product의 Branding 탭에서는 스플래시 화면(프로그램이 시작하면서 나오는 화면), 프로그램의 개발자나 개발사를 소개하는 About 화면도 설정할 수 있어 무척 편리하다.
화면 구성
앞서 <화면 3>을 보면 One, Two, Three라고 나오는데, 이것을 택시 운전사 이름의 목록으로 바꿔보자. 연재 시작부터 강조해온 점이지만, 서비스와 클라이언트는 인터페이스 성립 이후 부터는 독립적으로 개발과 테스트가 가능해야 한다고 했다. 비즈니스 로직에 해당하는 EJB의 soa.model은 그런 측면에서 공유가 가능하면서도 각자 소스를 가지고 있어야 한다. 이런 전략은 taxi-ejb 프로젝트의 src에서 soa.model 패키지를 taxi-rcp 프로젝트의 src로 복사해옴으로 실현된다.
물론, 이러한 공통 소스를 따로 관리하여 두 프로젝트가 완전히 똑같은 자료 모델을 쓰게 할 수도 있다. 하지만 그러한 방식은 SOA의 클라이언트와 서비스 간의 느슨한 연결(loosely coupled)과는 맞지 않다. 쌍방 통신상의 규약만이 있을 뿐, 나머지는 각자의 길을 걷는 것이다. 일단은 편의상으로 EJB로부터 모델를 빌려오지만(그리고 실제 프로젝트에서도 이렇게 하면 편하겠지만), EJB쪽의 모델과 RCP쪽의 모델은 얼마든지 다를 수 있다.
RCP 클라이언트에서 서비스를 호출하는 것도 EJB로부터 모델을 빌려오는 것과 비슷하게 해결된다. 먼저, taxi-ejb 프로젝트의 src에서 soa.service 패키지를 taxi-rcp 프로젝트의 src로 복사해온다. 다음, taxi-rcp의 soa.service 패키지의 TaxiBookService와 TaxiBookServiceBean에 있는 어노테이션을 모두 지운다. 그리고 나서, soa.rcp.View의 내부 클래스인 ViewContentProvider를 다음과 같이 고친다.
class ViewContentProvider implements IStructuredContentProvider {
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
}
public void dispose() {
}
public Object[] getElements(Object parent) {
TaxiBookService service = new TaxiBookServiceBean();
Taxi[] availableTaxis = service.getAvailableTaxis(null, null);
String[] driverNames = new String[availableTaxis.length];
for (int i = 0; i < driverNames.length; i++) {
driverNames[i] = availableTaxis[i].getDriverName();
}
return driverNames;
}
}
TaxiBookService service = new TaxiBookServiceBean(); 부분이 압권이다. EJB 3.0의 비즈니스 인터페이스와 빈 클래스가 얼마나 개념적으로 훌륭한 지를 실감할 수 있다. 그저 어노테이션을 지웠을 뿐인데, 인터페이스-임플리멘테이션 짝이 J2EE 환경 없이도 완벽하게 들어맞는다. 물론, 이러한 접근은 빈 클래스에 J2EE 기술이 쓰이면 통하지 않는다. 그러나 비즈니스 인터페이스의 의미의 파급이 자연스럽고, 더불어 더미 빈 클래스의 대입이 유연하다는 점은 EJB 3.0의 SOA적 장점으로 꼽을만하다.
고친 예제를 실행해보면 One, Two, Three 대신 Jack, Bill이 나옴을 확인할 수 있다. 이제부터 EJB 컴포넌트와 RCP 클라이언트의 개발은 완전히 별도로 진행할 수 있으며, 테스트 작성도 서로 의존하지 않고 테스트용(더미) 데이터를 통해 자신들의 기능에 충실히, 특히 상대편(RCP는 EJB, EJB는 RCP)의 개발 중의 각종 돌발 상황에 영향을 받지 않고 독자적으로 진행이 가능하다.
드디어 드러나는 차세대 자바 웹 서비스
다음 호에는 어쩌면 자바 웹 서비스의 대박 소식을 전할 수 있을지도 모르겠다(그래서 JAX-RPC 2.0과 JAXB 2.0 RI의 공개가 늦어지는 지도). 마지막으로 택시 예약 서비스 빈 클래스와 RCP의 UI의 빈 부분을 채워가며 복습 해 보기를 강력 추천한다. 재미는 필자가 보장한다.@
* 이 기사는 ZDNet Korea의 제휴매체인 마이크로소프트웨어에 게재된 내용입니다.
지금 뜨는 기사
이시각 헤드라인
ZDNet Power Center
