Whiteship's Note


BundleContext로 할 수 있는 일

Spring DM/OSGi : 2008.06.25 23:12


BundleActivator 다음으로 가장 중요한 OSGi API를 꼽으라면, BundleContext일 겁니다. 어쩌면 BundleActivator보다 중요할지도 모르죠. OSGi 플랫폼에 설치한 번들과 관련된 문맥 정보를 담고 있는 객체니까요. 어떤 용도로 쓸 수 있는지 알아두면 좋겠죠?

시스템 전역에서 사용할 설정 프로퍼티즈 룩업

ID로 설치된 다른 번들 찾기

설치된 모든 번들 목록 가져오기

번들을 프로그래밍을 통해서 라이프사이클 다루기

새로운 번들을 프로그래밍을 통해서 설치하기

프레임워크가 관리하는 영속 저장소에서 파일 가져오거나 저장하기

프레임워크 내부에 있는 어떤 번들의 상태 변화를 알려주기 위한 번들 리스너 등록 또는 해지하기

프레임워크 내부에 있는 어떤 서비스의 상태 변화를 알려주기 위한 서비스 리스너 등록 또는 해지하기

일반적인 프레임워크 이벤트를 알려주기 위한 프레임워크 리스너 등록 또는 해지하기

참조 : http://neilbartlett.name/blog/osgibook/

'Spring DM > OSGi' 카테고리의 다른 글

OSGi 툴 세트 Pax  (0) 2008.10.21
Shared Mutable State  (2) 2008.09.25
The Price of Freedom  (0) 2008.09.25
Concurrency and OSGi  (0) 2008.09.25
BundleContext로 할 수 있는 일  (0) 2008.06.25
2 Security Layer  (0) 2008.02.18
1. Introduction  (0) 2008.02.17
top


bnd를 소개합니다.

Spring DM/exercise : 2008.06.23 23:25


bnd는 겉보기에는 간단한 jar 파일 하나지만, 사실 이클립스 플러그인인데다가, Ant 태스크 정의를 가지고 있고, Maven 플러그인이며, 실제 독립적으로 어떤 기능을 수행하는 Java 애플리케이션이기도 하다. 그야말로 본좌라고 할 수 있다.

http://www.aqute.biz/Code/Download

위 링크에 가면 bnd-버전.jar 파일을 바로 다운받을 수 있습니다. 간단하군요. 다른 프로젝트들처럼 zip 파일로 샘플이며 문서며 소스 코드도 묶어두지 않고 바로 jar 파일입니다.

흠...사용법(콜솔 명령어, Eclipse 플러긴, Ant 스크립트, Maven 플러긴)은

http://www.aqute.biz/Code/Bnd

위의 링크 하단에 있습니다.

top

TAG Bnd, OSGi

화이트보드 패턴

Spring DM/etc : 2008.06.06 00:02


도입

OSGi 서비스의 다이내믹한 특징 때문에 프로그래머가 그 변경 사항을 추적해야 하는 노고가 필요한데, 이전에는 리스너들을 사용했었는데 이게 너무 복잡해지고 에러가 발생할 여지가 많아서 이 문서에서 그 이슈를 살펴보고 보다 쉽고 근본적으로 더 신뢰할 수 있는 모델을 설명하고자 한다.

배경

1. 리스너 패턴

자바의 기본적인 이벤트 리스너 구조 설명 생략.

리스너 패턴의 단점. 클래스 파일이 너무 많다. 프로그램 시작 시간에 영향을 주고 프로그램 사이트에도 영향을 주고 따라서 실행시 오버헤드가 존재한다. 대부분의 경우 이벤트 소스는 단일 리스트만 등록한다. 그런데도 이벤트 소스는 리스너들 리스트를 다룰 수 있도록 반드시 추가적인 벡터를 가지고 있어야 한다. 물론 이 문제가 메모리가 남아돌고 CPU가 빠른 데탑에서는 별 문제가 아니지만 임베디드 환경에서는 매우 중요한 오버헤드다.

또 다른 이슈는 이벤트 소스와 리스너 사이의 의존성이 분명하지 않다는 것이다. 이벤트 소스가 사라지면 그것이 물고 있던 리스너들도 제거되어야 한다. 만약 리스너가 없어지면 해당 리스너를 리스너 목록에서 제거해야 한다. 이런걸 사이프 사이클 이슈라고 한다. 일반적인 자바 애플리케이션에서는 이게 별 문제는 아니다. 일반적으로 초기화 과정 중에 리너너들을 등록하는데 이건 뭐 구현하기도 쉽고 확인하기도 쉽다. 하지만, 제거 하는 과정은 검증하기가 어렵고 보통 전혀 이런 과정을 다루지도 않는다. 워크스테이션 환경에서는 이게 별 문제가 아니다. 하지만 임베디드 환경에서는 이런 가정을 할 수 없으며 완전히 동적이지도 않다.

2. OSGi 환경

OSGi 환경에는 다음고 같은 것들이 필요하다
• Small devices
• Collaboration model
• Continuously up and running VM
• Life cycle management

작은 장치. 각각의 클래스 파일은 300 에서 500 바이트의 오버헤드를 가지고 있다. 따라서 파일이 많아질 수록 안 좋다. 따라서 OSGi 스펙 만드는 초기 시절에는 어설픈 예외 클래스나 어댑터 클래스들을 만들지 않기로 결정했었다.

작은 장치는 성능과 동적 메모리에도 제약이 있다. 메모리를 사용하는 객체들을 만드는 것도 최소화하는 방안을 스펙을 만들며 시도했다.

