월별 글 목록: 2008년 5월월

OSGi 시작하기 5 – 서비스 사용하기 : [번역] Consuming a Service

이 글은 Neil Bartlett 의 연재 글 “Getting started with OSGi”의 번역본입니다.
* 파트 1 – 첫번째 번들 : Your First Bundle
* 파트 2 – 프레임워크와 연동하기 : Interacting with the Framework
* 파트 3 – 번들간의 의존관계 : Dependencies between bundles
* 파트 4 – 서비스 등록하기 : Registering a Service
에 이어 5번째 글입니다. 오탈자 및 이상한 번역은 댓글로 남겨주세요

Getting started with OSGi : OSGi 시작하기 파트 5 – 서비스 사용하기

저자 : Neil Bartlett < njbartlett at gmail dot com >
역자 : 권 정혁 < guruguru at gmail dot com >

글원본 : http://www.eclipsezone.com/eclipse/forums/t90796.html – Getting started with OSGi : Consuming a Service

마지막 글에서 우린 어떻게 서비스를 등록하는지에 대해 알아봤습니다. 이제 그 서비스를 찾고 다른 번들에서 그 서비스를 이용하도록 작업해 봅시다.

Martin Folwer의 Dependency Injection에 대한 글에서 영감을 얻었던 지난번처럼, 우린 문제를 우리 요구사항에 포함할 것입니니다. 우린 MovieFinder 를 서비스로 만들어서 서비스 레지스트리에 등록했습니다. 이젠 특정 감독에 의해 제작된 영화를 찾기위해 MovieFinder 를 사용하는 MovieLister를 만들어볼 것입니다. 그리고 이 MovieLister 자체도 GUI Application 같은 다른 특정번들에 사용되는 서비스가 될것이라고 가정합니다. 여기서 문제점은, OSGi 서비스는 동적이라 등록되고 사라지고 한다는것입니다. 즉, 우리가 MovieFinder 서비스를 호출하고자 할때, 서비스가 불가능할수도 있습니다.

그러면, 만약 MovieFinder 서비스가 존재하지 않는다면 MovieLister 는 무엇을 해야할까요 ? MovieLister 가 하는 일중에 MovieFinder 에 대한 호출이 매우 중요한 것이라는것은 확실하므로, 우리가 선택할수 있는 옵션은 몇가지 밖에 없습니다.

  1. 에러를 낸다. (Null 을 리턴하거나 Exception 을 내거나)
  2. 기다린다.
  3. 처음부터 아예 설치가 안되도록 한다. ( Don’t be there in the first place )

이 글에선 쉬운 앞에 2가지 방법만을 살펴보도록 합니다. 세번째 방법은 아직 여러분께 어떤 의미가 있게 보이진 않겠지만, 앞에 2가지를 보고나면 알수 있게 되실겁니다.

첫번째로 할일은 MovieLister 서비스에 대한 인터페이스를 작성하는것입니다. 아래 소스를 osgitut/movies/MovieLister.java 에 복사하세요.

package osgitut.movies;
import java.util.List;
public interface MovieLister {
    List listByDirector(String name);
}

이제 osgitut/movies/impl/MovieListerImpl.java 파일을 생성합니다.

package osgitut.movies.impl;
import java.util.*;
import osgitut.movies.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
public class MovieListerImpl implements MovieLister {
    private final ServiceTracker finderTrack;
    public MovieListerImpl(ServiceTracker finderTrack) {
        this.finderTrack = finderTrack;
    }
    public List listByDirector(String name) {
        MovieFinder finder = (MovieFinder) finderTrack.getService();
        if(finder == null) {
            return null;
        } else {
            return doSearch(name, finder);
        }
    }
    private List doSearch(String name, MovieFinder finder) {
        Movie[] movies = finder.findAll();
        List result = new LinkedList();
        for (int i = 0; i < movies.length; i++) {
            if(movies[i].getDirector().indexOf(name) > -1) {
                result.add(movies[i]);
            }
        }
        return result;
    }
}

이것이 아마 지금까지 샘플중 가장 긴 코드일겁니다! 그럼, 여기선 무슨일이 일어나고 있을까요 ? 첫번째로 실제 영화를 찾는 로직이 doSearch(String,MovieFinder) 메소드로 분리되어, OSGi 에 관련된 코드를 독립시키도록 도와주고 있습니다. 불가피 하게도, 우리가 검색을 하는 방법이 멍청하고 비효율적이지만, 그건 이 튜토리얼에는 크게 종요하지 않습니다. 어차피 우리 데이터베이스에는 딱! 2개의 영화만 있으니까요.

