2016-04-29 17 views
1

Ich spiele mit OSGi DS-Komponenten und dem ConfigurationAdmin herum.OSGi ändern Ereignismethode nicht aufgerufen

habe ich eine einfache konfigurierbare Komponente

@Component(service=ConfigurableService.class) 
public class ConfigurableService { 

    private String message; 

    @Activate 
    public void activate(Map<String, Object> params) { 
    System.out.println("Activate configurable"); 
    message = (String) params.get("msg"); 
    } 

    @Modified 
    public void modified(Map<String, Object> params) { 
    System.out.println("Modify configurable"); 
    message = (String) params.get("msg"); 
    } 

    @Deactivate 
    public void deactivate(Map<String, Object> params) { 
    System.out.println("Deactivate configurable"); 
    message = (String) params.get("msg"); 
    } 

    public void execute() { 
    System.out.println("Service says: " + message); 
    } 
} 

Dann einen Felix Gogo Shell-Befehl Komponente I geschaffen, um die Konfiguration über ConfigurationAdmin

@Component(property = { 
    CommandProcessor.COMMAND_SCOPE + "=fipro", 
    CommandProcessor.COMMAND_FUNCTION + "=configure" 
}, 
service = ConfigurationCommand.class 
) 
public class ConfigurationCommand { 

    private ConfigurationAdmin cm; 

    @Reference(unbind="-") 
    public void setConfigAdmin(ConfigurationAdmin cm) { 
    this.cm = cm; 
    } 

    public void configure(String input) throws IOException { 
    Configuration config = cm.getConfiguration("org.fipro.osgi.config.ConfigurableService"); 
    Hashtable<String, Object> props = new Hashtable<>(); 
    props.put("msg", input); 
    config.update(props); 
    } 
} 

Und schließlich triggern I erstellt einen anderen Felix Gogo Shell-Befehl Komponente das macht Gebrauch von ConfigurableService

@Component(property = { 
    CommandProcessor.COMMAND_SCOPE + "=fipro", 
    CommandProcessor.COMMAND_FUNCTION + "=welcome" 
}, 
service = WelcomeCommand.class 
) 
public class WelcomeCommand { 

    private ConfigurableService service; 

    @Reference(unbind="-") 
    public void setConfigurable(ConfigurableService service) { 
    this.service = service; 
    } 

    public void updatedConfigurable(ConfigurableService service, Map<String, Object> properties) { 
    System.out.println("ConfigurableService updated"); 
    } 

    public void welcome() { 
    service.execute(); 
    } 
} 

Wenn ich eine OSGi-Anwendung mit den Bundles starte, die diese Komponenten enthalten, erwarte ich bei der ersten Ausführung von , dass die Komponente aktiviert ist und die Dienstausgabe null ist, weil noch keine Konfiguration angewendet wurde (sicher, dass sich diese fortlaufend ändert) Anrufe). Wenn ich danach configure Dirk ausführe, erwarte ich, dass die mit @Modified annotierte Methode ausgeführt wird, um anzuzeigen, dass die Dienstkonfiguration aktualisiert wurde. Ich erwarte auch, dass die updatedConfigurable Methode in der WelcomeCommand ausgeführt wird. Zumindest verstehe ich das aus dem Lesen der Spezifikation.

Jetzt beobachte ich unterschiedliches Verhalten in Equinox und Felix.

Equinox:

Die modifizierte Methode aufgerufen wird, wie erwartet, und die ConfigurableService richtig konfiguriert ist. Aber die updatedConfigurable(<Service>, <Map>) wird nicht aufgerufen. Nur wenn ich die Methodensignatur ändere, um eine ServiceReference zu nehmen, wird die aktualisierte Methode aufgerufen.

Die Spezifikation sagt, dass alle Referenzereignis Verfahren die folgenden Verfahrens Signaturen unterstützen

void <method-name>(ServiceReference); 
void <method-name>(<parameter-type>); 
void <method-name>(<parameter-type>, Map); 

