📜 ⬆️ ⬇️

Interband interaction. Equinox for developer

Hello again! And again a lot of code as a tutorial. ;)

In OSGi, the notion of a bundle is basic. As follows from its purpose, a bundle, as a component of the system, from the moment of its launch is capable of living its own life and realizing any service functions.

In this post I want to tell you how bandls can communicate with each other.

There is, for example, a simple task, which is formulated as follows: “the background service in the workerbundle of the bundle does something called“ preworkfunction ”every 20 seconds, after he has done this, the handlerbundle bundle must find out about it and inform the executing bundle so that it runs “workfunction”.
')
But let's start not with it, but with a simpler one: there is a Reglterer bundle that must keep a registry of bundles inside it, which can be registered in it at the time of launch and deleted from the register at the time of stopping.

To solve this problem, we use the EventAdmin service, which is a queue for the exchange of events between bundles. To get started, we’ll write a Registerer activator bundle activator that will receive messages from other bundles.

The implementation of receiving messages

public class Activator implements BundleActivator { private Register mRegister; public void start(BundleContext context) throws Exception { mRegister = new Register(); /* *       . */ context.registerService(EventHandler.class.getName(), new ActivationEventHandler(mRegister), getHandlerServiceProperties( "ru/futurelink/app/web/usecase/Activator" )); /* *     */ Dictionary<String, Object> props = new Hashtable<String, Object>(); props.put("contextName", "app"); context.registerService(ApplicationConfiguration.class.getName(), new ApplicationConfig(mRegister), props ); } public void stop(BundleContext context) throws Exception {} protected Dictionary<String, Object> getHandlerServiceProperties(String... topics) { Dictionary<String, Object> result = new Hashtable<String, Object>(); result.put(EventConstants.EVENT_TOPIC, topics); return result; } } 


Here we register a service that processes messages with the subject “en / futurelink / app / web / usecase / Activator” (subscription to messages with such a topic). It is worth paying attention to the fact that messages with such a topic can be received by any bundle that is subscribed to it. Since by itself such a registry does not bear any benefit - it must be transferred further to where it will be used, to the RAP application service in this case. Therefore, we override ApplicationConfig from this post by adding a parameter to the constructor.

 public class ApplicationConfig implements ApplicationConfiguration { private Register mRegister; public ApplicationConfig(Register register) { mRegister = register; } } 


The class Register itself does not represent anything special in itself, its implementation is not important. Inside it may just be a collection of names of registered bundles, for example.

And this is the registry receiver's message handler:

 public class ActivationEventHandler implements EventHandler { private Register mRegister; public UseCaseActivationEventHandler(Register register) { mRegister = register; } @Override public void handleEvent(Event event) { String bundle = (String) event.getProperty("bundleName"); Integer activated = (Integer) event.getProperty("activated"); BundleContext context = (BundleContext)event.getProperty("bundleContext"); if (activated == 1) { mRegister.registerBundle(bundle, context); } else { mRegister.unregisterBundle(bundle); } } } 


This is where the implementation ends. When you receive a message with the above topic, a bundle will be registered, the name of which is sent in the bundleName parameter. If the parameter is activated == 1, then it is considered that the bundle must be added to the registry, otherwise - removed from there.

The implementation of sending messages

Let's make an activator of the bundle that will send messages about its start and stop.

 public class ClientActivator implements BundleActivator { private ServiceTracker mServiceTracker; private EventAdmin mEventAdmin; private Logger mLogger; private String mBundleName; public ClientActivator() {} public void addUsecase(UseCaseInfo info) { mBundleName = info.getBundleName(); } @Override public void start(BundleContext context) throws Exception { mServiceTracker = new ServiceTracker( context, EventAdmin.class.getName(), null); mServiceTracker.open(); mEventAdmin = (EventAdmin) mServiceTracker.getService(); postActivationEvent(context); } @Override public void stop(BundleContext context) throws Exception { postDeactivationEvent(context); } private void postActivationEvent(BundleContext context) { if (mEventAdmin != null) { //     Dictionary<String, Object> props = new Hashtable<String, Object>(); props.put("bundleName", mBundleName); props.put("bundleContext", context); props.put("activated", 1); mEventAdmin.postEvent( new Event("ru/futurelink/app/web/usecase/Activator", props)); } else { mLogger.error("Cannot get to EventAdmin service!"); } } private void postDeactivationEvent(BundleContext context) { if (mEventAdmin != null) { Dictionary<String, Object> props = new Hashtable<String, Object>(); props.put("bundleName", mBundleName); props.put("activated", 0); mEventAdmin.postEvent( new Event("ru/futurelink/app/web/usecase/Activator", props)); mServiceTracker.close(); } else { System.out.println("Cannot get to EventAdmin service!"); } } protected Dictionary<String, Object> getHandlerServiceProperties(String... topics) { Dictionary<String, Object> result = new Hashtable<String, Object>(); result.put(EventConstants.EVENT_TOPIC, topics); return result; } } 


What's going on here? When the bundle is activated, we get the object of the EventAdmin service, which must, of course, be launched in the system. If it is not running - mEventAdmin == null. Well, then according to the logic of the task - we send a message about the start and stop of our bundle.

What does this apply for me? After stopping the bundle, I want the functionality of the module that is implemented in it to be instantly disabled and unavailable. No errors, exceptions - just turn off a piece of the site and notify the user that this part is currently unavailable when he tries to use it. As well as disabling any associated with this bandle funkiotsnala. The main application should be aware of the state of its modules, but it should not be dependent on them, and in this case it only knows what they tell it through the event.

By the way, you also need to note that the context of the bundle is also transmitted in the message.

Implementing a background service that can communicate with a colleague and tell him about his condition through EventAdmin, given the above, is already a trivial task.

I really want questions and additions on the topic ...;)

Source: https://habr.com/ru/post/179675/


All Articles