흥미로운건 서비스 레지스트리로부터 MovieFinder 를 찾기위해 ServiceTracker를 사용하는 listByDirector(String name) 메소드 입니다. ServiceTracker 는 OSGi API 의 재미없는 하위레벨 코드를 추상화시켜주는 매우 유용한 클래스입니다. 어쨋거나, 우린 정말 서비스가 존재하는지 체크할 필요가 있습니다. ServiceTracker 는 생성자로 전달되었다고 가정합니다.

여러분께선 아마도 ServiceTracker 를 사용하지 않고 레지스트리에서 서비스를 가져오는 코드를 보셨을수도 있습니다. 예를 들어 BundleContextgetServiceReferecegetService 를 호출하는것이 가능합니다. 하지만 이런 코드는 꽤 복잡하고 사용후 잘 지우도록 조심해야 합니다. 제 의견으론, 로우레벨 API를 사용하는 것의 이점은 매우 작고 많은 문제가 있습니다. ServiceTracker 를 항상 사용하는것이 좋습니다.

ServiceTracker 를 생성하기에 좋은곳은 bundle activator 입니다. 아래 코드를 osgitut/movies/impl/MovieListerActivator.java 에 복사하세요.

package osgitut.movies.impl;
import java.util.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
import osgitut.movies.*;
public class MovieListerActivator implements BundleActivator {
    private ServiceTracker finderTracker;
    private ServiceRegistration listerReg;
    public void start(BundleContext context) throws Exception {
        // Create and open the MovieFinder ServiceTracker
        finderTracker = new ServiceTracker(context, MovieFinder.class.getName(), null);
        finderTracker.open();
        // Create the MovieLister and register as a service
        MovieLister lister = new MovieListerImpl(finderTracker);
        listerReg = context.registerService(MovieLister.class.getName(), lister, null);
        // Execute the sample search
        doSampleSearch(lister);
    }
    public void stop(BundleContext context) throws Exception {
        // Unregister the MovieLister service
        listerReg.unregister();
        // Close the MovieFinder ServiceTracker
        finderTracker.close();
    }
    private void doSampleSearch(MovieLister lister) {
        List movies = lister.listByDirector("Miyazaki");
        if(movies == null) {
            System.err.println("Could not retrieve movie list");
        } else {
            for (Iterator it = movies.iterator(); it.hasNext();) {
                Movie movie = (Movie) it.next();
                System.out.println("Title: " + movie.getTitle());
            }
        }
    }
}

이제 Activator 가 재미있어 보이기 시작합니다. 처음에 start 메소드에서 MovieLister 가 사용할 ServiceTracker 개체를 생성합니다. 그리고는 ServiceTracker 를 “엽니다”. 이건 MovieFinder 서비스의 Instance를 레지스트리에서 추적하는걸 시작하라는 것이죠. 그리고는 MovieLister 인터페이스 이름으로 서비스 레지스트리에 MovieListerImpl 개체를 생성하고 등록합니다. 마지막으로, 우리가 번들을 시작했을때 뭔가 재미있는것이 보일수 있도록, MovieLister 를 이용하여 간단한 검색을 실행하고 결과를 출력합니다.

이제 이 번들을 만들고 설치해야 합니다. 자세한 설명은 하지 않도록 하겠습니다. 이전 회를 참고하면 충분히 하실수 있을겁니다. Manifest 파일을 만들고, Bundle-Activatorosgitut.movies.impl.MovieListerActivator 를 지정해야 하는걸 기억해 두세요. 또한 Import-Package 에는 우리가 다른 번들에서 임포팅하는 3개의 패키지 ( org.osgi.framework , org.osgi.util.tracker 그리고 osgitut.movies ) 를 적어주어야 합니다.

MovieLister.jar 를 Equinox 런타임안에 설치했다면, 시작할 수 있습니다. 지난번에 만든 BasicMovieFinder 번들이 동작하고 있는지에 따라 다음 2개의 메시지중 하나를 볼수 있습니다. 만약 동작중이 아니라면,

osgi> start 2
Could not retrieve movie list

아직 동작중이라면

osgi> start 2
Title: Spirited Away

각 번들을 중지시키고 시작시켜보면, 두개의 메시지를 원하는 대로 보실수 있습니다. 이것이 이번 연재의 거의 다입니다만, 제가 서비스가 사용 불가능할때(not available) 할수 있는 일중에 기다리는 방법이 있다고 한거 기억하시나요 ? 우리가 가지고 있는 코드만 있으면 이건 간단합니다. MovieListerImpl 의 16번째 라인을 getService() 메소드 대신 ServiceTrackerwaitForService(5000)으로 변경하시고, InterruptedException 에 대한 try/catch 블록을 추가하세요.