OSGi 협력 모델은 서비스 레지스트리를 사용하여 만들어졌다. 이 레지스트리는 번들(이게 곧 애플리케이션)이 서비스를 등록하도록 한다. 서비스는 보통 자바 객체이며 자바 인터페이스를 사용하여 다른 구현체로 갈아 칠 수도 있로고 한다. 레지스트리의 동적인 성격은 서비스가 언제 나오고 들어가는지 서비스 추적할 수 있는 무언가를 필요로 하게 됐다.

지속적인 수정과 실행 기능은 "라이프 사이클 관리"와 "다른 프로그래밍 규칙을 필요로하는 서비스 레지스트리"에 관련되어 있다.

 3. 화이트보드 패턴

화이트보드 패턴은 리스너 패턴으로 인해 필요한 사적인 레지스트리를 만드는 대신 서비스 레지스트리의 사용을 강화한 것이다. 이벤트 리스너를 이벤트 소스에 등록해서 이벤트를 추적하는 대신 화이트보드 패턴은 리스너 자체를 서비스로 등록하고 이벤트 소스가 이벤트를 가지고 서비스 레지스트리에 있는 모든 리스너들을 호출하는 방법이다.

사용자 삽입 이미지
보통은 서버 번들과 애플리케이션 번들 간에 복잡도 트레이드 오프가 있기 마련인데, 이 경우에는 둘 다 복잡도가 낮아진다. 둘 모두 OSGi 서비스 레지스트리에게 책임을 위임했기 때문이다.

추가적인 장점
- 디버깅: 이벤트 리스너를 레지스트리에서 볼 수 있다. 어떤 프레임워크도 레지스트리를 탐색하는 도구를 지원할꺼다.
- 시큐리티: OSGi 프레임워크 ServicePermissions는 이벤트 소스로의 접근을 제어할 수 있다. 이벤트 리스너가 이벤트 리스너 인터페이스를 등록할 수 있는 권한을 가지고 있어야하기 때문이다.
- 프로퍼티즈: 레지스트리는 모든 리스너중 부분집합을 선택할 때 서버가 사용할 프로퍼티즈를 사용할 수 있다. 이런 매카니즘을 설정 관리에 사용할 수 있다.

참조 : http://www.osgi.org/documents/osgi_technology/whiteboard.pdf

top


귿!! OSGi위에 웹 애플리케이션 돌리기 성공 with Spring DM

Spring DM/exercise : 2008.04.30 18:00


사용자 삽입 이미지

위 그림 한장이면 돌리는 방법은 끝나죠.

맨 아래 보이는 녀석이 Spring DM 받으면 src/sample에 들어있는 웹 애플리케이션입니다. 자세한 내용은 좀 더 공부해야겠지만 일단 예제를 돌려서 기쁘네요.




현재 Servlet 까지는 됐는데, JSP는 아직 안 됩니다. 이것 저것 만지다보면 될 것 같네요.

top


OSGi 번들 만들기 2

Spring DM/etc : 2008.04.08 21:54


참조 : Creating OSGi bundle

OSGi 메타데이터 작성하기

손으로
손수 OSGi 메타데이터를 작성하는 일은 비추.
한 줄당 72 스페이스를 넘으면 안 된다.
META-INF/MANIFEST.MF 파일이 압축파일 젤 위에 있어야 한다.
이 방법은 정말 정말 다른 방법이 없을 때나 사용하라.

Bnd
Bnd는 BuNDle 도구로 Peter Kriens(OSGi Technical Officer)님께서 만들었다. OSGi R4 번들용 메타데이터를 만들어주는 도구다. 멋진건 bnd.jar 파일 자체가 실행가능한 파일인데다가, Ant 태스크도 가지고 있고, 이 거 자체로 이클립스 플러그인이기 때문에, Eclipse의 plugins 폴더에 넣으면 번들 만들어 주는 메뉴가 생긴다.

(와.. 정말 죽인다.)

이걸 사용해서, 클래스들을 OSGi 번들로 만들 수도 있고, 이클립스 프로젝트를 OSGi 번들로 만들 수도 있고, 기존의 JAR 파일을 OSGi 번들로 만들 수 도 있다.

예제가 있는데 이건 실습하면서 해보게 생략합니다.

java -jar bnd.jar print c3p0-0.9.1.2.jar

java -jar bnd.jar wrap c3p0-0.9.1.2.jar

java -jar bnd.jar wrap -properties c3p0-0.9.1.2.bnd c3p0-0.9.1.2.jar

Maven용 번들 플러그인

Apache Felix Bundle Plug-in은 Bnd와 Maven2를 연동할 수 있는 메이븐 플러그인이다. 메이븐의 POM에 해당 프로젝트가 필요로 하는 라이브러리 정보가 들어있기 떄문에, Bnd가 MANIFEST를 작성할 때 필요한 추가 정보를 POM을 보고 생성할 수 있다.

예제가 있는데.. 이것도 실습해보기 위해 생략합니다.

(아.. 정말 Maven의 POM이 유용하게 쓰이겠군. 버전도 있지, optional인지도 있지, 캬.. 죽이는데.. OSGi랑  Maven 이랑 찰떡궁합이였군!!!)

Bnd가 번들로 패키징 할 때, 클래스패스에 있는 모든 클래스를 묶어버리는 것을 주의해야 한다. Bnd가  Export/Import 패키지를 보고서 생성할 jar파일에 추가할 라이브러리를 추가/제거 하긴 하는데, 패턴 매칭을 잘 해서 실제로 포함할 패키지만 가지고 묶을 수 있도록 설정을 잘 해야한다.

별도 개발, in-house 툴

바이트코드 분석을 기반으로 새로운 툴을 만들어 사용해도 된다. 스프링은 ASM 기반 바이트 코드 파서를 사용해서 테스트 프레임워크를 만들었다. 보다 효율적으로 간단한 MENIFEST.MF 파일을 만들려고..

OSGi 저장소 사용하기