Gibt es eine Ausnahme für die aktualisierte Methode, die ich nicht in der Spezifikation gesehen haben oder ist dies ein Problem in Equinox, wo ich sollte ein Ticket für?

Felix:

Wenn ich das gleiche Beispiel auf Felix in Bndtools laufen, weder verändert noch die Update-Methoden aufgerufen. Ich habe die ConfigurationCommand überprüft und es ist ein ConfigurationAdmin verfügbar, so gibt es keine Ausnahme beim Aktualisieren der Konfiguration. Aber es wird nie irgendwie angewendet.

Fehle ich etwas am Ausführen des Beispiels auf Felix?

Update:

Konsole Hinzufügen Ausgänge zu jedem Lifecycle Event-Methode erstellt die folgende Ausgabe:

____________________________ 
Welcome to Apache Felix Gogo 

g! ConfigurationCommand: Activate 
ConfigurableService: Activate 
WelcomeCommand: Activate 
welcome 
Service says: null 
g! configure Dirk 
g! welcome 
Service says: null 
g! exit 0 
WelcomeCommand: Deactivate 
ConfigurableService: Deactivate 
ConfigurationCommand: Deactivate 

Wie Sie sehen können, werden die ändern und aktualisiert Ereignisse nie aufgerufen.

Antwort

2

Ich denke, das Problem ist der Lebenszyklus für Gogo-Befehle.

Gogo hält Objekte nicht an, während ein Befehl nicht ausgeführt wird. Es verfolgt die ServiceReference aber ruft getService nicht auf, bis Sie tatsächlich den welcome Befehl aufrufen. Wenn Sie aufrufen, wird daher die WelcomeCommand Komponente instanziiert, die die Instanziierung des ConfigurableService zu dieser Zeit erzwingt.

Später, wenn der welcome Befehl abgeschlossen ist, wird die WelcomeCommand freigegeben, damit beide WelcomeCommand und ConfigurableService wird GC'd werden. Daher lebt keine Instanz von ConfigurableService jemals lange genug, um das Modified-Ereignis zu erhalten.

dies zu beheben, versuchen WelcomeCommandsofort machen:

@Component(immediate = true, ...) 

UPDATE

Bei der weiteren Diskussion mit Dirk über E-Mail, stellt sich heraus, dass das Problem Lage Bindung ist. In Config Admin sind Konfigurationen standardmäßig an das Paket gebunden, das sie erstellt, in diesem Fall das Paket, das ConfigurationCommand enthält. Sobald sie gebunden sind, können sie nicht von einem anderen Bündel konsumiert werden, so dass die ConfigurableService niemals die Konfiguration sieht.

Um eine ungebundene Konfiguration zu erstellen, die von einem beliebigen Bundle verwendet werden kann, rufen Sie die Zwei-Arg-Version ConfigAdmin.getConfiguration() auf und übergeben Sie für das zweite Argument null.

+0

Nein, das löst das Problem auf Felix nicht. –

+0

Können Sie (mit den Befehlen 'scr: list' und' scr: info') überprüfen, ob der ConfigurableService tatsächlich aktiv ist und eine Instanz existiert. Bitte entfernen Sie auch das 'unbind =" - "' Zeug, es wird nicht benötigt und ich weiß nicht, welche Nebenwirkungen es haben könnte. –

+0

Ich habe das Attribut "unbind =" - "' entfernt. Ich habe es nur hinzugefügt, weil die Spezifikation sagt, dass es notwendig ist, explizit zu sagen, dass es keine Methode zum Lösen gibt. Die neue DS-Annotation-Unterstützung in Neon beschwert sich anders. Für Felix bin ich nach Bndtools umgezogen und es gibt kein Problem mit einer fehlenden Entbindungsmethode. Trotzdem ändert es nichts. Mit 'scr: list' und' scr: info' wird angezeigt, dass der 'ConfigurableService' aktiv ist (' State: active'). Für mich sieht alles gut aus. Gibt es etwas Besonderes, wonach ich suchen sollte? –