예제2: 사전 서비스 번들

이번 예제에서는 사전 서비스를 구현하는 OSGi 번들을 만들어 보겠다. OSGi 서비스의 구현은 두개의 단계로 이루어진다. 먼저 서비스의 인터페이스를 정의해야 한다. 그리고는 그 서비스의 본체를 구현해야 한다. 이번 예제에서 만들게 될 사전 서비스는  단어가 존재하는지 검사를 해서 철자가 올바른지 첵크를 하는 서비스이다. 먼저, 심플한 사전 서비스 인터페이스를 정의하는 것으로 시작해 보자. 파일명은 DictionaryService.java가 된다.

/*
 * OSGi and Gravity Service Binder tutorial.
 * Copyright (c) 2003  Richard S. Hall
 * http://oscar-osgi.sourceforge.net
**/

package tutorial.example2.service;

/**
 * 사전 서비스를 정의하는 심플한 서비스 인터페이스.
 * 사전 서비스는 단어의 존재를 첵크하는 간단한 서비스이다.
**/
public interface DictionaryService
{
    /**
     * 단어가 존재지 검사한다.
     * @param word 검사 대상 단어
     * @return 사전에 존재하는 단어인 경우 true
     *         존재하지 않으면 false
    **/
    public boolean checkWord(String word);
}

이 서비스 인터페이스는 꽤 심플하다. 단 하나의 메소드만 구현하면 된다. 단, 서비스 인터페이스가 위치하는 페키지가 tutorial.example2 패키지가 아니고 tutorial.example2.service 패키지임을 주시하자. 이렇게 하는 이유는 인터페이스 정의를 다른 번들에게도 제공해야 하기 때문이다. 그렇기 때문에 공유해야할 서비스 인터페이스와 공유할 필요가 없는 코드를 분리하는 것이다. 이 기법은 인터페이스와 구현을 완전히 분리하는 것은 보장하게 한다.

아래의 소스코드를 보자. 번들은 번들 컨택스트를 사용해서 사전 서비스를 등록한다. 사전 서비스의 구현은 별도 파일에 할 수도 있었지만 여기서는 번들 Activator 클래스의 inner클래스로 정의하고 있다. 아래에 번들의 소스코드가 있다. 파일명은 Activator.java이다.

/*
 * OSGi and Gravity Service Binder tutorial.
 * Copyright (c) 2003  Richard S. Hall
 * http://oscar-osgi.sourceforge.net
**/

package tutorial.example2;

import java.util.Properties;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceEvent;

import tutorial.example2.service.DictionaryService;

/**
 * 이 클래스는 번들 컨택스트를 이용해서 영어 사전 서비스를 
 * OSGi 프레임워크에 등록하는 번들을 구현한다.
 * 사전 서비스의 인터페이스는 독립된 파일에 정의되어 있고
 * 구현은 이 파일의 inner 클래스로 되어 있다.
**/
public class Activator implements BundleActivator
{
    /**
     * BuncleActivator.start() 메서드를 구현한다.
     * 번들 컨택스트를 이용해서 사전 서비스의 인스턴스를 등록한다.
     * 프로퍼티를 서비스에 첨부해서 서비스를 검색할 때 질의될 수 있도록 한다.
     * @param context 프레임워크의 번들용 컨택스트.
    **/
    public void start(BundleContext context)
    {
        Properties props = new Properties();
        props.put("Language", "English");
        context.registerService(
            DictionaryService.class.getName(), new DictionaryImpl(), props);
    }

    /**
     * BundleActivator.stop() 메서드를 구현한다. 프레임워크가
     * 자동으로 등록된 서비스를 제거해 주기 때문에 구현내용은 비워 둔다.
     * @param context 프레임워크의 번들용 컨택스트.
    **/
    public void stop(BundleContext context)
    {
        // NOTE: 자동으로 서비스가 제거된다.
    }