기존의 JAR를 Bnd를 사용하여 새로운 OSGi 번들로 만들기 전에, 이미 OSGi 저장소에 존재할 수 있으니 거기서 찾아서 사용해도 된다.

OSGi Bundle Repository(ORB)
Eclipse Orbit
Apache Felix Commons
Apache OSGified projects

top


OSGi 번들 만들기 1

Spring DM/etc : 2008.04.08 21:16


참조 : Creating OSGi bundles

OSGi를 접할 때, 가장 먼저 익혀야 할 단어는 바로 번들(bundle). 이 아티클에서는 번들이 뭐고 어떻게 일반 Jar 파일을 OSGi 번들로 변환할 수 있는지 살펴본다.

번들은 무엇인가?

OSGi 스펙에서는 번들을 "모듈화 단위 Unit of modularization"이라고 표현하고 있다. 모듈은 다시 사용자에게 어떤 기능을 제공하기 위해 필요한 클래스와 리소스들을 뭉친것. 이라고 한다. 좀 더 정확히 번들은 무엇인가?

번들은 다음의 것들을 가지고 있는 JAR 파일들이다.
- 리소스들을 가지고 있다.
- JAR 파일의 내용과 번들에 대한 정보를 나타내는 menifest 파일을 가지고 있다.
- OSGi-OPT 폴더 또는 그 하위 폴더에 에 부가적인 문서를 가지고 있을 수 있다.

(그렇다고 JAR 만 번들이 될 수 있는 건 아닌데... WAR도 번들이 될 수 있는데.. Costin Leau님께서는
쉽게 설명하려고 그런 것 같다.)

번들 = JAR + OSGi 정보(META-INF/MANIFEST.MF)

OSGi 메타데이터

OSGi 메타데이터는 menifest 구성요소로 표현하며, 스펙에는 20가지 정보 되는 헤더를 설명하지만 여기서는 가장 자주 사용하는 것들 몇개만 살펴본다.

Export-Package
- 어떤 패키지를 노출시켜서 다른 버들들이 가져다 사용할 수 있는지 명시한다. 여기에 명시한 패키지만 노출시키고 나머지는 다른 번들들이 참조할 수 없다.

Import-Package
- 번들에서 참조할 패키지를 나타낸다. 여기에 명시한 것들만 참조할 수 있다. 기본으로, 여기에 명시한 패키지들은 필수mandatory가 된다. 따라서 명시한 패키지가 존재하지 않으면 해당 번들을 실행할 때 fail 하게 된다. 예외 발생.

Bundle-SymbolicName
- 유일한 필수 항목으로, 번들을 식별하기 위한 유일한 값이다. 컨벤션은 도메인 명 거꾸로 사용하기. 패키지 이름처럼..

Bundle-Name
- 사람들이 읽기 편한 이름을 정의한다. 공백이 없어야 한다. Bundle-SymbolicName보다 더 의미있는 정보를 짧게 표현할 수 있기 떄문에 이 헤더를 추가하는 것을 권장한다.

Bundle-Activator
- BundleActivator는 OSGi 스펙 인터페이스로 번들이 OSGi 프레임워크 위에서 가동Start 되거나 멈출Stop 때 실행되는 자바 코드를 정의할 때 사용한다. 여기에 적어줄 클래스는 풀 패키지 경로를 붙여줘야 하며, public  클래스여야 하고, 인자가 없는 public 생성자를 가지고 있어야 한다.

Bundle-Classpath
- 해당 JAR 파일이 여러 폴더에 클래스 패키지나 jar 파일을 라이브러리로 참조할 때 기본 패키지 경로(jar 파일 루트에서 도달할 수 있는 클래스들)를 확장하기 위해 사용한다.

Bundle-ManifestVersion
- OSGi release 3을 사용하면 1이라고 적어주고, OSGi release 4(이게 최신 스펙)를 쓰려면 2라고 설정한다. 기본값이 1이기 때문에, OSGi release 4를 사용할 땐 반드시 2라고 설정해준다.

예제
Bundle-Name: spring-core
Bundle-SymbolicName: org.springframework.bundle.spring.core
Bundle-ManifestVersion: 2
Export-Package:org.springframework.core.task;uses:="org.springframework.core,org.springframework.util";version=2.5.1 org.springframework.core.type;uses:=org.springframework.core.annotation;version=2.5.1[…]
Import-Package:org.apache.commons.logging,edu.emory.mathcs.backport.java.util.concurrent;resolution:=optional[…]

Export-Package:org.mypackage 라고 설정하면, org.mypackage에 있는 클래스들만 Export한다. org.mypackage.util에 있는 클래스들은 Export하지 않는다.

(패키지로 클래스를 Export 하는 거 말고 서비스를 Export/Import하는 설정은 왜 설명 안하지.. 그것도 많이 쓸텐데..)

Package consideration

export 할 떄는 별로 신경 쓸 것이 없는데,  import 할 때는 신경 쓸 께 좀 있다. 바로 어떤 구현체 어떤 버전을 사용할꺼냐는 것인데, logging(JDK 1.4것을 쓸꺼냐 Log4J를 쓸꺼냐),  정규표현식(Jakarta ORO를 쓸꺼냐 JDK 1.4+를 쓸꺼냐) 등등...

optional을 사용해서 패키지 가용 여부에 따라 사용하도록 설정할 수 있다. 즉 필수mandatory가 아니도록 설정할 수 있다.

예제
Import-Package: […]edu.emory.mathcs.backport.java.util.concurrent;resolution:=optional

여기서는 java.util.concurrent가 가용하면 그것을 쓰고, 만약에 없으면 없는대로 번들을 가동 시킨다.

OSGi에서는 같은 클래스가 서로 다른 버전으로 여러개 존재 할 수 있다. 따라서 Export/Import에 명시하는 모든 패키지명 뒤에 버전을 명시해주는 것이 좋다. 베스트 프랙티스다.

