2017-12-06 41 views
1

Apache Felix를 사용하여 이벤트를 보내고받는 방법을 결정하는 (매우) 간단한 테스트를 만들었습니다.OSGI의 선언적 서비스

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>be.pxl</groupId> 
    <artifactId>EventSender</artifactId> 
    <version>1.0-SNAPSHOT</version> 

    <dependencies> 
     <dependency> 
      <groupId>org.osgi</groupId> 
      <artifactId>org.osgi.service.event</artifactId> 
      <version>1.3.1</version> 
      <scope>provided</scope> 
     </dependency> 
     <dependency> 
      <groupId>org.osgi</groupId> 
      <artifactId>org.osgi.core</artifactId> 
      <version>6.0.0</version> 
      <scope>provided</scope> 
     </dependency> 
     <dependency> 
      <groupId>org.osgi</groupId> 
      <artifactId>org.osgi.service.component.annotations</artifactId> 
      <version>1.3.0</version> 
      <scope>provided</scope> 
     </dependency> 
     <dependency> 
      <groupId>org.eclipse.osgi</groupId> 
      <artifactId>org.eclipse.osgi.services</artifactId> 
      <version>3.2.100.v20100503</version> 
     </dependency> 

    </dependencies> 

    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.apache.felix</groupId> 
       <artifactId>maven-bundle-plugin</artifactId> 
       <version>2.4.0</version> 
       <extensions>true</extensions> 
       <configuration> 
        <instructions> 
         <Bundle-Vendor>SmartCampus</Bundle-Vendor> 
         <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> 
         <Export-Package> 
          be.pxl.*;version="1.0.0" 
         </Export-Package> 
         <Import-Package> 
          org.osgi.service.component.annotations 
          org.eclipse.osgi.service 
          org.osgi.core 
          org.osgi.service.event 
         </Import-Package> 
         <_dsannotations>*</_dsannotations> 
        </instructions> 
       </configuration> 
      </plugin> 
     </plugins> 
    </build> 

</project> 

모든 것이 잘 컴파일 :

package be.pxl; 

import org.osgi.framework.BundleContext; 
import org.osgi.service.component.annotations.Activate; 
import org.osgi.service.component.annotations.Component; 
import org.osgi.service.component.annotations.Reference; 
import org.osgi.service.event.Event; 
import org.osgi.service.event.EventConstants; 
import org.osgi.service.event.EventHandler; 
import java.util.Dictionary; 
import java.util.Hashtable; 

@Component(name = "be.pxl.Subscriber", immediate = true) 
public class Subscriber implements EventHandler { 

    private BundleContext context; 

    @Activate 
    public void run(Object object) { 
     System.out.println("IN SUBSCRIBER"); 
     System.out.println("\tIN RUN METHOD"); 
     String[] topics = new String[]{"event"}; 
     Dictionary props = new Hashtable(); 
     props.put(EventConstants.EVENT_TOPIC, topics); 
     System.out.println("\t\tCONTEXT: " + context); 
     context.registerService(EventHandler.class.getName(), this, props); 
     System.out.println("\t\tCONTEXT AFTER REGISTERSERVICE: " + context); 
    } 

    public void handleEvent(Event event) { 
     System.out.println("IN SUBSCRIBER"); 
     String text = event.getProperty("text").toString(); 
     System.out.println("\tEVENT CALLED: " + text); 
    } 

    @Reference(name="be.pxl.context", service=BundleContext.class) 
    protected void setBundleContex(BundleContext context) { 
     this.context = context; 
    } 

} 

이 내 보낸 사람의 치어는 다음과 같습니다

package be.pxl; 

import org.osgi.service.component.annotations.Activate; 
import org.osgi.service.component.annotations.Component; 
import org.osgi.service.component.annotations.Reference; 
import org.osgi.service.event.Event; 
import org.osgi.service.event.EventAdmin; 

import java.util.HashMap; 

@Component(name = "be.pxl.Publisher", immediate = true) 
public class Publisher { 

    EventAdmin admin; 

    @Activate 
    public void run(Object object) { 
     System.out.println("IN PUBLISHER"); 
     Event event = new Event("event", new HashMap<String, Object>()); 
     System.out.println("\tEVENT: " + event); 
     admin.postEvent(event); 
     System.out.println("\tADMIN: " + admin); 
    } 

    @Reference(name="be.pxl.admin", service = EventAdmin.class) 
    protected void setEventAdmin(EventAdmin admin) { 
     this.admin = admin; 
    } 

} 

이 내 수신기 :

내 보낸 것입니다. 나는 mvn clean 패키지를 사용하여 만든 다음,이 jar 파일을 내 아파치 펠릭스 컨테이너에 설치하고 시작한다. 그러나 아무 일도 일어나지 않습니다. 아무것도 pritns 얻을.

미리 감사드립니다.

답변

0

당신은 거기에있는 대부분의 것처럼 보입니다! 식별 한대로 이벤트 관리자는 화이트 보드 모델을 사용하여 이벤트를 수신합니다. 중요한 점은 화이트 보드에 듣고 싶은 주제가 무엇인지 묻는 것이 필요하다는 것입니다.

%%% 업데이트 %%%

