* 파트 1 – 첫번째 번들 : Your First Bundle
* 파트 2 – 프레임워크와 연동하기 : Interacting with the Framework
* 파트 3 – 번들간의 의존관계 : Dependencies between bundles
* 파트 4 – 서비스 등록하기 : Registering a Service
* 파트 5 – 서비스 사용하기 : Consuming a Service
* 파트 6 – 동적으로 서비스 추적하기 : Dynamic Service Tracking
* 파트 7 – 선언적 서비스 소개하기 : Introducing Declarative Services
에 이어 8번째 마지막 글입니다. 오탈자 및 이상한 번역은 댓글로 남겨주세요
Getting started with OSGi : OSGi 시작하기 파트 8 – 선언적 서비스와 의존관계
저자 : Neil Bartlett < njbartlett at gmail dot com >역자 : 권 정혁 < guruguru at gmail dot com >
글원본 : http://www.eclipsezone.com/eclipse/forums/t97690.html – Getting started with OSGi : Declarative Services and Dependencies
“Getting Started with OSGi” 시리즈에 돌아 오신걸 환영합니다. 레슨 시작전에 한가지 공지, 이 튜토리얼의 이전회들을 보시려면 제 블로그 페이지에서 링크들을 찾아보실수 있습니다.
지난번에는 선언적 서비스에 대해 처음으로 살펴봤습니다. 이번에는 선언적 서비스의 사용자 측면을 살펴볼 것입니다. 지난번에
java.lang.Runnable
말씀드린대로, 선언전 서비스에 대한 스펙은 이전 레슨들에서 보았던 OSGi 의 글루(glue)코드보다 여러분 코드의 Application Logic 에 집중할수 있도록 해주는 것입니다. 이걸 염두에 두고, 코드를 살펴보겠습니다. 그전에 우린 프로젝트를 하나 만들어야 합니다. 이전 레슨의 순서를 따라서, 이번엔 “SampleImporter” 라는 이름으로 프로젝트를 생성하여 보세요.
새로 생성된 Eclipse 프로젝트에 아래 코드를 복사하여 src 폴더에 붙여넣습니다.
package org.example.ds;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
public class SampleCommandProvider1 implements CommandProvider {
private Runnable runnable;
public synchronized void setRunnable(Runnable r) {
runnable = r;
}
public synchronized void unsetRunnable(Runnable r) {
runnable = null;
}
public synchronized void _run(CommandInterpreter ci) {
if(runnable != null) {
runnable.run();
} else {
ci.println("Error, no Runnable available");
}
}
public String getHelp() {
return "\trun - execute a Runnable service";
}
}
이 클래스는 Equinox 를 실행할때 osgi> 프롬프트 상에서 사용가능한 명령들을 확장하는
CommandProvider
CommandProvider
우리가 이 클래스에서 어떤 OSGi API 도 호출하지 않는다는 것을 주목하세요. 실제로 우리는
org.osgi.*
java.lang.Runnable
setRunnable
unsetRunnable
다른 두개의 메소드
getHelp
_run
_run
전과 같이, 우린 이것이 가능하게 하는 DS 선언을 가진 XML 파일을 제공해야 합니다. 아래 코드를
OSGI-INF/commandprovider1.xml
<?xml version="1.0"?> <component name="commandprovider1"> <implementation class="org.example.ds.SampleCommandProvider1"/> <service> <provide interface="org.eclipse.osgi.framework.console.CommandProvider"/> </service> <reference name="RUNNABLE" interface="java.lang.Runnable" bind="setRunnable" unbind="unsetRunnable" cardinality="0..1" policy="dynamic"/> </component>
제가 지난번에 말하지 않은 중요한 단계가 있습니다. ( 지적해준 Seamus Venasse 에게 감사드립니다.) 여러분의 플러그인 프로젝트안에
build.properties
OSGI-INF
Service-Component: OSGI-INF/commandprovider1.xml
위 DS 선언은 이전에 우리가 봤던것과 같은
implementation
service
implementation
service
CommandProvider
다음 엘리먼트인
reference
name
interface
bind
Runnable
unbind
cardinality
- 0..1: 선택이면서 단일관계 , “0 또는 1″ – “zero or one”
- 1..1: 필수이면서 단일관계 , “딱 1개” – “exactly one”
- 0..n: 선택이면서 복수관계 , “0 에서 여러개” – “zero to many”
- 1..n: 필수이면서 복수관계 , “1 에서 여러개” 또는 “적어도 한개 이상” – “one to many” or “at least one”
이 예제에서는 우린 옵션이면서 단일관계를 선택했으므로, 이것은 우리의 커맨드 서비스가 의존하는 서비스가 없더라도 대처할수 있다는것을 의미합니다. _run 메소드를 다시 살펴보면 이런 상황을 대처하기 위해 서비스 핸들에 대체 null 체크가 필요했다는것을 보실수 있습니다.
이 번들을 실행했을때 어떤 일이 일어나는지 봅시다. 지난번에 작성했던 SampleExporter 번들을 아직 실행중에 있다면, osgi> 프롬프트에서 “run” 명령을 입력했을때 아래 출력을 볼 수 있습니다.
Hello from SampleRunnable
멋집니다. 이것은 우리가 지난번 레슨에서 작성한 Runnable 서비스가 성공적으로 import 되었다는것을 알려줍니다. 이제 stop 명령을 이용해서 SampleExporter 번들을 중단시킵니다. 그리고 다시 “run” 명령을 입력하면 아래와 같은 메시지를 볼수 있습니다.
Error, no Runnable available
이것으로 보아, DS 가 Runnable 서비스가 없어져 버려서 우리의 unsetRunnable 메소드를 호출했다는것을 알수 있습니다.
다시
cardinality
이런 쉬운 변경이 우리가 선언적 서비스를 이용하는 가장 큰 이유중 하나입니다. 우리가
ServiceTracker
여러분께선 제가 아직 언급하지 않은
policy
그럼 지금까지 선택 단일 및 필수 단일 관계를 살펴보았습니다. 그럼 복수관계는 어떨까요 ? 서비스 레지스트리에는 한개이상의 Runnable 이 등록되어있을구 있구, 그중 한가지와 연결(bind)할때 어떤것을 선택하는지는 임의로 결정됩니다. 아마도 우린 현재 등록된 모든
Runnable
만약 우리가
cardinality
setRunnalbe
setRunnable
package org.example.ds;
import java.util.*;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
public class SampleCommandProvider2 implements CommandProvider {
private List runnables =
Collections.synchronizedList(new ArrayList());
public void addRunnable(Runnable r) {
runnables.add(r);
}
public void removeRunnable(Runnable r) {
runnables.remove(r);
}
public void _runall(CommandInterpreter ci) {
synchronized(runnables) {
for(Runnable r : runnables) {
r.run();
}
}
}
public String getHelp() {
return "\trunall - Run all registered Runnables";
}
}
자 이제
OSGI-INF/commandprovider2.xml
<?xml version="1.0"?> <component name="commandprovider2"> <implementation class="org.example.ds.SampleCommandProvider2"/> <service> <provide interface="org.eclipse.osgi.framework.console.CommandProvider"/> </service> <reference name="RUNNABLE" interface="java.lang.Runnable" bind="addRunnable" unbind="removeRunnable" cardinality="0..n" policy="dynamic"/> </component>
그리고 마지막으로 이 파일을 manifest 의
Service-Component
Service-Component: OSGI-INF/commandprovider1.xml, OSGI-INF/commandprovider2.xml
이 선언은 우리가 bind,unbind 메소드의 이름을 변경하고, cardinality를 “0..n”으로 변경했다는것을 제외하면, 이전과 거의 비슷합니다. 실험삼아 몇개의 Runnable 서비스들을 등록하고 runall 명령이 동작하는지를 살펴보세요. 다음으로 만약 우리가 cardinality 를 “1..n”으로 바꾸면 어떻게 될까요 ? 어떻게 될지를 한번 생각해보고 확인해 보세요.
레슨은 여기까지 입니다. OSGi Alliance Community Event 가 다음주에 독일 Munich 에서 열린다는것을 잊지마세요. 아직 등록하기에 늦지 않았습니다. 거기서 봅시다! (역주: 역시 지나버린 이벤트입니다만.. 그냥 번역해 둡니다.)
혁아…
댓글 가뭄이다…
가벼운 내용으로 중간에 하나쯤 넣어줬어야 하지 않았냐..?
너 댓글 무지 좋아한다며… 요즘은 요리도 안하냐?
ㅋㅋㅋ
뭐 예상은 했지만 넘 저조하긴 하군 ^^
잘보고갑니다. 수고하셨어요 ^^
고맙습니다 ^_^
감사히 잘 보겠습니다. 수고하셨네요.
도움이 되셨으면 좋겠네요 ^^
좋은 내용 잘 보고 갑니다~ OSGi를 이해하는데 많은 도움이 되었습니다.
다만 소스 부분에 <, &rt; 가 들어간 부분이 정상적으로 표현되지 않아서 몇몇 소스들은
원본 사이트를 봐야 하네요.
에구.. 댓글 삭제 기능이 없나보군요. 실수로 댓글을 여러번 남겼네요. ( __)
에구 답변이 늦었지만 수정해 두었습니다.
늦게나마 좋은글 잘 보았습니다.. 다만.. 마지막 튜토리얼 실행이 ㅋㅋ 안되네용 ..
왜 서비스는 등록이 되었지만.. 왜 실행이 안되는지.. 아직도 헤매고 있는중 ..
처음에 좀 갑갑한 부분이 많죠 ^^; 화이팅! 입니다
헛 바로 댓글이 ㅋㅋㅋ
아직 여행은 안가셨나봐요.. 그럼 수고하세요
네 아직 일정이 안나와서요
새해 복많이 받으세요!