OSGi에서 버전은 다음과 같이 구성된다.

<major>, <minor>, <micro>, <qualifier> 알것으로 생각하고 생략...

명시하지 않았을 때, 기본 버전은 "0.0.0"다.

import 할 때 특정 범위의 버전을 명시하고 싶다면, [], (), (], [) 를 사용할 수 있다. [] 는 초과 미만, () 는 이하, 이상을 뜻한다. 수학에서 동그라미를 까맣게 칠한거랑 하얀거 차이. 하얀게 [], 까만게 ()

버전을 저렇게 표시하지 않고 하나만 달랑 표시하면, 그 버전 이상을 뜻하는 것이다.

예제
Import-Package: com.mypackage;version="1.2.3"
즉 이녀석은
Import-Package: com.mypackage;version="[1.2.3, ∞)"
이거랑 같다.


기네;; 한 번 끊어서 갑니다.
top


2 Security Layer

Spring DM/OSGi : 2008.02.18 09:14


The OSGi Security Layer is an optional layer that underlies the OSGi Service Platform. The layer is based on the Java 2 security architecture. It provides the infrastructure to deploy and manage applications that must run in fine-grained controlled environments.

OSGi Security Layer는 선택적인 레이어다. 자바 2 security 아키텍처를 기반으로 만들었다. 반드시 세밀하게 제어된 환경에서 동작해야하는 애플리케이션을 배포하고 관리할 때 필요한 기반시설을 제공한다.

- Code Authentication: By location(Permission Admin service가 담당)과 By signer(Conditional Permission Admin service가 담당)방식으로 코드의 인증을 할 수 있다.

- Digitally Signed JAR Files: signer 방식의 Authentication이다. Principal에 의해 sign된 이 후에 그 내용이 수저오되지 않았음을 보장한다. Jar 파일에 public key cryptography를 적용하여 사용 권한을 줄 수 있다.

사용자 삽입 이미지

- JAR 구조와 Manifest: manifest 파일과 괕은 형식이지만 SF확장자로 끝나는 파일을 META-INF 폴더에 위치 시킨다. 이런 signing 자원들은 MENIFEST.MF 파일 바로 다음에 와야 한다. 그렇지 않으면 해당 JAR 파일을 unsigned로 인식한다.
사용자 삽입 이미지

나머지 복잡해서 패스;

'Spring DM > OSGi' 카테고리의 다른 글

OSGi 툴 세트 Pax  (0) 2008.10.21
Shared Mutable State  (2) 2008.09.25
The Price of Freedom  (0) 2008.09.25
Concurrency and OSGi  (0) 2008.09.25
BundleContext로 할 수 있는 일  (0) 2008.06.25
2 Security Layer  (0) 2008.02.18
1. Introduction  (0) 2008.02.17
top


1. Introduction

Spring DM/OSGi : 2008.02.17 11:35


OSGi Framework Overview

- OSGi 프레임워크는 OSGi 서비스 플랫폼 스팩의 핵심요소다.
- 번들 보안과 배포 다운로드, 설치, 제거를 동적이고 확장가능한 형태로 담당한다. 그러기 위해서 번들과 서비스의 종속성을 관리하는데 이 부분은 나중에 자세히.
- 프레임워크의 기능 세분화
사용자 삽입 이미지
- Security Layer: Java 2 security를 기반으로 다양한 제약 사항들과 blank(?)들을 추가했다. 보안 패키징 형식을 정의한다.

- Module Layer: 모듈화 된 모델을 정의한다. 자바 배포 모델의 단점을 극복한다. 자바 패키지를 번들에서 공유하거나 다른 패티지로부터 숨기는 등의 규칙을 가지고 있다. Life Cycle Layer와 Service Layer 없이도 사용할 수 있다. Life Cycle Layer는 번들을 Module Layer에서 관리할 수 있는 API를 제공한다. Service Layer는 번들 간의 의사소통 모델을 제공한다.

- Life Cycle Layer: 번들에 라이프 사이클 API를 제공한다. 번들을 다루기 위한 런타임 모델을 제공한다. 어떻게 번들을 시작하고 멈추고 설치하고 업데이트하고 언인스톨할지 정의한다. 추가적으로 다양한 이벤트 API를 제공하여 번들이 서비스 플랫폼의 기능을 제어할 수 있도록 한다. Life Cycle Layer는 Module Layer가 꼭 필요하며 Service Layer는 선택사항이다. 나중에 좀 더 자세히.

- Service Layer는 자바 번들 개발자들에게 동적이고, 정확하며, 탄탄한 프로그래밍 모델을 제공한다. 인터페이스와 구현체 사이를 디커플링 함으로써 서비스 번들의 개발과 배포를 단순화 시킨다. 이 모델은 번들 개발자들이 그들의 인터페이스만 가지고 서비스를 묶을 수 있도록 한다. 번들이 프레임워크 서비스 레지스트리를 통해서 동적으로, 가용한 구현체를 선택할 수 있도록 허용한다. 번들은 새로운 서비스를 등록하고, 서비스 상태에 대한 정보를 받고, 기존의 서비스를 룩업 할 수 있다. 프레임워크의 이런 측면으로 인해 번들을 배포된 이후에도 확장성을 보장한다. 즉, 시스템을 재시작 할 필요없이 새로운 기능을 추가한 번들을 설치하거나, 이미 존재하는 번들을 수정하고 업데이트 하는 것이 가능하다.

- 레이어들 사이의 관계
사용자 삽입 이미지

참조: OSGi Spec



'Spring DM > OSGi' 카테고리의 다른 글