이것은 listByDirector() 메소드가 5000 밀리세컨드동안 MovieFinder 서비스가 나타날때까지 기다리도록 할것입니다. 만약 MovieFinder 서비스가 그 시간내에 설치된다면 (물론 이미 있을때에도) 우린 바로 서비스를 가져와서 사용이 가능할 것입니다.

일반적인 경우에 저는 이런식으로 중지하고 있는 쓰레드를 사용하라고 권고하지만, 이 경우엔 listByDirecor() 메소드가 프레임워크 쓰레드로 부터 호출되는 Bundle activator 의 start 메소드 에서 호출이 되었기 때문에 위험할수 있습니다. 번들이 활성화 될때 여러 일들이 일어나야할 필요가 있기때문에 Activator 들은 빨리 리턴해야 합니다. 최악의 경우에는 우리가 다른것에 의해 이미 lock 되었을지도 모르는 프레임워크 소유개체의 synchronized 블록에 들어갔으므로 deadlock 이 발생할 수도 있습니다. 기본 가이드라인은, 프레임워크에 의해 호출되는 모든코드 또는 번들의 activator 에 있는 start 메소드에서는 시간이 오래 걸리는 작업이나 블록킹 오퍼레이션을 하지 말라는 것입니다.

다음 회에선 의존개체가 없을 경우의 신비한 3번째 옵션 “Don’t exist in the first place” 에 대해 알아보겠습니다. 기대해 주세요!

OSGi 시작하기 4 – 서비스 등록하기 : [번역] Registering a Service

이 글은 Neil Bartlett 의 연재 글 “Getting started with OSGi”의 번역본입니다.
* 파트 1 – 첫번째 번들 : Your First Bundle
* 파트 2 – 프레임워크와 연동하기 : Interacting with the Framework
* 파트 3 – 번들간의 의존관계 : Dependencies between bundles
에 이어 4번째 글입니다. 오탈자 및 이상한 번역은 댓글로 남겨주세요

Getting started with OSGi : OSGi 시작하기 파트 4 – 서비스 등록하기

저자 : Neil Bartlett < njbartlett at gmail dot com >
역자 : 권 정혁 < guruguru at gmail dot com >

글원본 : http://www.eclipsezone.com/eclipse/forums/t90688.html – Getting started with OSGi : Registering a Service

EclipseZone OSGi 미니시리즈에 돌아오신걸 환영합니다. 드디어 서비스에 대해 알아볼 준비가 되었습니다. 제 생각에 서비스 레이어는 OSGi 의 가장 재미있는 부분입니다. 그러니 다음 몇회는 아주 재미 있을겁니다.

지난시간에 우린 MovieLister 에 의해 영화를 찾기 위해 사용 되는 MovieFinder 인터페이스 예제에 대해 살펴보았습니다. 실은 아마 여러분도 이 예제를 알고 계셨을겁니다. 이건 Martin Fowler의 유명한 글 인 “Dependency Injection” (또는 “Inversion of Control” / IoC 라고 알려진 )에 나오는 예제입니다.

IoC 가 풀려고 했던 문제를 다시 살펴봅시다. MovieLister 는 어디서 Movie 에 대한 정보들이 오던지 상관하지 않으므로, 우리는 MovieFinder 인터페이스를 이용하여 그런 세부사항들을 숨겼습니다. MovieLister 가 특정 구현이 아닌 인터페이스에만 의존하고 있기 때문에, 우린 MovieFinder 구현을 데이타베이스 에서 읽어오거나 심지어는 Amazon Web Service 를 호출하는것으로 교체할수 있다는 것입니다.

지금까지는 좋습니다. 하지만 특정부분에서는 우리는 MovieLister 에게 MovieFinder 의 구현을 넘겨주어야만 합니다. 이를 위해 MovieLister 가 lookup하는 메소드를 호출하기 보다는 외부 컨테이너를 하나 두어서 적절한 개체를 MovieLister 에게 넣어주는(push) 방법으로 처리합니다. 이것이 우리가 “Inversion of Control” 이라고 부르는 것이죠. PicoContainer, HiveMind, Spring 그리고 EJB 3.0 처럼 수많은 컨테이너들이 개발되었습니다. 그러나 이런 컨테이너들에겐 아직도 하나의 제한이 있습니다. 거의 static 이라는 것이죠. 한번 MovieLister 에게 MovieFinder 가 주어진다면, JVM 의 생명주기동안 연결된채로 남아있는 경향이 있습니다.

