Ich entwickle eine Anwendung in Eclipse RCP. Ich brauche Hilfe bei einer Designentscheidung über die Gestaltung eines Service.OSGi-Services-Architektur: Erstellung von Service auf Anfrage des Verbrauchers
Ich habe einige Bündel, die verwendet werden, um ein REngine
Objekt für andere Module bereitzustellen. Die REngine
ist eine Schnittstelle zu einer Berechnungsmaschine, die auf mehrere Arten implementiert werden kann. Die Bundles stellen Instanzen von REngine bereit, indem sie eine Verbindung zu einem Remote-Server herstellen oder einen lokalen Berechnungsthread starten. Einige Bundles erfordern eine Konfiguration durch die GUI (müssen aber auch auf einer kopflosen Plattform verfügbar sein). Ein Client-Paket kann mehrere REngine
Objekte für parallele Berechnungen anfordern.
Ich registriere diese Module derzeit, um einen REngine
Service zur Verfügung zu stellen. Der Service wird von einer ServiceFactory erstellt, die entweder eine lokale Berechnungsinstanz oder eine Remote-Instanz (Server) startet. Der Kunde ist dafür verantwortlich, alle Service-Registrierungen der Klasse REngine
auszuprobieren und die richtige auszuwählen.
Der Code, dies zu tun, kann wie folgt zusammengefasst werden:
class API.REngine { ... }
class REngineProvider.Activator {
public void start(BundleContext ctx) {
ctx.registerService(REngine.class.getName(), new REngineFactory(), null);
}
}
class REngineProvider.REngineFactory implements ServiceFactory {
public Object getService(Bundle bundle, ServiceReference reference) {
return new MyREngineImplementation();
}
public void ungetService(REngine service) {
service.releaseAssociatedResources();
}
}
class RConsumer.Class {
REngine getREngine() {
ServiceReference[] references = bundleContext.getAllServiceReferences(REngine.class.getName(), null);
for(ServiceReference ref: references) {
try {
return bundleContext.getService(ref);
} catch (Exception e) {} // too bad, try the next one
}
}
}
ich dieses Modell halten möchten. Es ist schön, dass die OSGi-Dienstespezifikation mit meiner Geschäftsanforderung übereinstimmt, dass REngine-Objekte lebende Objekte sind, die freigegeben werden sollten, wenn sie nicht mehr benötigt werden.
Ein registrierter Dienst kann jedoch nur eine Serviceinstanz pro Bündel bereitstellen. Wenn der Dienst das zweite Mal angefordert wird, wird eine zwischengespeicherte Instanz zurückgegeben (anstatt eine neue Instanz zu erstellen). Dies entspricht nicht meiner Anforderung; Ein Bundle sollte mehrere REngine-Objekte vom selben Provider erhalten können.
Ich habe bereits andere OSGi-Framework-Klassen betrachtet, aber nichts scheint zu helfen. Die Alternative ist das Whiteboard-Modell, aber es scheint seltsam, einen REngineRequestService zu registrieren, der vom REngineProvider-Bundle verwendet wird, um eine Live-REngine auszugeben.
Wie implementiere ich das in OSGi? Zur Erinnerung, hier ist meine Liste der Anforderungen:
- Einfache Aktivierung und Deaktivierung von
REngineProvider
Bundles. Client-Code verwendet stattdessen nur einen anderen Anbieter. - Konfiguration der REngineProvider-Bundles.
- Mehrere
REngine
Instanzen pro Client-Bundle. - Explizite Freigabe von
REngine
Instanzen REngine
Erstellung kann fehlschlagen. Das Client-Modul sollte den Grund dafür kennen.
einfach die Lösung, die wir als zukünftige Referenz gewählt haben, hinzuzufügen. Es scheint, dass die OSGi Services-Plattform nicht dafür ausgelegt ist, "einen Dienst anzufordern". Es ist das Provider-Paket, das einen Service erstellt, und das Client-Paket, das die Services finden und verwenden kann. Es ist nicht möglich, eine automatische "Factory" für Dienste pro Benutzeranforderung bereitzustellen.
Die gewählte Lösung umfasst die OSGi whiteboard model. Auf den ersten Blick scheint dies sehr schwierig zu sein, aber Blueprint
kann viel helfen!
Anbieter Blaupause.XML-Datei:
<reference-list interface="org.application.REngineRequest"
availability="optional">
<reference-listener
bind-method="bind" unbind-method="unbind">
<bean class="org.provider.REngineProvider"/>
</reference-listener>
Die Klasse REngineRequest
ist eine gemeinsame API-Klasse ermöglicht den Provider zur Eingabe seines REngine Objekt oder eine Ausnahme zu erklären, warum die Schöpfung nicht funktioniert hat.
Für den Kunden ist es, ein REngine mit jetzt so einfach wie zu tun:
REngineRequest req = new REngineRequest();
ServiceRegistration reg = bundleContext.registerService(req, REngineRequest.class.getName(), engineCreationProperties);
req.getEngine().doSomeStuff();
reg.unregister();
Wir davon ausgehen, dass sich der Anbieter wird nie aufhören, während der Client die REngine verwendet. Wenn dies der Fall ist, wird REngine
ungültig.
Würden Sie BluePrint und die PROTOTYPE-Anmerkung anstelle von DS empfehlen? Es fällt mir schwer, den Unterschied zu sehen. – parasietje
Ich wollte Blueprint und den Prototypbereich vorschlagen. Blueprint hat mehr Knöpfe als deklarative Dienste, die Ihnen hier nützlich sein können. –
Leider brauche ich den Kontext (Eigenschaften) bei der Erstellung meines Objekts. Es ist ein großer Fehler, dass ich keine einfache Factory-Methode angeben kann, sondern eine Klasse angeben muss, die instanziiert wird. Hoffen wir, dass Blueprint so etwas hat! – parasietje