OSGi 툴 세트 Pax  (0) 2008.10.21
Shared Mutable State  (2) 2008.09.25
The Price of Freedom  (0) 2008.09.25
Concurrency and OSGi  (0) 2008.09.25
BundleContext로 할 수 있는 일  (0) 2008.06.25
2 Security Layer  (0) 2008.02.18
1. Introduction  (0) 2008.02.17
top


설맞이 OSGi 간단 예제

Spring DM/exercise : 2008.02.06 16:46


1. Equinox 기반 OSGi 번들 만들기.
2. OSGi 번들 패키지 노출하기와 들여오기.
3. OSGi 서비스 노출하기와 들여오기.
4. Spring DM을 사용하여 서비스 노출하기.
5. Spring DM을 사용하여 서비스 사용하기.

가장 기본이 되는 것들만 살펴봤습니다.



top


3. OSGi 서비스 노출하기와 들여오기.

Spring DM/exercise : 2008.02.06 12:52


1. Runtime 수정하기.

먼저 service.impl 패키지는 노출시키지 않고, service 패키지만 노출 시킵니다. 그 안에 들어있는 인터페이스만 외부로 노출 시키려는 것이지요.

사용자 삽입 이미지

이거면 됩니다. 그러면 이제 더 이상, StoreManager에서 service.impl 패키지를 import 할 수 없습니다. 따라서 구현체는 사용할 수 가 없게 됩니다. 구현체는 제공하지 말고 서비스를 registry에 등록하겠습니다.

2. Service Registry에 등록하기.

Activator로 이동해서. Store 번들이 ACTIVE 상태가 될 때, 특정 서비스를 등록하도록 코딩합니다.

public class Activator implements BundleActivator {

    public void start(BundleContext context) throws Exception {
        System.out.println("Store 번들을 가동 했습니다.");
        String className = Greeting.class.getName();
        context.registerService(className, new GreetingImpl(), null);
        System.out.println("GreetingImpl 객체를 '" + className + "'으로 서비스 레지스트리에 등록 했습니다.");
    }
   
    public void stop(BundleContext context) throws Exception {
        System.out.println("Store 번들을 멈췄습니다.");
    }

}

context에, 서비스를 등록합니다. 인터페이스의 이름으로 구현체를 등록합니다. JNDI와 비슷한 것 같네요.

자 이제 이 번들을 다시 Export 하고, start 시켜봅니다.

more..


ACTIVE 상태가 된 다음에 서비스가 등록 된 것을 확인할 수 있습니다.

3. Dependencies 수정하기.

이제 StoreManager를 수정해야 합니다. 먼저 Depedencies에서 service.impl을 제거해 줍니다. 인터페이스만 알고 있으면 되기 때문에, service만 남겨둡니다.

사용자 삽입 이미지

이렇게 수정해면, GreetingImpl 클래스를 참조할 수 없기 때문에 에러가 발생하는데, 이 때 이상하게 Greeting 까지 못 찾는다고 에러가 납니다. 이건 Eclipse의 버그 같습니다. 이럴 때는 그냥 Eclipse를 껐다가 다시키면, Greeting 인터페이스를 참조할 수 있습니다.

이제 Activator에서 GreetingImpl 객체를 직접 만들어 사용하던 코드를 context에서 서비스를 가져오도록 수정해야 합니다.

서비스를 가져오려면 ServiceTracker를 사용해야 하는데, 그러려면, StoreManager에 org.osgi.util.tracker 패키지를 import 해주어야 합니다.

사용자 삽입 이미지

4. ServiceTracker 사용하기

이제 구현해 줍니다.

public class Activator implements BundleActivator {
   
    private ServiceTracker greetingServiceTracker;

    public void start(BundleContext context) throws Exception {
        System.out.println("StoreMaganer 번들 가동했습니다.");

        String serviceName = Greeting.class.getName();
        greetingServiceTracker = new ServiceTracker(context, serviceName, null);
        greetingServiceTracker.open();
        Greeting greeting = (Greeting) greetingServiceTracker.getService();
        System.out.println("'" + serviceName + "' 서비스를 가져왔습니다.");
       
        System.out.println(greeting.hi("토비"));
    }
   
    public void stop(BundleContext context) throws Exception {
        System.out.println("StoreManager 번들 멈춥니다.");
       
        greetingServiceTracker.close();
        greetingServiceTracker = null;
       
        System.out.println("Service Tracker 닫습니다.");
    }

}

ACTIVE 상태가 되면, 서비스 트래커를 만들고, 열어 줍니다. RESOLVED 상태가 될 때(stop)는 닫은 다음에 null로 만들어 줍니다.

그리고 Store 번들을 시작한 다음에 StoreManager를 시작하면 잘 동작합니다.

osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      org.eclipse.osgi_3.3.1.R33x_v20070828
1    RESOLVED    StoreManager_1.0.0
2    RESOLVED    Store_1.0.0

osgi> start 2
Store 번들을 가동 했습니다.
GreetingImpl 객체를 'service.Greeting'으로 서비스 레지스트리에 등록 했습니다.

osgi> start 1
StoreMaganer 번들 가동했습니다.
'service.Greeting' 서비스를 가져왔습니다.
hi 토비

osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      org.eclipse.osgi_3.3.1.R33x_v20070828
1    ACTIVE      StoreManager_1.0.0
2    ACTIVE      Store_1.0.0

osgi>

자 이 상태에서 Store를 stop하고, StoreManager도 stop한 다음에 StoreManaegr를 먼저 start 시킬 수 있습니다. 그럴 수도 있겠죠. 아직 작업이 마무리 되지 않았는데, 접속을 시도하고 있다고 생각해시면 그럴 수도 있다는 것이 상상되실 겁니다. 이런 상황에서 어떤 일이 벌어지는지 보겠습니다.

osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      org.eclipse.osgi_3.3.1.R33x_v20070828
1    ACTIVE      StoreManager_1.0.0
2    ACTIVE      Store_1.0.0

osgi> stop 2
Store 번들을 멈췄습니다.

osgi> stop 1
StoreManager 번들 멈춥니다.
Service Tracker 멈춥니다.

osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      org.eclipse.osgi_3.3.1.R33x_v20070828
1    RESOLVED    StoreManager_1.0.0
2    RESOLVED    Store_1.0.0

osgi> diag 1
file:/c:/plugins/StoreManager_1.0.0.jar [1]
  No unresolved constraints.

osgi> start 1
StoreMaganer 번들 가동했습니다.
'service.Greeting' 서비스를 가져왔습니다.
org.osgi.framework.BundleException: Exception in storemanager.Activator.start() of bundle StoreManager.
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:1018)
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:974)
    at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:346)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:260)
    at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:252)
    at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._start(FrameworkCommandProvider.java:260)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:150)
    at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:291)
    at org.eclipse.osgi.framework.internal.core.FrameworkConsole.console(FrameworkConsole.java:276)
    at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:218)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
    at storemanager.Activator.start(Activator.java:22)
... 생략

재밌습니다. 분명 StoreManager가 Resolved 상태였는데(종속성이 모두 해결되고 Start 될 수 있는 상태) start를 시키면... NullPointerException이 발생합니다.

왜 그러죠?


당연하죠. 서비스 레지스트리에 StoreManager의 Activator에서 찾으려는 Service가 없기 때문이죠.

왜 없죠?

Store 번들이 stop 으로 인해 RESOLVED 상태가 되면서, 등록됐던 서비스들이 사라져버려서 그렇습니다.
증거는 아래를 열어보세요.

more..


뭔가 멋지지가 않습니다.

5. 좀 더 멋지게 ServiceTracker 사용하기.

일단 StoreManager가 Resolved 상태가 됐다면, Start 시켜서, AVTIVE 상태로 만들고 싶습니다.(서비스가 없더라도 말이죠.) 그러다가 원하는 서비스가 등록되면, 그 때 서비스를 얻어낸 다음 할 일을 처리하게 하고 싶습니다.

public class Activator implements BundleActivator {

    public static class GreetingServiceTracker extends ServiceTracker {

        public GreetingServiceTracker(BundleContext context) {
            super(context, Greeting.class.getName(), null);
        }

        public Object addingService(ServiceReference reference) {
            Greeting greeting = (Greeting) context.getService(reference);
            System.out.println(greeting.hi("토비"));
            return greeting;
        }
    }

    private ServiceTracker greetingServiceTracker;

    public void start(BundleContext context) throws Exception {
        System.out.println("StoreMaganer 번들 가동했습니다.");

        greetingServiceTracker = new GreetingServiceTracker(context);
        greetingServiceTracker.open();
    }

    public void stop(BundleContext context) throws Exception {
        System.out.println("StoreManager 번들 멈춥니다.");

        greetingServiceTracker.close();
        greetingServiceTracker = null;

        System.out.println("Service Tracker 멈춥니다.");
    }

}

ServiceTracker의 addingService() 메소드는 ServiceTracker 객체를 만들 때 필요한 ServiceTrackerCustomizer 파라미터가 null일 때 호출 됩니다. 그래서 위처럼 생성자에서 super를 사용해서 세 번째 인자에 null을 넣어 주어야 addingService() 메소드가 호출되고, 그럼 이 메소드 안에서 context.getService(ServiceReference);를 사용해서 서비스 객체를 가져옵니다. 여기서 비밀이 있는 것 같은데 우선은 복잡한 건 제끼고 예제부터 실행해 보겠습니다.

이번에도 위에서 했던 것처럼, Export 한 다음, StoreManager와 Store를 stop 시키고, StoreManager를 먼저 start 시켜보겠습니다.

osgi> ss

Framework is launched.

id    State       Bundle
0    ACTIVE      org.eclipse.osgi_3.3.1.R33x_v20070828
1    RESOLVED    StoreManager_1.0.0
2    RESOLVED    Store_1.0.0

osgi> start 1
StoreMaganer 번들 가동했습니다.

osgi> start 2
Store 번들을 가동 했습니다.
hi 토비
GreetingImpl 객체를 'service.Greeting'으로 서비스 레지스트리에 등록 했습니다.

osgi>

와우~~ 멋지지 않나요.

뭐가 멋진지 모르겠다구요??

분명 StoreManager를 먼저 실행 시켰는데 에러가 발생하지 않았습니다. 멋지지 않아요??? 물론 여기까진 별로 멋지지 않을 수도 있습니다. 그런데.. Store를 start 시키자 마자. StoreManager에서 해야 했던 일이 실행됐습니다.

이건 정말 멋진겁니다.

그런데 코딩이 정말... 피곤하죠. 이제 Spring DM이 등장할 차례 입니다.

참조 : http://www.eclipsezone.com/eclipse/forums/t91059.html
top


2. OSGi 번들 패키지 노출하기와 들여오기.

Spring DM/exercise : 2008.02.06 11:13


1. 앞에서 만든 Store에 간단한 인터페이스 하나와 그걸 구현한 클래스를 만듭니다.


public interface Greeting {

    public String hi(String name);
}


public class GreetingImpl implements Greeting {

    public String hi(String name) {
        return "hi " + name;
    }

}

사용자 삽입 이미지

service 패키지에 Greeting 인터페이스, service.impl 패키지에는 GreetingImpl 클래스를 두었습니다. 그리고 이 두 개의 패키지 안에 있는 클래스들을 다른 번들에서 사용할 수 있도록 Export 해주어야 합니다.

2. 패키지 Export 하기