    /**
     * 사전 서비스를 구현하는 private inner 클래스
     * 서비스에 대한 자세한 내용은 DictionaryService를 참고한다.
    **/
    private static class DictionaryImpl implements DictionaryService
    {
        // 사전에 등록되어 있는 단어들의 집합.
        String[] m_dictionary =
            { "welcome", "to", "the", "osgi", "tutorial" };

        /**
         * DictionaryService.checkWord() 메서드를 구현한다.
         * 전달된 단어가 사전에 존재하는지 검사한다.
         * @param word 검사한 단어.
         * @return true 사전에 단어가 존재하는 경우.
         *         false 그외.
        **/
        public boolean checkWord(String word)
        {
            word = word.toLowerCase();

            // 비효율적인 방법
            for (int i = 0; i < m_dictionary.length; i++)
            {
                if (m_dictionary[i].equals(word))
                {
                    return true;
                }
            }
            return false;
        }
    }
}

등록한 서비스를 stop() 메서드에서 제거할 필요가 없다는 점에 주목하자. OSGi 프레임워크가 자동으로 제거하기 때문이다. 여기서 구현한 사전 서비스는 아주 간단하다. 사전은 다섯개의 단어를 정적 배열에 담고 있어서 성능이 좋지 못하다. 고로 교육용으로만 사용할 수 있는 예제이다. 이제 manifest.mf 파일에 번들의 메타데이터를 기술한다. manifest 파일의 내용은 아래와 같다.

Bundle-Activator: tutorial.example2.Activator
Export-Package: tutorial.example2.service
Bundle-Name: English dictionary
Bundle-Description: A bundle that registers an English dictionary service
Bundle-Vendor: Richard Hall
Bundle-Version: 1.0.0

앞에서의 예에서처럼 대부분의 내용은 설명일 뿐이다. BundleActivator 인터페이스를 구현하고 있는 클래스를 Bundle-Activator 에 기술하고 번들이 제공(공유)하는 패키지를 Export-Package 속성에 기술한다. 이 속성이 다른 번들들이 우리의 사전 서비스 인터페이스를 import할 수 있게 해준다.

예제1에서 한 것과 동일하게 아래의 명령으로 컴파일한다.

javac -d c:\classes *.java

c:\classes 디렉토리에 패키지 디렉토리와 클래스파일들이 생성된다. 이제 컴파일 결과와 manifest 파일을 묶어서 JAR 파일을 만든다.

jar cfm example2.jar manifest.mf -C c;\classes tutorial\example2

이제 번들을 install하고 start할 준비가 되었다.

Oscar를 실행하자. profile을 물어 올 것이다. tutorial이라고 입력하자. 우리가 만들 모든 번들은 tutorial에 넣을 것이다. Oscar가 실행되었다면 예제1에서 만든 번들이 활성화되어 있는지 확인해 본다. ps 라는 Oscar 쉘 명령을 사용해서 모든 번들의 일람과 상태, 식별 번호를 확인할 수 있다. 예제1의 번들이 활성화되어 있지 않다면 start 명령과 ps 명령으로 확인한 번들 식별 번호를 사용해서 start시켜야 한다. 이제 사전 서비스 번들을 install하고 start한다. c:\tutorial 이라는 디렉토리에 JAR파일을 만들었다고 하면

start file:/c:/tutorial/example2.jar

라는 명령으로 install과 start를 하자. 예제1의 번들이 active상태라면, 사전 서비스가 등록되었을 때 발생한 이벤트를 예제1의 번들이 출력하는 것을 볼 수 있었어야 한다.
ps 명령으로 각 번들의 식별번호를 확인해서 그 번호로 start나 stop을 행할 대상 번들을 지정할 수 있다. 사전 서비스를 start 시키거나 stop 시키면 그 이벤트를 예제1의 번들이 받아서 그 내용을 출력할 것이다. 예제3에서는 사전 서비스를 사용하는 클라이언트를 만들어 볼 것이다. Oscar에서 나가려면 shutdown명령을 사용한다.

원문:http://oscar-osgi.sourceforge.net/tutorial/ex2.html
번역: 허 련호(airless at funit.net)
2009/05

Comments