하지만 OSGi 는 우리에게 동적인 방식으로 IoC 패턴을 구현하도록 해줍니다. MovieLister 에게 동적으로 MovieFinder 의 구현을 제공할수 있고, 후에 제거할수도 있습니다. 따라서 우린 평범한 텍스트파일에서 영화를 찾는 어플리케이션에서 Amazon Web Service 를 통해 영화를 찾는 Application 으로 실행중 교체(Hot-swap)가 가능합니다.

Service 계층이 우리가 이런 일을 할수있도록 도와줍니다. 간단히 말해 MovieFinder 를 Service Registry 에 서비스로 등록합니다. 후에 MovieFinder 서비스는 MovieLister 에게 제공될수 있습니다. 서비스는 그냥 자바 개체(POJO : Plain Old Java Object)와 특별히 다를게 없으며 Java Interface 이름으로 등록됩니다. ( POJI 라고 해야되나요 ? )

이번 회에서는 레지스트리에 서비스를 등록해 볼것입니다. 차후에 레지스트리에서 서비스를 가져오고 어떻게 이것이 어떻게 MovieLister 에게 제공되는지를 살펴보겠습니다.

지난번에 만들었던 BasicMovieFinder 번들을 추가할것입니다. 기존 클래스를 수정할 필요는 없고, 단지 번들 Activator 만 추가하면 됩니다. 아래 내용을 osgitut/movies/impl/BasicMovieFinderActivator.java 파일에 복사하세요.

package osgitut.movies.impl;
import org.osgi.framework.*;
import osgitut.movies.*;
import java.util.Properties;
import java.util.Dictionary;
public class BasicMovieFinderActivator implements BundleActivator {
    private ServiceRegistration registration;
    public void start(BundleContext context) {
        MovieFinder finder = new BasicMovieFinderImpl();
        Dictionary props = new Properties();
        props.put("category", "misc");
        registration = context.registerService(
                               MovieFinder.class.getName(),
                               finder, props);
    }
    public void stop(BundleContext context) {
        registration.unregister();
    }
}

자 이제 BasicMovieFinder.mf 파일의 내용을 아래로 교체하세요.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Basic Movie Finder
Bundle-SymbolicName: BasicMovieFinder
Bundle-Version: 1.0.0
Bundle-Activator: osgitut.movies.impl.BasicMovieFinderActivator
Import-Package: org.osgi.framework,
 osgitut.movies;version="[1.0.0,2.0.0)"

지난 번에 비해 두가지가 Manifest 에 추가되었습니다. 프레임워크에게 Activator 를 알려주는 Bundle-Activator 부분 ( 지난번엔 이부분은 필요없었죠 ). 그리고 Import-Packageorg.osgi.framework 를 추가했습니다. 지난번 번들에선 프레임워크와 연동할 일이 없었으므로, OSGi API 패키지가 필요없었기 때문입니다.

자 이제 BasicMovieFinder.jar 를 다시 만들수 있습니다.