MENIFEST.MF 파일을 클릭하고, 하단의 Runtime 탭을 클릭하고, Export packages에서 Add 버튼을 클릭하여 밖으로 노출시킬 패키지들을 추가해줍니다. Alt + S로 저장해 줍니다.

사용자 삽입 이미지

3. 확인하기

위 번들을 다시 Export 해서, 다시 C:\plugins 폴더에 Store_1.0.0.jar 파일을 갱신합니다. 지금은 파일만 수정했을 뿐, OSGi 플랫폼에 올라가있는 번들은 수정되지 않았습니다.

지금 올라가 있는 Store 번들은 이클립스로 보고 있는 프로젝트의 번들이 아니라, 이전 글에서 Export 했던 Jar 파일을 기반으로 올라간 번들입니다. 그렇기 때문에, 방금전에 다시 Export를 한 것입니다. 어쨋든 좀 햇갈릴 수도 있겠지만, 지금까지 잘 따라오셨다면 다음과 같이 번들을 업데이트 할 수 있습니다.

update [id] 명령은 원래 RESOLVED 상태에서 수행됩니다. 그런데 만약 현재 번들이 ACTIVE 상태였다면, 해당 번들을 STOP으로 멈춘다음에 update를 수행하고, 다시 START 시켜줍니다.(똑똑한 Equinox, 나이스 OSGi 스팩)

사용자 삽입 이미지

현재 번들이 service 패키지와 service.impl 패키지를 노출시키고 있는 것을 확인했습니다.

4. 새로운 번들 만들기

위의 번들을 사용할 새로운 번들을 만듭니다. 첫 번째 글을 참조하시면 쉽게 만들 수 있을테니 생략하겠습니다.번들 이름은 편의상 StoreManage라고 하겠습니다.

5. Store 번들의 패키지 사용하기

StoreManager 번들의 Actovator를 다음과 같이 구현하려고 합니다.

public class Activator implements BundleActivator {

    public void start(BundleContext context) throws Exception {
        System.out.println("StoreMaganer 번들 가동했습니다.");
        Greeting greeting = new GreetingImpl();
        System.out.println(greeting.hi("기선"));
    }
   
    public void stop(BundleContext context) throws Exception {
        System.out.println("StoreManager 번들 멈춥니다.");
    }

}

위 코드에서 빨간색 부분이 당연히 에러가 납니다. 저런 클래스가 StoreManager에는 없기 때문입니다. 이 번들에서 다른 번들의 패키지를 import 하면 됩니다.

사용자 삽입 이미지

MENIFEST.MF 파일을 클릭하고, Dependecies 탭을 클릭하고 오른쪽의 imported Packages에서 add를 클릭하여, 노출된 패키지 중에서 검색을 합니다. service와 service.impl을 클릭하고 저장해 줍니다.

그런다음 Organize Import를 하면, 에러는 사라집니다.(위 과정을 거치지 않고, Organize Import를 했을 때, 노출된 패키지 중에서 검색 한 다음 자동으로 MENIFEST.MF 파일에 import-package를 추가해주고, 그 다음에 소스 코드에서도 import를 추가해주면 좋겠는데 말이죠...)


6. 새로운 번들 설치하기

위에서 만든 번들을 이전 번들과 마찬가지로, Export 해서 배포 가능한 번들 Jar로 만들어 주고, install 합니다.

사용자 삽입 이미지

7. 시작 합니다.

INSTALLED 상태가 됐네요. 이제 시작하기 전에 혹시나 이 번들이 필요로 하는 패키지를 못찾지는 않았을까 걱정이 되서, diag [id]로 확인해 봤습니다.

사용자 삽입 이미지

없는게 없다는군요. 그럼 start [id]로 시작시켜 봅니다.

사용자 삽입 이미지

귿!! (번들 번호가 바꼈는데, 제가 구현할 때 빠트린게 있어서 다시 Uninstall 하고, Export 한 다음에 다시 Install 해서 그렇습니다.)

다음 글에서는 이렇게 구현체를 직접 제공하는게 아니라, 인터페이스만 제공 하고 서비스 레지스트리를 사용해서 서비스로 노출하는 방법을 살펴보겠습니다.

================================================================================
복잡한 샘플

한번 ACTIVE 상태가 되면, 그 안에서 노출시킨 패키지의 클래스들 중에서 다른 번들에 의해 사용되는 클래스는 번들이 사라져도, 레지스트리에 계속 남아서 사용됩니다.

more..


오묘한, 번들 라이프사이클과 서비스 레지스트리. 이 부분은 꼭 열공해야겠습니다.
top


1. Equinox 기반 OSGi 번들 만들기

Spring DM/exercise : 2008.02.06 10:06


1. Eclipse를 다운로드 합니다.
http://www.eclipse.org/downloads/ 이 곳에서 Ecliipse Classic 3.3.1.1을 다운 받습니다.

2. Eclipse를 실행하고, 새 프러그인 프로젝트를 생성합니다.
Ctrl + N -> Plug 입력
사용자 삽입 이미지

3. 프로젝트 이름을 넣고, 맨 아래 Target Platform을 OSGi 프레임워크 Equinox로 선택합니다.

사용자 삽입 이미지

4. Next를 클릭합니다. 여기서 버전이 중요한데, OSGi에서는 같은 번들 여럿이 다른 버전으로 동시에 동작할 수 있습니다. A라는 번들이 B_1.0.0.jar 번들을 사용하면서, C라는 번들이 B_1.1.0.jar 번들을 사용할 수 있습니다. 그 상태에서 이 상태에서 A번들을 잠시 멈췄다가 B_1.0.0.jar 번들대신에 B_1.1.0.jar 번들을 사용하도록 수정한 다음에 다시 시작시키는 등의 컨트롤이 가능합니다.

