참조 : 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, ∞)"
이거랑 같다.



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