일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 삼성전자 소프트웨어멤버십 SSM
- hopfield network
- 나르왈프레오
- 고려대학교
- BAM
- 구글 앱 엔진
- 멤버십
- SSM
- Friendship
- 가상화
- 갤럭시탭S8울트라
- 하이퍼바이저
- Bidirectional Associative Memory
- 물걸레로봇청소기추천
- 빅데이터
- 삼성소프트웨어멤버십
- 파이썬
- 패턴인식
- 동아리
- 신경망
- NarwalFreo
- 인공지능
- 패턴 인식
- 삼성
- 증강현실
- Python
- 물걸레자동세척로봇청소기
- Google App Engine
- 신경회로망
- Neural Network
- Today
- Total
정보공간_1
[2기 강북 송석호]OSGi 동적으로 서비스 추적하기 본문
안녕하세요.
강북 멤버십 20-2기 송석호입니다.
이번 달에는 equinox 기반으로 OSGi 서비스를 동적으로 추척하는 법을 살펴보겠습니다.
1. 동적으로 서비스 추적하기
지난 달에 고려하지 않았던, 만약 한개 이상의 MovieFinder
가 있다면? 즉, 어떤 번들이라도MovieFinder
인터페이스를 구현하는 서비스를 등록할수 있고, 레지스트리 입장에선 모든 번들은 같습니다.
이 문제를 간단히 무시할 수도 있고, 실제로 지난번엔 그렇게 했습니다. ServiceTracker
에게 getService()
를 호출함으로써, 서비스 레지스트리에 의해 선택된 임의의 MovieFinder
인스턴스를 받게 됩니다. 이 선택에 영향을 줄 수 있는 여러가지 방법이 있지만, 사용자로서의 이 선택에 대한 완벽한 조정능력을 가지지는 못합니다. 그리고 실제로 더 많은 조정 능력을 가지게 되는 것은 좋은게 아닙니다. 즉 MovieFinder
의 어떤 인스턴스라도 사용할수 있어야 한다는것이죠. 처음부터 인터페이스를 사용하는 이유이기도 합니다.
대신에 여러개의 서비스 인스턴스들에 대해 인지하고 사용하는 것은 때때로 유용할 수도 있습니다. 예를 들어, 여러개의MovieFinder
인터페이스가 가용하다면 MovieLister
가 이용할수 있는 영화 데이타에 대한 여러 개의 소스가 있다는 것을 의미합니다. 검색 시에 이들을 모두 이용함으로써, 더 넓고 유용한 검색결과를 사용자에게 제공할 수 있게됩니다.
마지막에 논의했던 문제로 다시 돌아가서, 만약 MovieFinder
서비스가 사용 불가하다면 어떤일을 하는것이 맞을까요 ? MovieFinder
가 가용하지 않을때 listByDirector
메소드가 호출될때마다 null 을 리턴하는 간단한 방법을 사용했습니다. 하지만 MovieFinder
가 존재하지 않는다면 MovieLister 의 메소드 호출도 볼가능하게 하면 어떨까요 ?MovieLister
는 MovieFinder
와 마찬가지로 서비스입니다. 만약 MovieFinder
서비스가 사라진다면, MovieLister
도 같이 사라지게 하는건 ? 다시 말해, 우린 MovieLister
서비스가 MovieFinder
에 대해 “1 대 다” 관계를 가지기를 원했습니다. 지난 달에는 “0 대 1″ 관계였습니다.MovieListerImpl
를 변경해봅시다. 아래 코드와 작성하세요.
MovieListerImpl.java
---------------------------------------------------------------------------------------------------------------package osgitut.movies.impl; import java.util.*; import osgitut.movies.*; public class MovieListerImpl implements MovieLister { private Collection finders = Collections.synchronizedCollection(new ArrayList()); protected void bindFinder(MovieFinder finder) { finders.add(finder); System.out.println("MovieLister: added a finder"); } protected void unbindFinder(MovieFinder finder) { finders.remove(finder); System.out.println("MovieLister: removed a finder"); } public List listByDirector(String director) { MovieFinder[] finderArray = (MovieFinder[]) finders.toArray(new MovieFinder[finders.size()]); List result = new LinkedList(); for(int j=0; j < finderArray.length; j++) { Movie[] all = finderArray[j].findAll(); for(int i=0; i < all.length; i++) { if(director.equals(all[i].getDirector())) { result.add(all[i]); } } } return result; } }
---------------------------------------------------------------------------------------------------------------
이제 MovieListerImpl
에서 OSGi 에 대한 의존성을 없앴습니다. 이젠 순수 POJO 입니다. 이 클래스는 누군가 또는 어떤 것이 MovieFinder
서비스를 찾아서 bindFinder
메소드를 통해 제공되어야 합니다. 이렇게 하기 위해서osgitut/movies/impl/MovieFinderTracker.java
라는 새로운 파일을 아래와 같이 작성합니다.
MovieFinderTracker.java
---------------------------------------------------------------------------------------------------------------
package osgitut.movies.impl; import org.osgi.framework.*; import org.osgi.util.tracker.*; import osgitut.movies.*; public class MovieFinderTracker extends ServiceTracker {
private final MovieListerImpl lister = new MovieListerImpl(); private int finderCount = 0; private ServiceRegistration registration = null; public MovieFinderTracker(BundleContext context) { super(context, MovieFinder.class.getName(), null); } private boolean registering = false; public Object addingService(ServiceReference reference) { MovieFinder finder = (MovieFinder) context.getService(reference); lister.bindFinder(finder); synchronized(this) { finderCount ++; if (registering) return finder; registering = (finderCount == 1); if (!registering) return finder; } ServiceRegistration reg = context.registerService( MovieLister.class.getName(), lister, null); synchronized(this) { registering = false; registration = reg; } return finder; } public void removedService(ServiceReference reference, Object service) { MovieFinder finder = (MovieFinder) service; lister.unbindFinder(finder); context.ungetService(reference); ServiceRegistration needsUnregistration = null; synchronized(this) { finderCount --; if (finderCount == 0) { needsUnregistration = registration; registration = null; } } if(needsUnregistration != null) { needsUnregistration.unregister(); } } }
---------------------------------------------------------------------------------------------------------------
이 클래스는 지난번에 얘기했던 ServiceTracker
클래스를 오버라이드 해서, ServiceTracker
가 서비스 등록/삭제 시 동작하는 방식을 커스터마이즈 합니다. 특징적으로, MovieFinder
서비스가 추가될때 addingService
메소드가 호출되고 ,MovieFinder
가 제거 될 때 removedService
가 호출됩니다. 오버라이드 할수 있는 메소드중에 modifiedService
도 있지만 여기선 필요하지 않습니다.
이 두개의 메소드에 대해선 살펴 볼 만한 가치가 있습니다. 첫째로 addingService
에선 전달받은 인자가 실제 서비스 구현 개체가 아니라 ServiceReference
입니다. ServiceReference
는 인자로 전달될 수 있는 가벼운 핸들이며, 서비스에 대한 속성(서비스 등록시에 전달했던)를 읽는데 사용이 가능합니다. 결정적으로, ServiceReference
를 얻는것은 OSGi 프레임워크가 해당 서비스의 레퍼런스 카운트를 증가시키지 않습니다. Java Reflection API 에 있는 WeakReference
클래스와 비슷하게 생각하시면 됩니다.
예제에서 ServiceReference
로 할 첫번째 작업은 MovieFinder
서비스 개체를 얻는것입니다. 이를 위해서 다시 BundleContext 를 필요로 합니다. 편리하게도 슈퍼클래스인 serviceTracker가
BundleContext
에 대한 레퍼런스를 context
라고 이름붙인 protected 멤버로 가지고 있으므로 바로 사용할 수 있습니다.
다음으로 위에서 정의한 MovieListImpl
의 bindFinder
메소드를 가지고 파인더를 바인딩 합니다. 그리고 MovieListerImpl
자체를 MovieLister
인터페이스로 서비스에 등록합니다. 이미 서비스가 등록되지 않았을 때만 서비스를 등록하고 있다는 걸 주의하세요. 이번 시나리오 에선 한개의 MovieLister
가 여러개의 MovieFinder
서비스를 추적하기를 원합니다.
마지막으로 메소드에서 리턴합니다. addingService
의 리턴타입은 그냥 Object
입니다. 그렇다면 무엇을 리턴해야 할까요? 사실은 ServiceTracker
는 상관하지 않습니다. 원하는 어떤것을 리턴해도 됩니다. 어쨌든, addingService
에서 리턴하는 객체는 modifiedService
나 removedService 가
호출되었을 때 다시 주어집니다. 그러므로 removeService
메소드의 첫번째 줄을 보시면, 객체를 MovieFinder
로 캐스팅하는 것을 볼 수 있습니다. 이렇게 해서 리스터로 부터 unbound
될 수 있는 것이죠. 그리고는 만약 추적하는 finder 들이 0개가 되었을 때 MovieLister
서비스를 등록해제 합니다.
일반적으로, addingService
에서 한 일들은 removedService
메소드에서 되돌려 놔야 합니다. 그러므로, addingService
메소드에서 리턴할 것은 우리가 무슨 일을 했는지를 알 수있도록 도와 주는 것이야 합니다. HashMap
에서의 Key가 될 수도 있고, ServiceRegistration
객체일수도, 이번 경우처럼 실제 서비스 객체일수도 있습니다.removedService
의 마지막 단계로, “가져왔던(Got)” 서비스를 “돌려줘야(Unget)” 합니다. 이는 서비스 레지스트리가 서비스 사용 카운터를 줄이게 해서, 카운터가 0 이 되었을때 서비스가 해제될수 있도록 하기위한 것이므로, 매우 중요합니다.
자 이제 Activator가 필요합니다.
osgitut/movies/impl/TrackingMovieListerActivator.java
입니다.
TrackingMovieListerActivator.java
---------------------------------------------------------------------------------------------------------------
package osgitut.movies.impl; import org.osgi.framework.*; public class TrackingMovieListerActivator implements BundleActivator { private MovieFinderTracker tracker; public void start(BundleContext context) { tracker = new MovieFinderTracker(context); tracker.open(); } public void stop(BundleContext context) { tracker.close(); } }
---------------------------------------------------------------------------------------------------------------
Manifest 파일TrackingMovieLister.mf
입니다.
TrackingMovieLister.mf
---------------------------------------------------------------------------------------------------------------
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Tracking Movie Lister
Bundle-SymbolicName: TrackingMovieLister
Bundle-Version: 1.0.0
Bundle-Activator: osgitut.movies.impl.TrackingMovieListerActivator
Import-Package: org.osgi.framework,
org.osgi.util.tracker,
osgitut.movies;version="[1.0.0,2.0.0)"
---------------------------------------------------------------------------------------------------------------
그 후에는 아래 단계들을 따라해서 모든것이 동작하는지를 살펴보세요.
BasicMovieFinder
를 실행하고TrackingMovieLister
를 실행합니다. “MovieLister: added a finder” 메시지가 나오는지 확인.services
명령을 입력해서MovieLister
가 등록되어 있는지 확인합니다.BasicMovieFinder
를 중단하고 “MovieLister: removed a finder” 메시지가 나오는지 확인.services
명령을 다시 입력해서MovieLister
서비스 등록이 해제 되었는지 확인.
여기서 한 작업은, 매우 강력한 기술의 토대를 다진거라고 볼수 있습니다. 우리는 한 개의 서비스의 라이프 사이클을 다른 서비스(실제로는 여러개의 다른 서비스)의 라이프 사이클에 연결하였습니다. 이 기술을 더 발전시키면, MovieLister
에 연결된 다른 서비스를 가질수도 있고, 또 거기에 의존하는 다른 서비스 등등.. 서로 의존하는 서비스들의 그래프를 만들었습니다. 하지만 다른 정적인 IOC 컨테이너에 의해 만들어진 bean들의 그래프와는 달리 우리의 그래프는 튼튼하며, 자가 치유능력이 있고, 변화하는 환경에 적응할 수 있습니다.
한편으로 작성한 코드에는 약간의 문제가 있습니다. MovieFinderTracker
와 TrackingMovieListerActivator
클래스는 반복사용 되는 문장들이 가득해서, 우리가 시스템을 확장하기 시작한다면 우리는 같은 코드를 매번 조금씩만 바꿔서 작성하게 되어 매우 피곤해 질것입니다.
2. Reference
§ “OSGi Service Platform Core Specification Release 4, Version 4.3”, The OSGi Alliance, Apr. 2011.
§ Song J.H., “Design and Implementation of Management Bundle for OSGi Framework”, Soongsil Univ., 2008.
§ 권정혁, “실전 OSGi & Spring DM”, 위키북스, 2009.
§ Guru`s Blog, http://xguru.net/
§ OSGi Alliance site, www.osgi.org
§ Open OSGi middleware project site, www.knopflerfish.org
'IT 놀이터 > Elite Member Tech & Talk' 카테고리의 다른 글
[2기 광주 박이근] 카메라 보정2 (0) | 2012.11.30 |
---|---|
[2기 강북 강정인] Aircrack-ng 소개 (0) | 2012.11.29 |
[2기 대전 김형순] 게이미피케이션과 자기동기부여 (0) | 2012.11.27 |
[2기 수원 이상웅] 페이스북 네트워크 분석 (0) | 2012.11.26 |
[2기 강북 강동하] 안드로이드 시스템 권한 앱 만들기 (5) | 2012.11.25 |