또 하나 중요한 것은 Plug-in Options에 있는 Activator입니다. 이 녀석은 해당 번들을 시작시켜서 Active 상태가 되면 자동으로 콜백 메소드(start)를 호출하고, 멈출 때도 자동으로 콜백 메소드(stop)를 호출해 줍니다. 따라서 해당 번들을 가동시킬 때 어떤 일을 하고 싶다면, 이 옵션이 체크된 상태(기본)로 만들면 되고, 그렇치 않다면 체크를 없애고 넘어갑니다.

사용자 삽입 이미지

저는 일단 Activator로 만들겠습니다. 위 상태 그대로 Next를 클릭합니다.

5. 탬플릿을 선택합니다.

사용자 삽입 이미지

탬플릿을 선택하는 이유는 코드 탬플릿과 필요한 번들을 자동으로 추가해 주기 때문입니다. Bundle의 경우 org.osgi.framework를 추가해 주는데 그 이유는 이 번들이 가지고 있는 BundleActivator라는 인터페이스를 구현해야 하기 때문입니다. 이 인터페이스가 위에서 말한 콜백 메소드를 가지고 있습니다.

이제 Finish를 합니다. Next가 한번 더 있긴 하지만 별거 아닙니다. 궁금하신 분들은 눌러보셔도 됩니다.

6. 자 그러면 다음과 같이 프로젝트가 생성된 것을 볼 수 있습니다.

사용자 삽입 이미지
위에 보이는 화면은 MENIFEST.MF 파일을 비주얼하게 보여주는 편집기 입니다. 저곳의 하단에 있는 Depedency에서는 번들과 패키지 종속성을 설정할 수 있으며, Runtime에서는 외부로 노출 시킬 패키지를 설정할 수 있습니다.

일단 자동으로 만들어준 Activator부터 확인해보겠습니다.

7. Activator.java 파일을 열어 봅니다.

start와 stop 메소드에 간단한 메시지를 출력하도록 구현되어 있는 것을 볼 수 있습니다. 이 부분을 적당하게 수정해보겠습니다.

사용자 삽입 이미지

8. 이제 이 번들을 osgi 플랫폼 Equinox에서 실행해 보겠습니다.

Ctrl + 3 -> Run Dia 엔터  를 입력하여, Open Run Dialog 창을 띄우고, 왼쪽 맨 아래에 있는 OSGi Framework를 더블클릭합니다. 그러면 화면 중앙에 Equinox에서 가동시킬 모든 번들 목록이 표시 됩니다.

사용자 삽입 이미지

여기서 지금 제가 가동시키려는 것은 딱 하나, 맨 위에 있는 Store 뿐이니까 나머지는 모두 체크박스를 없애 줍니다. 아예 나타나지 않게 할 수도 있는데, Ctrl + 3 -> Target Plat 엔터를 입력하여, 이클립스가 로딩 될 때 읽어들인 번들 목록을 다음과 같이 모두 해제 시켜준 다음에 Apply를 클릭합니다.

사용자 삽입 이미지

자 그러면 프로젝트에서 에러가 납니다. 왜? org.eclise.osgi 번들까지 목록에서 제거했기 때문입니다. 그 녀석은 있어야 하니까(BundleActivator 때문에...) 그 녀석만 추가해 줍니다.

사용자 삽입 이미지

자 그러면 이제 에러도 없어지고, 정말 필요한 번들만 Target Platform에 선택해 두었습니다. 다시 Run Dialog로 돌아갑니다.

사용자 삽입 이미지

이제 Run을 클릭합니다.

9. 콘솔에 메시지가 출력된 것을 확인할 수 있습니다.

사용자 삽입 이미지
OSGi 플랫폼을 가동시키자 마자, Store 번들이 가동됐기 때문입니다.

ss 명력을 사용해서, 현재 이 플랫폼에 존재하는 번들들의 상태를 확인할 수 있습니다.

사용자 삽입 이미지

stop [id] 명령을 사용해서 id에 해당하는 번들을 멈출 수 있습니다.

사용자 삽입 이미지

bundle [id]를 입력하면 번들에 대한 구체적인 정보를 확이할 수 있습니다.

사용자 삽입 이미지

현재 이 번들은 등록 된 서비스도 없고, 사용하는 서비스도 없고, 공개한 패키지도 없고, 가져온 패키지가 하나 있습니다. org.osgi.framework

uninstall [id]를 입력하면, 해당 번들을 플랫폼에서 없앱니다.

사용자 삽입 이미지

install [url]  명령을 사용해서, 번들을 설치할 수 있습니다. 이렇게 가져오려면 일단 Export를 해서 배포 가능한 jar 파일로 만들어 주어야 합니다. 프로젝트를 우클릭하고, Export를 클릭합니다. 그리고 deployable 머시기를 선택합니다.

사용자 삽입 이미지

Next를 클릭하고, destination은 C:\으로 선택합니다.

사용자 삽입 이미지

Options에 가서 이 과정을 빌드 파일로 만들 수 있는데, 글이 너무 길어져서 생략하겠습니다. Finish 클릭하면 C:\plugins 폴더가 만들어지고, 그 안에 Store_1.0.0.jar 파일이 들어있는 것을 볼 수 있습니다.

다시 콘솔로 돌아와서

install file:c:/plugins/Store_1.0.0.jar

이렇게 입력하면 번들이 설치됩니다.

사용자 삽입 이미지

상태는 INSTALLED 상태이고, 이 상태에서 Start를 시켰을 때, 필요한 종속성이 모두 충족되면, ACTIVE 상태로 넘어갑니다. 필요한 종속성을 확인하려면, diag [id] 명령을 사용하면 됩니다.

사용자 삽입 이미지

이제 start [id] 명력을 사용해서 해당 번들을 가동하겠습니다.

사용자 삽입 이미지

1부 끝!!
top