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 시작하기 4 – 서비스 등록하기 : [번역] Registering a Service”에 대한 20개의 생각

  1. 오류문의드려요

    javac -classpath equinox.jar:MoviesInterface.jar osgitut/movies/impl/*.java 입력시에

    osgitut/movies/impl/BasicMovieFinderActivator.java:3: package org.osgi.framework does not exist
    import org.osgi.framework.*;
    ^
    osgitut/movies/impl/BasicMovieFinderActivator.java:10: cannot find symbol
    symbol: class BundleActivator
    public class BasicMovieFinderActivator implements BundleActivator {
    ^
    osgitut/movies/impl/BasicMovieFinderActivator.java:11: cannot find symbol
    symbol : class ServiceRegistration
    location: class osgitut.movies.impl.BasicMovieFinderActivator
    private ServiceRegistration registration;
    ^
    osgitut/movies/impl/BasicMovieFinderActivator.java:13: cannot find symbol
    symbol : class BundleContext
    location: class osgitut.movies.impl.BasicMovieFinderActivator
    public void start(BundleContext context) {
    ^
    osgitut/movies/impl/BasicMovieFinderActivator.java:26: cannot find symbol
    symbol : class BundleContext
    location: class osgitut.movies.impl.BasicMovieFinderActivator
    public void stop(BundleContext context) {
    ^
    osgitut/movies/impl/BasicMovieFinderImpl.java:5: cannot find symbol
    symbol: class MovieFinder
    public class BasicMovieFinderImpl implements MovieFinder {
    ^
    osgitut/movies/impl/BasicMovieFinderImpl.java:6: cannot find symbol
    symbol : class Movie
    location: class osgitut.movies.impl.BasicMovieFinderImpl
    private static final Movie[] MOVIES = new Movie[] {
    ^
    osgitut/movies/impl/BasicMovieFinderImpl.java:10: cannot find symbol
    symbol : class Movie
    location: class osgitut.movies.impl.BasicMovieFinderImpl
    public Movie[] findAll() { return MOVIES; }
    ^
    osgitut/movies/impl/BasicMovieFinderActivator.java:15: cannot find symbol
    symbol : class MovieFinder
    location: class osgitut.movies.impl.BasicMovieFinderActivator
    MovieFinder finder = new BasicMovieFinderImpl();
    ^
    osgitut/movies/impl/BasicMovieFinderActivator.java:21: cannot find symbol
    symbol : class MovieFinder
    location: class osgitut.movies.impl.BasicMovieFinderActivator
    MovieFinder.class.getName(),
    ^
    osgitut/movies/impl/BasicMovieFinderImpl.java:6: cannot find symbol
    symbol : class Movie
    location: class osgitut.movies.impl.BasicMovieFinderImpl
    private static final Movie[] MOVIES = new Movie[] {
    ^
    osgitut/movies/impl/BasicMovieFinderImpl.java:7: cannot find symbol
    symbol : class Movie
    location: class osgitut.movies.impl.BasicMovieFinderImpl
    new Movie(“The Godfather”, “Francis Ford Coppola”),
    ^
    osgitut/movies/impl/BasicMovieFinderImpl.java:8: cannot find symbol
    symbol : class Movie
    location: class osgitut.movies.impl.BasicMovieFinderImpl
    new Movie(“Spirited Away”, “Hayao Miyazaki”)
    ^
    Note: osgitut/movies/impl/BasicMovieFinderActivator.java uses unchecked or unsafe operations.
    Note: Recompile with -Xlint:unchecked for details.
    13 errors

    이렇게 뜹니다..머가 잘못된건지요….

    응답
    1. 구루

      package org.osgi.framework does not exist 맨 앞부분에 이 에러가 나는것은 컴파일할때 classpath 에서 osgi 프레임워크를 못 찾는 다는 말입니다.

      응답
    2. 구루

      아 죄송합니다. 컴파일 문 인
      javac -classpath equinox.jar:MoviesInterface.jar osgitut/movies/impl/*.java
      에 오타가 있었네요
      javac -classpath equinox.jar;MoviesInterface.jar osgitut/movies/impl/*.java
      로 하셔야 합니다. 중간에 세미콜론대신 콜론이 들어갔습니다.

      응답
  2. 오류문의

    저도 위의 댓글 다신 분처럼 에러나요 ㅠㅠ 에러 첫줄에 package org.osgi.framework 이거 임포트 시킨적 없지 않나요??

    전에 1장 2장 3장에서 저런 경로로 디렉토리 만든적 없는데..저부분 코드가 이상하네요..

    응답
  3. 오류문의

    아,,혼자 어제 하나하나 코드 보며 찾다가 고쳤어요 ㅋㅋㅋㅋ

    여기를 좀더 일찍 와볼껄 ㅋㅋㅋ 감사해요 ㅋ

    응답
  4. 힘들어

    compile 시 osgitut/movies/impl/BasicMovieFinderActivator.java uses unchecked or unsafe operation. 이라 나오며
    Recompile with -Xlint로 하라고..
    그래서 컴파일을 -Xlint 붙여서 하니
    props.put(“category”, “misc”)부분에서 warning이 납니다. java.util.Dictionary의raw type이어야 한다고. 어찌해야 할지…

    응답
  5. 힘들어

    답변 감사합니다
    compile은 됩니다. 근데 start를 시키면 ogsitut.movies를 import못 시킨다고 나옵니다. 즉 위에 거랑은 상관이 없는 것 같더군요. 그래서 3장 부터 다시 해보는데 3장에서도 똑같이 import를 못시키더군요. 그래서 찬찬히 다시 해보려구요.
    근게 bundle번호를 다시 처음부터(1)부터 시작하는 명령은 없나요? 기록을 어디 가지고 있는지. shutdown하고 init하고 다 해도 점점 증가가 되네요

    응답
    1. 구루

      번들번호는 프레임워크가 관리해서.. 리셋하려면 프레임워크가 관리하는 정보를 다 지우셔야만 합니다. 🙂

      응답
  6. 도와주세요

    안녕하세요. complie도 나머지것도 하고 했는데요 services (objectClass=*MovieFinder) 하니
    No registered services 라고 뜨네요.

    왜 서비스 등록이 왜 안될까요?

    응답
  7. 도와주세요ㅠ

    서비스 등록이 되지 않아요 ㅠ
    힘들어님 첫번째 질문과 같이 저도 경고창이 떳지만 클래스파일은 만들어 지더군요
    그리고 순조롭게 다 진행이 되었는데
    서비스등록을 확인하려고 services를 해보았지만 등록되지 않았다고 나옵니다. ㅠㅠ
    왜그런걸까요,.,?

    응답
  8. 진돗개

    구루님 질문이 있습니다!
    시간되시면 봐주십시요!
    서비스등록할때
    registration = context.registerService(
    MovieFinder.class.getName(),
    finder, props);
    여기에서 finder 객체를 넣어주는데 여기서 객체를 왜 집어 넣는 겁니까~? 파트5에서 find서비스 불러올때에도
    MovieFinder.class.getName()로 찾아서 불러오든데..
    서비스에 등록할때 집어넣은 객체는 따로 쓸때가 있는겁니까~?

    응답
    1. 진돗개

      아 .. 제가 소스를 자세히 못봤네요 ㅋㅋ MovieListerImpl객체에서 사용하네요.. 그럼 서비스 등록할때 객체를 1가지 밖에 못넣는 거나요 ~?

      응답
  9. 정완

    >>> UNIX운영체제는 :
    javac -classpath equinox.jar:MoviesInterface.jar osgitut/movies/impl/*.java <—요게 맞습니다. 혹시 맥으로 테스트 하시는 분들은 세미콜론이 아니라 콜론으로 해주시면 됩니다.

    응답

정완에게 댓글 남기기 댓글 취소

이메일은 공개되지 않습니다.