이벤트 관리 항목 이름은 / 문자로 구분 된 토큰의 계층 구조를 사용합니다. 일정을 게시 할 때 특정 주제에 대해 수행합니다 (예 : foo/bar/baz). 이벤트를 받으면 등록 된 관심사와 일치하는 주제에 대해 EventHandler가 호출됩니다. 이러한 관심사는 특정 주제에 대한 것이거나 *으로 끝나며 와일드 카드 일치를 나타낼 수 있습니다. 예를 들어 foo/bar/*foo/bar/baz으로 전송 된 이벤트를 수신하고 foo/bar/fizzbuzz으로 전송 된 이벤트는 수신합니다. 돌아 가기

이 있습니다 원래 %%%에

%%%

, 당신의 코드 문제 그러나 몇 첫째

:

@Reference(name="be.pxl.context", service=BundleContext.class) 
protected void setBundleContex(BundleContext context) { 
    this.context = context; 
} 

이 당신이 액세스하는 방법 아니다 번들에 대해 BundleContextBundleContext이 필요하면 주석 된 메소드에 매개 변수로 삽입해야합니다. A BundleContext은 결코 서비스로 등록되어서는 안됩니다 (OSGi 프레임 워크에 대한 귀하의 번들 개인 액세스를 나타냄). 귀하의 예제에서이 참조가 만족스럽지 않다는 사실을 알게되어 놀랄 일도 아닙니다. 당신은 실제로 필요하지 않은 BundleContext 그러나 둘째

... 이유는

@Activate 
public void run(Object object) { 
    System.out.println("IN SUBSCRIBER"); 
    System.out.println("\tIN RUN METHOD"); 
    String[] topics = new String[]{"event"}; 
    Dictionary props = new Hashtable(); 
    props.put(EventConstants.EVENT_TOPIC, topics); 
    System.out.println("\t\tCONTEXT: " + context); 
    context.registerService(EventHandler.class.getName(), this, props); 
    System.out.println("\t\tCONTEXT AFTER REGISTERSERVICE: " + context); 
} 

이는 activate 메소드를 작성하는 올바른 방법이 아니다 (그 결과가 호출되고되지 않을 수 있습니다) 여기에 서비스로 구성 요소를 등록 할 필요도 없습니다. 클래스를 @Component으로 만들면 직접 구현 된 각 인터페이스를 사용하여 서비스로 자동 등록됩니다. 이는 다음을 의미합니다 :

@Component(name = "be.pxl.Subscriber", immediate = true) 
public class Subscriber implements EventHandler { 
    ... 
} 

은 이미 OSGi EventHandler 서비스입니다!

@Component 주석을 사용하여 구성 요소에 서비스 등록 정보를 추가하거나 구성 요소 등록 정보 주석을 사용하여 OSGi R7 릴리스 (몇 달 만에)에서 서비스 등록 정보를 추가 할 수 있습니다. 이 경우는 다음과 같이 당신의 event.topics 속성을 설정하려면 : 만약 당신이 좋아하면 그런 다음 완전히 활성화 방법 제거 할 수

@Component(property="event.topics=event") 

. 마지막으로

:

이벤트 관리자는 메시지 큐 아니며, 게시자는 원샷 전송합니다. 따라서 게시자가 처리기가 완전히 등록되기 전에 이벤트를 보내면 절대로 이벤트를받지 못합니다. 게시자가 정기적 인 이벤트를 보내도록하거나 수신자가 게시자가 전에 메시지를 볼 수 있도록 을 시작하는지 확인하십시오.

P.

기술적으로 문제는 아니지만 maven-bundle-plugin 버전 2.4를 사용하고 있습니다. 이것은 이며 매우이며, 현재 릴리스 된 버전은 3.5입니다. Bnd 팀은 여러분이 보길 원하는 자신의 Maven 플러그인 (예 : bnd-maven-plugin)을 제공하기 시작했습니다.

+0

매우 도움이되는 설명에 감사드립니다. 하지만 Component Annotation으로 선언 한 속성을 사용하려면 어떻게해야합니까? 또한 구성 요소를 시작하려면 BundleActivator가 필요합니까? 이 데모의 목적은 구독자를 즉시 ​​시작한 다음 Apache Felix 컨테이너에서 게시자를 시작하고 게시자가 보낸 텍스트를 인쇄하는 것입니다. 또한 수신자가 게시자보다 먼저 시작하는지 어떻게 확인할 수 있습니까? 미리 감사드립니다. –

+0

** @Component로 선언 한 속성은 어떻게 사용합니까? ** 대답은 이미 선언하는 방법을 보여 주므로 질문은 이벤트 관리 항목과 관련 있다고 가정합니다. 나는 이것을위한 섹션을 추가했다. ** BundleActivator가 필요합니까? ** 확실히 아닙니다. 현대 OSGi 응용 프로그램에서 저수준 API를 사용할 이유가 거의 없기 때문에 사람들이 번들 활성화기를 작성하지 않는 것이 좋습니다. ** 수신자가 게시자보다 먼저 시작하는지 어떻게 확신 할 수 있습니까? ** gogo 쉘이 설치되어 있으면'scr : list' 및'scr : info' 명령을 사용하여 DS 구성 요소를 확인할 수 있습니다 –