밑에 스프링 사이트에서 jar파일 및 Dependency를 찾을수있습니다.
http://www.springsource.com/repository/app/;jsessionid=A431F38984691BE6F71E5849F17C46E0.jvm1
또한 이곳에서도 jar파일 및 Devpendency를 찾을 수 있다.
http://mvnrepository.com/
밑에 스프링 사이트에서 jar파일 및 Dependency를 찾을수있습니다.
http://www.springsource.com/repository/app/;jsessionid=A431F38984691BE6F71E5849F17C46E0.jvm1
또한 이곳에서도 jar파일 및 Devpendency를 찾을 수 있다.
http://mvnrepository.com/
1. SpringDMd을 사용
1-1. 이벤트 핸들러로 이벤트 받기
Manifest.mf의 Import-Package에 org.osgi.service.event 추가
1-1-1. 인터페이스
public interface EventHandler {
void handleEvnet(Event event);
}
1-1-2. 구현체
public class 클래스명 implements EventHandler {
//인터페이스 구현체
public void handleEvent(Event event) {
System.out.println("\r\n[Event Received] Topic : " + event.getTopic());
for(String key : event.getPropertyNames()){
System.out.println("\t[Property] " + key + " : " + event.getProperty(key));
}
}
}
1-1-3. spring.xml
<osgi:service id="EventAdminServiceBean명" ref="구현EventAdminBean명" interface="org.osgi.service.event.EventHandler">
<osgi:service-properties>
<entry key="event.topics" value="Topic주소" />
</osgi:service-properties>
</osgi:service>
<bean id="구현EventAdminBean명" class="구현EventAdmin경로" />
1-2. 이벤트 보내기
1-2-1. 구현체
public class 클래스명 {
private EventAdmin eventAdmin;
@ServiceReference
public void setEventAdmin(EventAdmin eventAdmin) {
this.eventAdmin = eventAdmin;
}
private String EVENT_QUEUE;
public void setEVENT_QUEUE(String EVENT_QUEUE) {
this.EVENT_QUEUE = EVENT_QUEUE;
}
public void sender(){
Properties props = new Properties();
props.put("key", "value");
//동기 전송: sendEvent, 비동기 전송: postEvent
eventAdmin.sendEvent(new Event(EVENT_QUEUE, props));
}
}
1-2-2. spring.xml
<bean id="클래스Bean명" class="클래스 경로" init-method="실행 메서드 명">
<property name="EVENT_QUEUE" value="Topic주소" />
</bean>
<bean class="org.springframework.osgi.extensions.annotation.ServiceReferenceInjectionBeanPostProcessor" />
1-2-3. event를 보내기 위해 spring-osgi-annotation jar파일 필요
Maven을 사용한다면 dependency를 추가 하거나 아니며 spring-osgi-annotation jar파일이 필요
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>org.springframework.osgi.extensions.annotation</artifactId>
<version>1.2.1</version>
</dependency>
본 내용은 실전 OSGi&SpringDM(위키북스) 책의 일부 내용입니다
1. SpringDM을 사용한 OSGi Service 구현
Service를 좀더 편하게 사용하기 위해 SprigDM사용(SpringDM설치 방법 참조 Charter 11-p265)
1-1. SpringDM xml서비스 등록
구현체 googleBean 즉, 클래스 chapter12.google.Google를 인터페이스, 서비스 속성와 같이 서비스 등록
<beans ... >
//구현체
<bean id="googleBean" class="chapter12.google.Google" />
//서비스 등록
<osgi:service id="googleService" ranking="5" ref="googleBean">
//인터페이스
<osgi:interfaces>
<value>chapter04.searchengine.SearchEngine</value>
</osgi:interfaces>
//서비스 속성
<osgi:service-properties>
<entry key="service.vendor" value="Google" />
<entry key="searchable" value="Text,Image,Code" />
</osgi:service-properties>
</osgi:service>
</beans>
1-2. 서비스 실행
3-2-1. 서비스 실행 객체 얻기
//xml파일에서 주입받아 사용
private SearchEngine searhEngine;
public void setSearchEngine(SearchEngine searchEngine) {
this.searcheEngine = searchEngien;
}
1-2-2. 서비스 주입을 위한 xml파일
<beans ...>
//인터페이스를 통해 reference가져 옴
<osgi:reference id="searchEngineSvc" interface="chapter04.searchengine.SearchEngine" />
//<osgi:reference id="searchEngineSvc" interface="chapter04.searchengine.SearchEngine" cardinality="0..1" timeout="5000"/>
//위의 reference를 통해 서비스 검색(서비스 없으면 5분 동안 해당 서비스 대기)
<bean id="searchClient" class="chapter12.client.SearchClient" init-method="start">
<property name="searchEngine" ref="searchEngineSvc" />
</bean>
</beans>
1-2-3. 복수 서비스 검색(더 많은 옵션은 chpater12-p321참조)
//xml파일에서 주입받아 사용
private List searhEngines;
public void setSearchEngines(List searchEngines) {
this.searcheEngines = searchEngiens;
}
//xml 파일
<beans ...>
//인터페이스를 통해 reference가져 옴
<osgi:List id="searchEngineSvc" interface="chapter04.searchengine.SearchEngine" />
//위의 reference를 통해 서비스 검색(서비스 없으면 5분 동안 해당 서비스 대기)
<bean id="searchClient" class="chapter12.client.SearchClient" init-method="start">
<property name="searchEngine" ref="searchEngineSvc" />
</bean>
</beans>
3. OSGi Service를 구현한 jar파일
Maven을 사용한다면 dependency를 추가 하거나 아니며 OSGi Service를 구현 jar파일이 필요
<dependency>
<groupId>org.eclipse.osgi</groupId>
<artifactId>org.eclipse.osgi.services</artifactId>
<version>3.1.200.v20071203</version>
</dependency>
OSGi Log 서비스
1. OSGi의 Log 서비스
Log4j를 직접 사용하는 것도 가능하지만, OSGi에서는 간단하면서도 확장이 쉽고 좀더 동적인 변경이 가능한
OSGi Service 기반의 Log 메커니즘을 R1버전부터 제공하며 래퍼(Wpapper)와 같은 기능을 한다.
사용자가 로그를 입력하기 위해 LogService를 ServiceTracker에서 객체를 받아와 log메서드로 log를 입력해주면
로그를 받을 클래스에 LogListener 인터페이스를 구현 후 ServiceTracker에서 LogReaderService객체를 받아와 로그
를 받을 클래스를 LogReaderService에 addLogListener(this) 해주면 받을 준비 끝이다.
이제 로그를 받으면 되는데 LogListener 인터페이스의 구현체인 loged(LogEntry)에서 받은 logEntry타일에서 로그
정보를 추출하면 된다.
각각의 객체 설명은 밑에 인터페이스를 참조
1-1. OSGi Log 서비스에서 사용하는 4개의 중요 인터페이스
1-1-1. LogService: LOG_ERROR=1, LOG_WARNING=2, LOG_INFO=3, LOG_DEBUG=4
log(int logLevel, String msg)
log(int logLevel, String msg, Throwable ex)
log(ServiceReference sr, int logLevel, String msg)
log(ServiceReference sr, int logLevel, String msg, Throwable ex)
1-1-2. LogEntry: LogService에 의해 생성되어 객체로 log메서드를 호출시 입력되는 부가 정보들과 메시지
getBundle() => 해당 로그메시지를 생성한 번들 객체 호출
getSErviceReference() => 해당 로그메세지와 관련있는
erviceReference 객체 반환(log메서드 호출시 입력한 것만)
getLevel() => 로그의 레벨을 가져옴
getMessage() => 로그의 문자열 가져옴
getException() => 해당 로그메세지와 관련있는 Throwable객체 반환
(log메서드 호출시 입력한 것만)
getTime() => 로그메시지가 만들어진 시간 가져옴
1-1-3. LogReaderService: LogEntry객체의 리스트를 저장하여 사용자에게 리턴해주는 서비스
getLog() => 로그 메시지를 최근 순으로 가져온다.(이쿼녹스의 경우
100개 로그 저장 객수와 레벨 설정은 Configuration속성에서 변경 가능)
addLogListener => LogReaderService에서 Listener 추가
1-1-5. LogListener: 로그를 리스닝 할 수 있는 인터페이스로 LogReaderService에 add해 주어야 로그를
받을 수 있다.
logged(LogEntry) => LogReaderService에 LogEntry객체가 추가
되었을 때 호출
2. OSGi Log를 구현한 jar파일
Maven을 사용한다면 dependency를 추가 하거나 아니며 log구현 jar파일이 필요
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.log</artifactId>
<version>1.0.0</version>
</dependency>
SpringDM을 사용하여 POJO개발을 하면 BundleActivator로 BundleContext를 받을 수 없다. 하지만 SpringDM이 생성해주는 OSGi Application Context에는 기본적으로 bundleContext라는 Bean이 생성된다. 그러므로 BundleContext가 필요한 클래스에 BundleContextAware 인터페이스를 구현해 주면 BundleContext를 전단 받을 수 있다.
1. BundleContextAware 인터페이스
public interface BundleContextAware{
public void setBundleContext(BundleContext context);
}
2. BundleContext 얻기
public calss 클래스명 implements BundleContextAware{
private BundleContext context;
public void setBundleContext(BundleContext context) {
this.context = context;
}
//위와 같이 BundeContextAware 인터페이스를 구현하면
//SpringDM이 자동으로 setBundleContext를 사용하여 Bean을 주입해줌
ServiceTracker tracker = new ServiceTracker(context, EventAdmin.class.getName(), null);
…
}
Event Admin 서비스 사용
1. 기본 계념
화이트보드 패턴을 이용하여 이벤트 메시지를 전달 한다.
1-1. Event Object 속성
//이벤트 필터링을 이름 같은 것(일반적으로 kr/bit/uhealth 와 같이 계층구조를 가짐)
String Topic
//이벤트에 대한 추가 속성(속성 종류는 charter5-p114 참조)
Hashtable properties
2. Event Admin 구현
2-2. 이벤트 핸들러로 이벤트 받기
Manifest.mf의 Import-Package에 org.osgi.service.event 추가
2-2-1. 인터페이스
public interface EventHandler {
void handleEvnet(Event event);
}
2-2-2. 구현체
public class Activator implements BundleActivator, EventHandler {
//모든 이벤트 받음
final static String[] topics = new String[]{"*"};
public void start(BundleContext context) throws Exception {
Dictionary<String, Object> prop = new Hashtable<String,Object>();
prop.put(EventContants.EVENT_TOPIC, topics);
context.registerService(EventHandler.class.getName(), this, prop);
}
public void stop(BundleContext context) throws Exception {
...
}
//인터페이스 구현체
public void handleEvent(Event event) {
System.out.println("\r\n[Event Received] Topic : " + event.getTopic());
for(String key : event.getPropertyNames()){
System.out.println("\t[Property] " + key + " : " + event.getProperty(key));
}
}
}
2-2-3. 이벤트 필터링
//모든 이벤트 받기
final static String[] topics = new String[]{"*"};
//세부항목 이벤트 받기
final static String[] topics = new String[]{"org/osgi/framework/ServiceEvent/*"};
//세부 선택항목 이벤트 받기
final static String[] topics = new String[]{"org/osgi/framework/ServiceEvent/REGISTERED", "org/osgi/framework/ServiceEvent/STARTED"};
//그 밖에 필터 방법 http://www.ietf.org/rfc/rfc2254.txt 참조
2-3. 이벤트 보내기
ServiceTracker tracker = new ServiceTracker(context, EventAdmin.class.getName(), null);
tracker.open();
Properties props = new Properties();
props.put("key", "value");
EventAdmin ea = (EventAdmin) tracker.getService();
if(ea != null) {
//동기 전송: sendEvent, 비동기 전송: postEvent
ea.sendEvent(new Event("com/foo/bar", props));
}
3. EventAdmin을 구현한 jar파일
Maven을 사용한다면 dependency를 추가 하거나 아니며 EventAdmin을 구현 jar파일이 필요
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.eventadmin</artifactId>
<version>1.0.0</version>
</dependency>
본 내용은 실전 OSGi&SpringDM(위키북스) 책의 일부 내용입니다.
OSGi 서비스 사용
1. 서비스 구현을 위한 3요소 (chapter 4-p69)
SGi 서비스 등록을 위해서는 해당 서비스 객체의 인터페이스, 인터페이스 구현체, 서비스 속성 Dictionary가 필요하다. 그리고 기본적으로 모든 구현 번들 Manifest.mf의 Import-Package에는 인터페이스 패키지(믿의 예에선 SearchEngine 인터페이스)를 추가해 주어야하며 인터페이스 패키지는 Manifest.mf에 Export-Package되어야 한다.
1-1. 서비스 3요소
1-1-1. 인터페이스
public interface SearchEngine {
List<String> search(String query);
List<String> searchImage(String query);
}
1-1-2. 구현체
public Google implements SearchEngine {
List<String> search(String query) {
...
}
List<String> searchImage(String query) {
...
}
}
public Naver implements SearchEngine {
List<String> search(String query) {
...
}
List<String> searchImage(String query) {
...
}
}
1-1-3. 서비스 속성
Dictionary props = new Properties();
props.put(org.osgi.framework.constants.SERVICE_VENDOR, "Google");
props.put("searchable", "Text,Image");
//서비스를 등록할 때 개발자가 지정할 수 있는 랭킹 값으로, 만약 같은 인터페이스에 대해
//여러 개의 서비스 구현체가 있다면 이 랭킹값이 큰 순으로 우선순위를 가진다.
//기본값은 0이다. 만약 랭킹값이 같다면 id값이 작은 것이 더 높은 우선순위를 가진다.
props.put(org.osgi.framework.Constants.SERVICE_RANKING, 5);
2. 서비스 구현
2-1. 서비스 등록 구현
public class Activator implements BundleActivator {
//인터페이스
private SearchEngine service;
//서비스에 대한 접근자인 ServiceReference를 읽어오거나, Service의 등록을 해지할 때 사용
//즉, 서비스 등록은 Bundlecontext.registerService가 하지만 서비스 해지는 ServiceRegistratio 을 통해서만 가능
private ServiceRegistration registration;
public class Activator implements BundleActivator {
//서비스 속성
Dictionary props = new Properties();
props.put(org.osgi.framework.Constants.SERVICE_VENDOR, "Google");
props.put("searchable", "Text,Image");
props.put(org.osgi.framework.Constants.SERVICE_RANKING, 5);
//인터페이스 구현체
service = new Google();
//서비스 등록
//context.registerService(인터페이스,구현체,서비스속성)
registration = context.registerService(SearchEnglish.class.getName(), service, props);
//여러게 서비스 등록
//bundlecontext.registerService(String[] clazzes, Object service, Dictionary properties);
}
public void stop(BundleContext context) throws Exception {
//서비스 해지(꼭하지 않아도 됨)
registration.unregister();
}
}
2-2. 서비스 실행
2-2-1. 서비스 정보를 가져오는 ServiceReference 인터페이스
//BundleContext.getServiceReference(String interfaceName);
//BundleContext.getService(ServiceReference refenece);
//BundleContext.getServiceReference에서 서비스레퍼런스 정보를 객체로 가져와
//이 객체를 통해 BundleContext.getServiceReference함수로 서비스를 가져올 수 있다.
public interface ServiceReference extends Comparable {
//속성 값을 읽어 온다.
public Object getProperty(String key);
//속성의 키 값을 배열로 읽어온다.
public Stiring[] getPropertyKeys();
//이 서비스를 등록한 번들 객체를 리턴한다. 만약 서비스가 unregister 되었다면
//null을 리턴한다.
public Bundle getBundle();
//이 서비스를 사용하는 번들의 배열을 리턴
public Bundle[] getUsingBundles();
}
2-2-2. 서비스 실행 구현
public class ClientActivator implements BundleActivator{
ServiceReference reference;
SearchEngine engine;
public void start(BundleContext context) throws Exception {
//ServiceReference객체를 가져옴
reference = context.getServiceReference(SearchEngine.class.getName());
//ServiceReference객체를 통해 서비스를 가져옴
engine = (SearchEngine) context.getService(reference);
//검색엔진을 사용하여 검색기능 호출
List result = engine.search("query string");
}
public void stop(BundleContext context) throws Exception{
context.ungetService(reference);
engine = null;
}
}
2-3. 서비스 검색
2-3-1. SerivceTracker
2-2-2와 같이 서비스를 가져오면 OSGi 동적 환경에서 서비스가 언제 존재 할지 모르기 때문에 서비스를 기다려야 한다. 이런 서비스를 찾고 기다리기 위해 ServiceTracker가 필요하다.
2-3-1-1. ServiceTracker 메서드
//세 개의 생성자를 가지고 있음 ServiceTrackerCustomizer는 추적하는 방식을 개발자가
//원하는데로 변경(자세한 설명 책에 없음)
ServiceTracker(BundleContext, ServiceReference, ServiceTrackerCustomizer)
ServiceTracker(BundleContext, String, ServiceTrackerCustomizer)
ServiceTracker(BundleContext, Filter, ServiceTrackerCustomizer)
//ServiceTracker 사용전 open() 서비스 사용 끝난 후 close()
open(), close()
//서비스 리턴 getService()는 랭크값이 크고 ID가 가장 작은 서비스, getServices()는 해당
//모든 서비스 리턴
getService(), getServices()
//해당 ServiceReference또는 그 배열 리턴
getServiceReference(), getServiceReferences()
//timeout시간동안 서비스 검색 후 서비스 반환, 0일경우 무한 루프(데드락이 걸릴수있음 스레드 사용 권장)
waitForService(timeout)
2-3-2. ServiceTracker 구현
public void run() {
//context는 스레드 인자값으로 값음, ServiceTrackerCustomizer는 null
ServiceTracker tracker = new ServiceTracker(context, SearchEngine.class.getName(), null);
track.open();
SearchEngine engine;
try {
//파라미터 0은 무한 검색
engine = (SearchEngine) tracker.waitForService(0);
//서비스 실행
List results = engine.search("query string");
...
} catch (InterruptedException e) {
e.printStackTrace();
}
tracker.close();
}
3. OSGi Service를 구현한 jar파일
Maven을 사용한다면 dependency를 추가 하거나 아니며 OSGi Service를 구현 jar파일이 필요
<dependency>
<groupId>org.eclipse.osgi</groupId>
<artifactId>org.eclipse.osgi.services</artifactId>
<version>3.1.200.v20071203</version>
</dependency>