유니버설미들웨어프레임워크 - OSGi OSGi 개발환경구현 2 - OSGi Bundle 구현 지난시간에는 OSGi 개발환경구축에앞서 OSGi 애플리케이션구현을위한실행과개발환경에대해살펴봤다. 그흐름을이어서이번시간에는 OSGi 애플리케이션 (Bundle) 을직접구현하고 OSGi 프레임워크에등록, 수행, 테스트, 그리고원격관리를수행하는일련의번들라이프사이클을살펴보기로한다. 6 연재순서 1 회 2007. 7 임베디드를넘어엔터프라이즈로! 2 회 2007. 8 OSGi 서비스와활용사례 3 회 2007. 9 OSGi 개발환경구현 1 - J2ME & OSGi 4 회 2007. 10 OSGi 개발환경구현 2 - OSGi Bundle 구현 5 회 2007. 11 이클립스의핵심, Equinox 6 회 2007. 12 엔터프라이즈로의확장, Spring-OSGi 김석우 suhgoo.kim@samsung.com Polytech 전산학석사. 현재삼성전자선행개발팀에근무중이며센서네트워크를활용한빌딩의쾌적제어시스템을개발하고있다. 또한 OSGi 기반의센서네트워크컨트롤러를구상하고있다. 많은 OSGi 관련툴들이나와있지만이번호에서도역시 IBM 의웹스피어 (Websphere) 솔루션을사용해구현해보기로한다. 구현할내용은다음과같다. - HttpLogService를이용한번들구현 - OSGi 프레임워크상에서번들 Test IBM에서는 OSGi 관련솔루션들을 IBM Workplace Client Technology, Micro Edition이라는이름으로 One-stop 솔루션을제공하는데, 이클립스기반의통합개발툴인 WSDD (WebSphere Studio Device Developer), OSGi 기반의미들웨어툴킷 Micro Environment Toolkit for WebSphere Studio, J2ME 런타임모듈과 DB2e를제공하는 WebSphere Everyplace Micro Environment로구성되어있다. SMF (Service Management Framework) 는 IBM의 OSGi 솔루션이름이면서또한 Front-End Solution의핵심컴포넌트가운데하나이다. IBM의 Front-End Solution을 Workplace Client Technology라고통칭하기도하는데주로 PC 기반의비즈니스애플리케이션, 디바이스콘트롤, 임베디드및모바일디바이스를 타깃으로운용된다. OSGi 번들아키텍처 OSGi에서는모든기능과서비스들이번들에의해구현되고서비스로운영된다. 번들이기본적인구성요소인이유로는느슨한결합 (loosely-coupling) 과재사용성 (reusability) 에있는데, 번들은 Dependency static sharing과 dynamic services로각각의독립성 (Dependency) 을유지하게된다. 그렇다면번들의독립성이란어떤의미일까? OSGi는같은번들이라고해도다른버전의번들을동시에사용할수있다. 1.0의 A 번들과 1.5의번들이함께구동될수있다는뜻이다. 그렇게운영되는것은번들이다음의구성요소들로구분되고요청하는번들이나서비스에인터페이스로제공되기에가능하다. Bundle manifest file 번들의가장기본적인명칭, 버전, 제공기능및다른번들과의 static & dynamic interaction 방법들을서술하고있다. Bundle activator implementation 236 m a s o
우리는번들이 OSGi 시스템프레임워크로부터 install, update, start, stop되는일련의라이프사이클을가지고있음을알고있다. 이렇게번들이시스템프레임워크와연동되고컨트롤할수있게해주는것이바로 OSGi BundleActivator inter face이다. Bundle BundleActivatorImpl Custom ServiceFactoryImpl Custom Service Impl new Instance Custom Service Interface Service Consumer start()/stop() BundleActivator getservcie()/ ungetservice() ServiceFactory registerservice() getservice() SMF Runtime BundleContext Custom service interface 번들이반드시 R3, R4의규약에나온서비스들로만구현될수 Bundle Business Logic Custom Service Interface 있는것은아니다. 각벤더에서 < 그림 1> Bundle Process Flowdiagram 독자적인번들을서비스형태로 구현할수있는데, 이렇게각벤더들이각각독자적으로구현한번들과서비스를사용하려고할때필요한것이바로 Custom service interface이다. Custom service implementation custom service interface를정의한 Class 메소드 Business logics Business logics 부분은일종의번들제공기능의알고리즘이면서블랙박스라고할수있다. 또한 Java class file이나다른 resource file을 Invoke해서사용할수도있다. < 그림 1> 은 OSGi 시스템프레임워크 (IBM에서는 SMF Runtime) 와 service consumer bundle 그리고 service provider bundle간의 interaction을보여주고있다. HttpLogService를이용한번들구현 WSDD(WebSphere Studio Device Developer) 를이용해 HttpLog라는번들을구현해보기로한다. HttpLog 번들은특정한 HttpServlet에의해엑세스된트랜잭션의로그메시지를추적하고기록하는기능을가진다. Step 1 : Bundle skeleton 생성 WSDD에서자바프로젝트를통해 HttpLog라는번들 skeleton을만든다. 또한 Properties를통해 OSGi framework library osgi.jar와 servlet.jar의 build path를수정한다. < 화면 1> Java Build Path 수정 Step 2 : OSGi BundleActivator interface 구현이제 HttpLogBundleActivator라는자바클래스를작성하면서 OSGi BundleActivator interface를구현해보기로한다. BundleActivator interface는두개의메소드를정의하는데 start() 와 stop() 이바로그것이다. start() method는번들이 active될때 OSGi 시스템프레임워크로부터 invoke된다. < 리스트 1> 의코드에서 BundleContext argument는 delegation object로프레임워크로부터 invoke될때구동되는 Operation set이다. < 리스트 1> HttpLogBundleActivator.java public class HttpLogBundleActivator implements BundleActivator BundleContext bc; public void start(bundlecontext context) throws m a s o 237
6 _ OSGi 개발환경구현 2 - OSGi Bundle 구현 Exception bc=context; //to add initialization code here public void stop(bundlecontext context) throws Exception Step 3 : Register custom service 이제 HttpLogService라는로그기록을관리하는 custom service를구현하기로한다. 총 3개의자바파일을코딩하는데, 명칭은각각다음과같다. HttpLogService.java, HttpLog ServiceImpl.java, HttpLogServiceFacotry.java. 우리는 custom service를위한하나의 interface class와 implement ation class를구현한다. 예를들어 HttpLogService interface의경우 log() 라는하나의메소드를정의한다. < 리스트 2> HttpLogServiceImpl.java package httplog; public interface HttpLogService void log(string message); < 리스트 3> HttpLogService.java package httplog; public class HttpLogServiceImpl implements HttpLogService static public List messagearray = new ArrayList(); public void log(string message) HttpLogServiceImpl.messageArray.add(message); 일반적으로어떤 custom services를요청하는번들 (hosting bundle) 이 active될때해당 custom services는시스템프레임워크에등록된다. 따라서 Step2에서구현했던 HttpLogBundle Activator 클래스에 < 리스트 4> 의 start() method를추가한다. < 리스트 4> HttpLogBundleActivator.java public class HttpLogBundleActivator implements BundleActivator static final String httplogservicename = HttpLogService.class.getName(); public void start(bundlecontext context) throws Exception registerhttplogservice(); private void registerhttplogservice() HttpLogServiceFactory sf = new HttpLogServiceFactory(); ServiceRegistration sr=bc.registerservice(httplogservicename,sf,null); 또한 registerservice() 가호출될때해당번들은정의된 custom service name과 OSGi ServiceFactory interface의서비스오브젝트, 그리고해당서비스의 properties가포함된 Dictionary object를제공한다. 각각의 ServiceFactory subclass 는 getservice() 와 ungetservice() 라는두개의메소드를갖게된다. 우리가작성하는코드에서는 sf가하나의 HttpLog Ser vicefactory 타입이면서또한 HttpLogServiceImpl instances를 generate하는역할을한다. < 리스트 5> HttpLogServiceFactory.java package httplog; import org.osgi.framework.bundle; import org.osgi.framework.servicefactory; import org.osgi.framework.serviceregistration; public class HttpLogServiceFactory implements ServiceFactory public Object getservice(bundle bun, ServiceRegistration sr) return new HttpLogServiceImpl(); public void ungetservice(bundle bun, ServiceRegistration sr, Object obj) Step 4 : Consume external service 우리가작성하는 HttpLog 번들에의해제공되는외부서비스는바로 HttpService이다. 사용자는 localhost의 HttpServlet이액세스한기록들을 HttpLog 번들이작성한레코드를통해추적할수있다. 이러한기능을제공하기위해 HttpLog 번들은 HttpService가제공하는인터페이스를통해 HttpService 번들을 servlet object로등록해야만한다. HttpLog 번들이 start될때위의과정이자동적으로발생한다. 238 m a s o
< 리스트 6> HttpService 에특정 HttpServlet object 등록 public class HttpLogBundleActivator implements BundleActivator static final String servleturi = /httplog ; private void initialize() //Import HttpService attachtohttp(); //register HttpLogService registerhttplogservice(); private void attachtohttp() httpcontext = new HttpContext() request, response) public boolean handlesecurity(httpservletrequest return true; HttpServletResponse public URL getresource(final String name) return (URL) AccessController.doPrivileged(new PrivilegedAction() public Object run() String resource = name; if (resource.charat(0)!= / ) resource = /.concat(resource); //$NON-NLS-1$ return getclass().getresource(resource); ); ; public String getmimetype(string name) return null; catch (ServletException e) e.printstacktrace(); catch (NamespaceException e) e.printstacktrace(); //HttpLogServlet.java package httplog; import java.io.ioexception; import java.io.printwriter; import java.util.list; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import javax.servlet.servletexception; public class HttpLogServlet extends HttpServlet protected void doget(httpservletrequest req, HttpServletResponse res) throws ServletException, IOException res.setcontenttype("text/html; charset=utf-8"); PrintWriter out = res.getwriter(); out.print("<html><head><title>" + "Http Log Display" + "</title></head>"); out.print("<body text=\"#000000\" bgcolor=\ "#C0C0C0\" link=\"#0000ee\" vlink=\"#551a8b\" alink= \"#FF0000\">"); List msgarray = HttpLogServiceImpl.messageArray; int len=msgarray.size(); for (int i=0;i<len;i++) String msg= (String)msgArray.get(i); out.print(msg); out.println("</body></html>"); ServiceReference httpsr = bc.getservicereference(httpservice.class.getname()); HttpService http = (HttpService)bc.getService(httpSR); try http.registerservlet(servleturi, new HttpLogServlet(), null, httpcontext); < 리스트 6> 을살펴보면번들이초기화될때특정한 Http Servlet object가 HttpService에등록된다. 일반적으로 external service가구동되기전에요청번들은 OSGi 시스템프레임워크로부터 external service instance가어디에위치해있는지를알필요가있다. 이러한일련의과정은 BundleContext에서 get ServiceReference() 와 getservice() 메소드를제공함으로써수행된다. 두개의메소드는필요로하는정보들을 service regis m a s o 239
6_ OSGi 개발환경구현 2 - OSGi Bundle 구현 try 에서찾아리턴하는역할을한다. Step 5 : Migrate to bundle format 코드를모두작성하고나면실제번들을패키지형태로작성하는과정을거친다. WSDD에서 File -> New -> SMF를고르고, 번들폴더를선택해서새로운번들을생성한다. < 화면 4> MANIFEST 작성화면 (1) - Bundle-Version : 1.0.0. - Bundle-Activator : httplog.httplogbundleactivator - Import Services : org.osgi.service.httpservice - Import Packages : javax.servle, javax.servlet.http, org.osgi. < 화면 2> 번들폴더생성 타깃번들폴더에서 HttpLog를선택한다. 나머지옵션은선택하지않는다. framework, org.osgi.service.http. OSGi는하나의 JVM 환경에서작동한다. 그러나하나의 VM 이라고하나의프로세스또는싱글태스크라고생각하면안된다. 앞에서도이야기했지만, OSGi는비록하나의 VM 위에서구동하더라도번들간의독립성과협업을위해각번들마다서로다른클래스로더가구동해작동하게되어있다. 따라서각번들은 MANIFEST 파일에서자신의클래스패스와버전, 기본적인정보들을레퍼런스하게된다. - Export Packages : httplog. - Export Services : httplog.httplogservice. < 화면 3> 번들폴더컨테이너선택 다음단계로 MANIFEST를작성할단계이다. MANIF EST.MF 파일은번들들의독립성과정보공유및협업을위해매우중요한정보파일이다. 반드시일정한 OSGi 명세 (specifi cation) 에의해작성되어야한다. WSDD의 MANIFEST editor 는 < 화면 4> 처럼사용자가쉽게작성할수있게도움을준다. 다음은섹션을필수적으로정의해야하는항목들로우리가작성한파일을예로든내용이다. - Bundle-Name : HttpLog. < 화면 5> MANIFEST 작성화면 (2) 240 m a s o
MANIFEST.MF 파일까지생성하면이제번들을배포할준비는모두마친셈이다. 번들의배포는.jar 패지키형태로생성해이뤄지며여기서우리는 httplog.jar란이름으로생성한다. WSDD의 Project explorer view에서 HttpLog project를 Export하면된다. Step 6 : OSGi 서버로번들배포작성한번들을배포하려면 OSGi 시스템프레임워크가탑재된시스템을찾고그곳에추가하면된다. WSDD에서는이런모든과정을매우쉽게접근할수있도록돕는데, 이를위해다음의방법을사용한다. 우선 [Run] Window를실행시켜 OSGi 서버 (SMF Server) 를생성하고구동한다. 이렇게 SMF Server를구동한후에 Project Explorer에서 [HttpLog project] 를클릭하고 SMF -> Submit 번들을선택하면번들의배포가끝난다. SMF 서버구동시에서버가되는타깃에대한대화상자가나오는데, 그곳에아이디와패스워드, IP 등에대한기본적인액세스정보들을적는다. 우리는로컬PC에서작업을하므로 Admin@localhost:8080/smf 로기입한다. 이렇게모든서버의구동과번들의배포를마친후에 [SMF perspective]-[smf Bundle Servers view] 에서 HttpLog 번들이 SMF 서버에배포된것을확인할수있다. IBM 솔루션에서는이러한모든과정들이 WSDD의다이얼로그박스 (Dialog Box) 에서자동으로이뤄지지만, 다른여타의 OSGi 솔루션에서는각기다른방법을써서로컬서버및원격서버 ( 실제 OSGi가설치된 PC 및타깃디바이스 ) 로배포할수있다. < 화면 6> SMF Server 생성및구동 < 화면 9> 배포된번들확인 < 화면 7> Bundle Deployment < 화면 8> 타깃디바이스 / 서버설정 Step 7 : Bundle testing 이제우리가구현한번들을배포했고테스트하는단계만남았다. 이역시도테스트번들을구현하기로한다. 테스트번들을 HttpLogTester로명명하고, 이번들은테스트용으로 HttpLog Service를 invoke하는것이주된기능이다. 이번들이 HttpLog Service를 invoke하면그다음단계로넘어간다. 여기서 Http log가화면에정상적으로나타난다면우리가만든번들이성공적으로작성된것으로본다. 이번들역시우리가거쳐왔던 step 1, 2를반복해 bundle skeleton을생성한다. 빌드패스에 httplog.jar를포함하며 < 리스트 7> 의코드와같이 HttpLog TesterBundleActivator에 start() method를코딩한다. Step 2-6을반복하며마지막으로역시 HttpLogTester 번들을 SMF 서버에배포한다. m a s o 241
6 _ OSGi 개발환경구현 2 - OSGi Bundle 구현 < 리스트 7> HttpLogTesterBundleActivator.java class HttpLogTesterBundleActivator implements BundleContext public void start(bundlecontext context) throws Exception bc=context; ServiceReference httplogsr=bc.getservicereference(httplogservicename); HttpLogService httplog =(HttpLogService)bc.getService(httpLogSR); httplog.log("hello world!"); Step 8 : Test HttpLog in SMF runtime 이제우리는배포된 HttpLogTester 번들을실제 installactivate시키는과정을거쳐우리가만든번들이제대로작동되는지를확인해야한다. SMF Runtime을실행시키고 Http LogTester를인스톨한다. 이모든과정역시 WSDD의 SMF Bundle Server view에서지원된다. HttpLogTester 번들이 SMF 번들서버에인스톨되는순간필요한번들을요청하게되어 HttpLog와 HttpService는자동적으로함께인스톨되고 ready하게된다. 이제로그메시지를확인하기위해웹브라우저에 http:// localhost/httplog 라고입력하면곧우리는브라우저에서해당로그결과를살펴볼수있다. 이번호에서는 OSGi 번들의기본적인구조를비롯해코드를통한구현과배포, 실행에대해각각살펴봤다. 예제코드에서로컬서버와번들간의인터페이스들을살펴봤지만, 실제구현되는코드에서는 DB와의연동과원격관리서버를통한업데이트및관리, 네이티브코드 (Native Code) 와의연동등을통해 OSGi의장점을최적화해사용하고있다. 특히방금이야기한 DB hand ling & Sync, Bundle Remote Management & Dynamic Update, JNI를통한 Native code interface 등은 OSGi의고급핵심기술들로향후더많이사용될중요한부분이다. 여타의 OSGi 솔루션들도마찬가지겠지만, 특히 IBM의 OSGi 솔루션은이클립스플러그인프레임워크 (Equinox) 의비즈니스프로세스애플리케이션 (Expeditor) 등을거쳐더욱강력한미들웨어프레임워크 (Middleware Framework) 로부각되고있다. 다음호에서는 RCP(Rich Client Platform) 로대변되는이클립스 OSGi 프레임워크인 Equinox를통해임베디드에서데스크탑애플리케이션, 그리고플랫폼의일부분으로까지확장되는 OSGi 의사례를살펴본다. < 화면 10> SMF Bundle Server view < 화면 11> 번들인스톨화면 참고자료 1. Managed mobile clients with OSGi - http://www.ibm.com/developerworks/ library/wi-osgi 2. IBM Workplace Client Technology, Micro Edition and Open Services Gateway Initiative (OSGi) -http://www.ibm.com/developerworks/websphere/library/ techarticles/0606_salkosuo/0606_salkosuo.html 3. IBM Service Management Framework - http://www-306.ibm.com/software/ wireless/smf/index.html 242 m a s o
m a s o 243