> javac -classpath equinox.jar;MoviesInterface.jar osgitut/movies/impl/*.java
> jar cfm BasicMovieFinder.jar BasicMovieFinder.mf osgitut/movies/impl/*.class

OSGi 콘솔로 돌아가면, 아마 아직 지난번의 BasicMovieFinder.jar 가 설치되어 있을것입니다. 그럼 OSGi 에게 번들을 업데이트 할수 있도록 update N 을 입력해보세요. N 은 ss 를 입력했을때 보이는 번들의 ID 번호입니다. 자 이제 start N 을 입력해서 번들을 시작해 보세요. 그런데.. 별로 일어난 일이 없습니다.

실제로 우린 우리의 첫번째 서비스를 OSGi 서비스 레지스트리에 등록했습니다만, 불행하게도 아직 이 서비스의 사용자가 없으므로 등록작업이 눈에 보이는 효과를 가져오지 못합니다. 우리의 코드가 정말로 무엇을 했는지 확인하려면 좀더 깊게 들어가야 하므로 아래의 명령을 입력해 봅니다.

services (objectClass=*MovieFinder)

그럼 아래와 같은 출력을 볼수 있습니다.

{osgitut.movies.MovieFinder}={category=misc, service.id=22}
  Registered by bundle: file:BasicMovieFinder.jar [4]
  No bundles using service.

멋집니다. 우리의 서비스가 등록되어 있네요. 이제 어떻게 서비스를 찾고 다른 번들에서 사용하는지를 말해드리고 싶지만, 다음날까지 기다려야 할 듯 합니다. 그동안 services 명령을 가지고 무엇을 할수 있는지 시도해 보세요. 입문자 분들께서는 services 뒤의 괄호안의 문자열을 빼고 입력해 보세요. 그 문자열은 우리가 관심있는 서비스들만 볼 수 있도록 출력될 서비스의 숫자를 줄여주는 필터 입니다. 필터가 없다면 등록된 모든 서비스들을 보실수 있습니다. 놀라울 정도로 많은 서비스가 있을겁니다!

OSGi 시작하기 3 – 번들간의 의존관계 : [번역] Dependencies between bundles

이 글은 Neil Bartlett 의 연재 글 “Getting started with OSGi”의 번역본입니다.
* 파트 1 – 첫번째 번들 : Your First Bundle
* 파트 2 – 프레임워크와 연동하기 : Interacting with the Framework
에 이어 3번째 글입니다. 오탈자 및 이상한 번역은 댓글로 남겨주세요

Getting started with OSGi : OSGi 시작하기 파트 3 – 번들간의 의존관계

저자 : Neil Bartlett < njbartlett at gmail dot com >
역자 : 권 정혁 < guruguru at gmail dot com >

글원본 : http://www.eclipsezone.com/eclipse/forums/t90544.html – Getting started with OSGi : Dependencies between bundles

지난회까지의 튜토리얼에서는, 어떻게 번들이 시작되고 중단되는지, 어떻게 프레임워크와 연결되고 다른 번들의 라이프 사이클에 연결되는지를 알아보았습니다. 그런데 정말 번들은 뭘 위한걸까요 ?

번들(Bundles)은 모듈(Modules)입니다. 번들은 우리의 단일 프로젝트를 관리가 가능한 조각들로 분리하여 OSGi 런타임 안으로 각각 로드될수 있도록 해줍니다. 문제는 우리가 원하든 원하지 않든간에, 모듈들이 다른 모듈에 의존관계(Dependency)를 가지고 있다는 겁니다. 평범한 Jar 파일에서는 다른 Jar 파일들에 대해 신뢰할수 있게 의존관계를 명시하는 일이 불가능했습니다. ( Manifest 에 있는 Class-Path 항목은 신뢰할 만한 방법이 아닙니다. ) 그래서 Jar 파일안에 있는 코드가 정말로 동작할지 아니면 런타임시에 ClassNotFoundException 을 낼지는 알 수 없습니다.

OSGi 는 이 문제를 매우 우아한 방법으로 해결했습니다. 말로 하는것보다 보여주는 방법이 좋을듯 하니, 코드로 가보도록 합시다. 불행하게도 우린 지금까지 기본 패키지를 이용해 왔지만, 이는 더이상 동작하지 않습니다. 우린 적절한 패키지가 필요하게 될 것입니다. 그럼 아주 간단한 JavaBean 스타일의 클래스로 시작해 봅시다. osgitut/movies/Movie.java 파일을 만들고 아래 코드를 복사하세요.

package osgitut.movies;
public class Movie {
    private final String title;
    private final String director;
    public Movie(String title, String director) {
        this.title = title; this.director = director;
    }
    public String getTitle() { return title; }
    public String getDirector() { return director; }
}

이제 같은 패키지 안에 인터페이스를 만들겁니다. osgitut/movies/MovieFinder.java 파일을 만들고 아래코드를 복사하세요.

package osgitut.movies;
public interface MovieFinder {
    Movie[] findAll();
}

이제 이 두개의 클래스들을 번들안에 집어 넣습니다. 우리의 번들은 터무니없을 정도로 작고, 거의 쓸모가 없지만 지금은 문제없습니다. 전과 같이 Manifest 파일을 만들어야 하므로, MoviesInterface.mf 를 만들고 아래를 복사하세요.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Movies Interface
Bundle-SymbolicName: MoviesInterface
Bundle-Version: 1.0.0
Export-Package: osgitut.movies;version="1.0.0"

이전에는 보지 못했던 Export-Package 라는 새로운 줄이 있습니다. 이는 번들에서 osgitut.movies 패키지가 export 되었다는것을 의미합니다. 예전 Java jar 파일에서는 모든것이 export 되었으므로, 처음에는 좀 이상하게 보일수 있습니다. 하지만, 혹시 당신의 Jar 파일안에 내부적으로만 볼수 있는 코드를 패키지에 추가하는 것을 원해본적 없으신가요 ? 물론 클래스는 private 나 proctected 로 만들 수 있겠지만, 그러면 당신의 Jar 파일에 있는 다른 Package 에서도 못 보게 됩니다. 그래서 OSGi는 효율적인 새로운 코드 보안 레벨을 소개했습니다. 만약 번들안에 있는 패키지가 Export-Package 헤더에 포함되지 않는다면, 그 패키지는 오직 당신 모듈안에서만 접근이 가능합니다.

또 한 우리가 패키지에 버전 번호를 붙힌것을 볼수 있습니다. 이것은 중요한것이며 차후에 살펴볼 것입니다. 꼭 버전번호를 제공할 필요는 없습니다. 하지만 제공하지 않으면 OSGi 는 자동적으로 버전 “0.0.0”을 당신의 패키지에 할당하게 됩니다. 제 생각에 항상 버전을 명시하는것이 좋은 습관이라고 생각됩니다.

자 이제 이 번들을 빌드해 봅시다.

> javac osgitut/movies/Movie.java osgitut/movies/MovieFinder.java
> jar -cfm MoviesInterface.jar MoviesInterface.mf osgitut/movies/*.class

바로 번들을 런타임에 설치하진 않을것입니다. 먼저 이 번들에 의존하는 다른 번들을 만들 예정입니다. MovieFinder 인터페이스의 구현부를 작성할 것이므로 , 아래를 osgitut/movies/impl/BasicMovieFinderImpl.java 에 복사합니다.

package osgitut.movies.impl;
import osgitut.movies.*;
public class BasicMovieFinderImpl implements MovieFinder {
  private static final Movie[] MOVIES = new Movie[] {
    new Movie("The Godfather", "Francis Ford Coppola"),
    new Movie("Spirited Away", "Hayao Miyazaki")
  };
  public Movie[] findAll() { return MOVIES; }
}

매니페스트 파일 BasicMovieFinder.mf 를 아래와 같이 만듭니다.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Basic Movie Finder
Bundle-SymbolicName: BasicMovieFinder
Bundle-Version: 1.0.0
Import-Package: osgitut.movies;version="[1.0.0,2.0.0)"

다른 번들에 의해 Export 되었던 osgitut.movies 번들을 import 하고 잇다는것을 주목하세요. 또한 이번엔 import 할때 버전의 범위를 추가했습니다. 프레임워크는 import 에 맞는 적절한 export 를 찾을때 이 범위를 사용합니다. OSGi 는 일반적인 수학에서 사용하는 범위형태의 문법을 사용합니다. “[” 는 포함한다는 것을 의미하며, “)”는 포함하지 않는다는 것을 의미합니다. 이에 의해 우리는 버전 “1.x” 대를 효과적으로 선택했습니다.

다시 한번 말씀드리지만, 이 경우에 버전번호 제약을 import 에 추가하는것은 꼭 필요하진 않습니다. 그냥 익숙해지면 좋을 습관일 뿐입니다.

자 이제 2번째 번들을 컴파일하고 번들로 만들어 봅니다.

> javac -classpath MoviesInterface.jar osgitut/movies/impl/BasicMovieFinderImpl.java
> jar -cfm BasicMovieFinder.jar BasicMovieFinder.mf osgitut/movies/impl/*.class

이제, 이 번들들을 Equinox 에서 시도해볼때가 되었습니다. 이제 익숙해 지셨을테니, 이번엔 상세한 설명은 하지 않겠습니다. 먼저 BasicMovieFinder 번들을 설치한후, ss 를 입력해 보세요. 번들이 INSTALLED 상태에 있다는것을 보실수 있습니다.

id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.3.0.v20070208
4       INSTALLED   BasicMovieFinder_1.0.0

(NB 여러분의 번들 리스트는 제것과 약간 다르게 보일수 있습니다. 번들의 ID 는 당신이 얼마나 HelloWorld 번들을 설치/삭제 해보았는지에 따라 다를수 있씁니다. 번들ID 를 당신의 것으로 바꿔서 보도록 하세요.).

INSTALLED 는 프레임워크가 이제 막 번들을 설치했다는것을 의미하며, 아직 번들의 의존관계를 해결하지 못햇다는 것(not resolved)입니다.Equinox 에게 우리 번들에게 의존관계를 해결하도록 하는 하나의 방법은 refresh 명령입니다. refresh 4 를 입력하고 다시 ss 를 입력해 보세요.

id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.3.0.v20070208
4       INSTALLED   BasicMovieFinder_1.0.0

여전히 번들이 resolve 되지 않았습니다. 당연히, 우린 Movie 클래스와 MovieFinder 인터페이스를 가지고 있는 번들을 설치해야만 합니다. 이것이 정말 문제인지를 확인하기 위해 diag 4 를 입력해서, 진단 정보를 불러봅니다.

file:BasicMovieFinder.jar [4]
  Missing imported package osgitut.movies_[1.0.0,2.0.0).

네, 그게 문제였네요. 어떤 번들도 osgitut.movies 패키지를 export 하고 있지 않기 때문에 import 가 불가능합니다. 그럼 이제 MovieInterface.jar를 설치하고 ss 를 입력해 보세요. 리스트는 아래와 같을겁니다.

id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.3.0.v20070208
4       INSTALLED   BasicMovieFinder_1.0.0
5       INSTALLED   MoviesInterface_1.0.0

마지막 단계는 Equinox 에게 다시 BasicMovieFinder 번들에게 resolve 를 시도하도록 refresh 4 를 입력해 보는것입니다. ss 의 출력은 이제 아래와 같습니다.

id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.3.0.v20070208
4       RESOLVED    BasicMovieFinder_1.0.0
5       RESOLVED    MoviesInterface_1.0.0

BasicMovieFinder 이 이제 RESOLVED 가 되었습니다. 이것은 필수단계로서, 번들이 RESOLVED 상태가 되지 않으면 시작이 불가능하며, 또한 다른 번들들에게 Dependency 를 제공하지도 못합니다.

참고로, 보통은 이런 방법의 수작업은 필요치 않습니다. 일반적으로 번들은 그들이 필요로 할때 자동적으로 resolve 됩니다. 예를 들어 우리가 refresh 를 호출하지 않았어도 MoviesInteface 번들이 RESOLVED 상태가 된것을 보세요.

여기까지 입니다. Equinox 콘솔과 해볼수 있는 더 많은 재미난 것들을 위해서는 IBM developerWorks에 있는 Chris Aniszczyk 의 훌륭한 기사 를 참고하세요. 다음회에서는 OSGi 서비스에 대해 알아보겠습니다. 기대해 주세요.

OSGi 시작하기 2 – 프레임워크와 연동하기 : [번역] Interacting with the Framework

이 글은 Neil Bartlett 의 연재 글 “Getting started with OSGi”의 번역본입니다.
* 파트 1 – 첫번째 번들 : Your First Bundle
에 이어 2번째 글입니다. 오탈자 및 이상한 번역은 댓글로 남겨주세요

Getting started with OSGi : OSGi 시작하기 파트 2 – 프레임워크와 연동하기

저자 : Neil Bartlett < njbartlett at gmail dot com >
역자 : 권 정혁 < guruguru at gmail dot com >

글원본 : http://www.eclipsezone.com/eclipse/forums/t90448.html – Getting started with OSGi : Interacting with the Framework

EclipseZone OSGi 튜토리얼에 돌아오신걸 환영합니다.

지난 시간에는 시작과 종료시에 메시지를 출력하는 Hello World 번들을 살펴보았는데요. 이것은 BundleActivator 인터페이스를 구현하여 start 와 stop 메소드를 제공함으로서 가능했습니다. 코드를 다른부분을 살펴보면, startstop 메소드의 서명(Method Signature , 역주:메소드의 이름,인자,리턴타입등을 총칭)에서 우리가 BundleContext 라는 인자를 받았다는 것을 알수 있습니다. 이 장의 튜토리얼에서 우린 BundleContext 에 대해 알아보고 이 것으로 무엇을 할수 있는지 살펴볼 것 입니다.

BundleContext 는 OSGi 프레임워크가 우리에게 보내주는 매직티켓 입니다. 코드상에서 프레임워크와 연관된 작업을 해야할 필요가 있을 때 BundleContext 를 사용하게 될것입니다. 실제로 이것은 OSGi API 와 연결하기 위한 단 하나의 방법이며 프레임워크는 번들이 시작될때 BundleActivator 를 통해 각 번들에게 이 티켓중의 하나를 발권하게 됩니다.

지난번에 시작한 Equinox 가 아직 실행중이라면 재시작 할 필요는 없습니다. 실행중이 아니라면, 다시 시작하기 위한 커맨드는

> java -jar equinox.jar -console

입니다. ss 를 입력해서 지난번에 설치한 HelloWorld 번들이 아직 설치되어 있는지 확인해 볼 수 있습니다. 당신이 Equinox 를 종료하고 재 시작했더라도 그것을 볼수 있는데, 왜냐하면 OSGi 프레임워크가 각각의 실행간에 실행 상태를 저장하기 때문입니다.

이번 연습을 위해, 우리는 Hello World 번들을 찾아내고 Uninstall(제거) 하는 번들을 작성해 볼것입니다. 물론 콘솔창에서 uninstall 명령을 내림으로 간단히 해볼수 있지만, 어떻게 OSGi API 를 통해 프로그램적으로 실행가능한지를 알아보기 위해서입니다. 그럼 HelloWorldKiller.java 라는 파일을 만들고 아래의 코드를 복사합니다.

import org.osgi.framework.*;
 
public class HelloWorldKiller implements BundleActivator {
    public void start(BundleContext context) {
        System.out.println("HelloWorldKiller searching...");
        Bundle[] bundles = context.getBundles();
        for(int i=0; i < bundles.length; i++) {
            if("HelloWorld".equals(bundles[i]
                                   .getSymbolicName())) {
                try {
                    System.out.println("Hello World found, "
                                     + "destroying!");
                    bundles[i].uninstall();
                    return;
                } catch (BundleException e) {
                    System.err.println("Failed: "
                                     + e.getMessage());
                }
            }
        }
        System.out.println("Hello World bundle not found");
    }
 
    public void stop(BundleContext context) {
        System.out.println("HelloWorldKiller shutting down");
    }
}

이제 Manifest 를 작성합니다. 마지막줄에 빈줄이 있어야 하는것은 역시 매우 중요합니다. 아래 내용을 HelloWorldKiller.mf 에 복사하세요.

Manifest-Version: 1.0
Bundle-Name: HelloWorldKiller
Bundle-Activator: HelloWorldKiller
Bundle-SymbolicName: HelloWorldKiller
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework

자 이젠 컴파일 하고 Jar 파일을 만듭니다.


> javac -classpath equinox.jar HelloWorldKiller.java
> jar -cfm HelloWorldKiller.jar HelloWorldKiller.mf HelloWorldKiller.class

다시 OSGi 콘솔에서 install file:HelloWorldKiller.jar 를 입력해서 새 번들을 설치하고 ss 를 입력해 봅니다. 상태 리스트는 이제 아래와 같을 것입니다.

id      State       Bundle
0       ACTIVE      system.bundle_3.2.1.R32x_v20060919
1       ACTIVE      HelloWorld_1.0.0
2       INSTALLED   HelloWorldKiller_1.0.0

자 이제 start 2 를 입력해서 Hello World Killer 를 실행하여 봅시다. 아래와 같은 출력을 보실수 있습니다.

HelloWorldKiller searching...
Hello World found, destroying!
Goodbye EclipseZone Readers!

마지막 출력라인은 원본 Hello World 번들에서 나왔다는것을 주목하세요. 우리가 Killer 를 실행하기 전에 그 번들이 active 상태였기 때문에 제거되기 전에 중단 되어야만 했기에 BundleActivator 에게 stop 이 실행 되도록 만들었습니다.

ss 의 출력을 보도록 합시다. Hello World 가 이제 사라졌습니다.

id      State       Bundle
0       ACTIVE      system.bundle_3.2.1.R32x_v20060919
2       ACTIVE      HelloWorldKiller_1.0.0

여기에 보안 문제가 있지 않은가 궁금해 하실수 있습니다. 어떤 번들이라도 다른 어떤 번들을 제거할수 있는것 처럼 보이니까요! 다행스럽게도 OSGi 는 프레임워크와의 모든 연계작업들을 세밀하게 조종할수 있는 종합적인 보안계층을 가지고 있습니다. 예를 들어 특정 “관리” 번들에 의해서만 번들이 제거될수 있도록 할수도 있습니다. 어쨋거나, 보안이 동작하도록 하는것은 대부분 설정(Configuration)상의 문제이니 이 연재에서는 우리는 코드에만 집중하기로 합니다.

이번회는 여기까지 입니다. 다음시간까지 BundleContext 의 인터페이스를 살펴보고 무엇을 할수 있는지 알아보는건 어떨까요 ? 예를 들어 installBundle 메소드를 이용하여 프로그램적으로 새 번들을 설치하는 것을 시도해 볼 수도 있습니다. 또는 현재 설치된 번들들에 대한 리스트를 가져와서 마지막으로 수정된 날짜와 시간을 출력하도록 할 수도 있구요. 시작하는데 도움이 필요하다면 OSGi Release 4 API 에 대한 JavaDoc 을 참고하세요