Why does the ConfigurationAdmin specification use its own eventing mechanism, as opposed to the EventAdmin? - osgi

I want to understand why the ConfigurationAdmin specification defines its own mechanism for dispatching events, instead of using the EventAdmin specification, which is also defined in the OSGi Compendium.
The ConfigurationAdmin specification mentions that it will send ConfigurationEvents to ConfigurationListeners registered in the service registry.
Listener for Configuration Events. When a ConfigurationEvent is fired, it is asynchronously delivered
to all ConfigurationListeners.
ConfigurationListener objects are registered with the Framework service registry and are notified
with a ConfigurationEvent object when an event is fired.
ConfigurationListener objects can inspect the received ConfigurationEvent.
This seems like it would be a fine candidate for the EventAdmin, given that the properties of the ConfigurationEvent are all primitive.
val event: Event = Event(Hashtable(mapOf<String, Any>(
"type" to CM_UPDATED,
"service.factoryPid" to "someFactoryPid.guid",
"service.pid" to "somePid.guid"
)))
#Component
class ConfigurationListener : EventHandler {
override fun handleEvent(event: Event) {
// ...
}
}
I'm designing some services which would make use of some sort of event handling mechanism. The choices I think I have are using the EventAdmin (provided in the Compendium), and rolling my own (like the ConfigurationAdmin).
I'd like to know what design decision was made that led the OSGi Alliance to create a separate event mechanism for the ConfigurationAdmin, instead of the already created event mechanism, provided by the EventAdmin, and if I need to consider the same factors when selecting my event mechanism.
It seems like duplicated work.
The EventAdmin can send events synchronously or asynchronously (sendEvent and postEvent), and already provides an interface to responding to events (EventHandler).
The ConfigurationAdmin sends ConfigurationEvents asynchronously or synchronously depending on the the interface used to respond to the event(ConfigurationListener, SynchronousConfigurationListener), rather than the method called.
One possibility I'd considered was that the OSGi Alliance didn't want to make the services defined in the Compendium, depend on other Compendium services, based on the fact that the ConfigurationAdmin has no problem depending on the Service registry, which is defined in Core.
This seems to line up in my mind with the understanding that services are not guaranteed to exist at runtime; therefore making ConfigurationAdmin depend on EventAdmin would equate to "You cannot use this optional service (ConfigurationAdmin) unless this other optional service (EventAdmin) is guaranteed to be in the runtime as well" which is kind of contradictory.

There are several reasons:
Configuration Admin was designed before Event Admin
A type safe event interface like Configuration Admin is easier to use than using properties
As you figured out, it is not nice if services depend on each other. Implementations should be able to freely chose services and not be artificially constrained.

Related

Handling expected exceptions from dao

I am currently coding a spring-mvc (jsp) project with three layers (controller -> service -> dao) and I am wondering what is the correct way of handling expected exceptions from dao invocations (e.g trying to persist an User that already exists, if it exists then call the register view again with a message saying that the user already exists), at first I thought it would be a good idea to catch the exception in the dao (e.g DataIntegrityViolationException) and throw my arbitrary checked exception so then I can do an exception handler for it in the controller but I fear if I do this then I might have conflicts if I want to make my service methods #Transactional later on since spring won't know how to rollback the transaction.
If this is correct then I have two ideas:
try/catch DataAccessException in the controller when I invoke the service call userService.register(..)
Use something among the lines like userService.findByUsername(username) in the controller (which returns an Optional) and if its present I notify the user before even calling userService.register(..)
Also, our teacher emphasizes on following DDD behavior and trying to avoid leaking business logic in our controllers and I fear both of this solutions do that but I don't really know how to handle it otherwise.
Spring already converts checked JDBC exceptions into more informative unchecked exceptions, which play well with service layer transactions. All your custom checked exceptions do is force you to type more. Spring gives you reasonable defaults, take advantage of them.
Create an exception handler. Spring has multiple ways to implement this, none of them involve writing catch blocks for exceptions in your controller.
Put the business logic in the service, not the controller. It seems like your findByUsername and register can be combined in one transactional service method.

Spring Cloud Bus - Custom Event Received but not handled by Event Handler

I am using Spring Cloud Bus (1.2.1.RELEASE, Camden.SR2). I have a custom event (call it CustomEvent) that I have created and registered via #RemoteApplicationEventScan as well as a custom AbstractBusEndpoint implementation to publish the event. I am able to publish events to the bus just fine.
My remote application receives the event and acknowledges (I verified this using the trace endpoint). I have verified via debugging that the CustomEvent is published via the ApplicationEventPublisher provided in BusAutoConfiguration#acceptRemote. I have a bean with an event handler in my remote application (I have this auto-configured into all of my micro-services):
#Component
public class EventListener {
#EventHandler(CustomEvent.class)
public void handleCustomEvent(CustomEvent event) {
..
}
}
Despite this, the event handler will not receive the event. I traced within the AbstractApplicationEventMulticaster class and despite my bean being created (verified via beans endpoint), the listener is not in the list of ApplicationListeners retrieved by ListenerRetriever. I do see the BusAutoConfiguration.acceptLocal listener in this list, but not my custom listener.
This event handler is also registered on the source application (the one I am accessing the bus endpoint from to initiate the event). The custom listener receives the event in this application, but not the remote application.
Essentially, both applications are configured the exact same except one is configured to send the CustomEvent using an implementation of AbstractBusEndpoint.
I am out of ideas of where else to look within the Spring code to debug this problem. If anyone has a thread they can lead me on it would be appreciated.
I've come up with the exact same problem, and debugging it revealed that ApplicationListener which handles the custom remote event not returned among candidate listeners within ApplicationEventMulticaster due to eventType was loaded by two different classloaders, one of them was devtools related classloader. Removing devtools dependency from classpath simply resolved issue for me.

Where should i store thread dependent data within a receiving rabbitListener component in a multithreaded environment?

I'm using the annotation based approach of spring amqp in a multithreaded environment (i have multiple consumers => multiple rabbit listener containers).
#RabbitListener(queues = "tasks")
public void receiveMessage(#Payload Task task) {
// usage of httpClient here with its own httpContext (would be fine)
// this method gets called from different listenerContainers / threads
}
My component which contains the annotated receiveMessage() method needs to do some http calls with the apache http client. Since i'm working with multiple consumers at the same time, this method gets called from different threads and the apache http client documentation says that i should create a httpContext for each thread to be thread safe. Since all threads are calling the same component method i can't put the httpContext into the component.
Is there something like a listener container context for each listener container where i can put the httpClientContext? Or does somebody have an idea how to solve this easy? I thought about ThreadLocal or a central registry for httpContexts but it would be fine if this would be more easy.
There is nothing like that provided by the framework; the simplest solution is to store them in something like a LinkedBlockingQueue and check one out, use it, and put it back in the queue when you're done (creating one as necessary if the queue is empty).
ThreadLocal will work too, but I prefer to use a pool.

OSGi 'await for listeners to subscribe'

Let say I have kinda EventGenerator service in bundle A and Processors (listeners) in bundles B and C.
A knows nothing about B and C, where Processors make subscriptions for EventGenerator events on initialization.
There could be created more listeners in other bundles D, E etc.
In spring application I would do subscription while constructing Processor, passing EventGenerator as a constructor argument. I would have B and C logically dependent from A. On #PostConstruct I would have working system, ready to process events.
How could I initialize A, B and C as an OSGi application? I'm facing problem when EventGenerator starts to work and Processors miss events, because they are not yet initialized and subscribe for them.
What you are trying to achieve is not possible in OSGi. The reason is that you cannot know at the time of deploying the bundle of EventGenerator, what bundle deployment events will happen and in which order.
In Spring everything is deployed at the same time therefore it can be analyzed, which beans implement the Processor interface.
There are a couple of workarounds, you must choose the one that is the best for you.
LogService
You can find the Log Service chapter in the OSGi specification. LogListener implementations can be registered as OSGi service. The LogService implementation picks up every LogListener service and sends every LogEvents for them.
The issue here is that a LogListener might be registered after that a LogEvent is already occured.
A solution here is to tell how many records should be memorized by LogService and if a LogListener is registered, send the last X events first. As much as I remember, the default setting of Equinox LogService is that it remembers the last 100 LogEvents.
BundleTracker-like events
The speciality of BundleTracker events are that the number of active events are limited. After an event is not relevant anymore, it is deleted. In practice:
Until a Bundle is in the container, the last event of the bundle is stored and processed by every newly opened BundleTracker
When a Bundle is marked for deletion, its last event is removed
In case you have events like this, you can implement the same approach. It is not easy to implement it. There is an library I implemented and makes the job easier. You need to implement some interfaces and define your types via Generics and you will have the necessary event management functionality: https://github.com/everit-org/eventdispatcher
Wait for all Processors before starting EventGenerator
In case non of the previous solutions work for you, you must tell somehow the EventGenerator component not to register its OSGi service until all Processors are picked up.
In my opinion, the best way if you make this configurable via ConfigAdmin. By doing that, you will be able to re-configure your EventGenerator component via the CommandLine Console or WebConsole without restarting your system.
I implemented a Component Model to have this functionality. Your component would look like the following:
import org.everit.osgi.ecm.annotation.Component;
import org.everit.osgi.ecm.annotation.Service;
import org.everit.osgi.ecm.annotation.ServiceRef;
import org.everit.osgi.ecm.extender.ECMExtenderConstants
import aQute.bnd.annotation.headers.ProvideCapability;
#Component
#Service
#ProvideCapability(ns = ECMExtenderConstants.CAPABILITY_NS_COMPONENT,
value = ECMExtenderConstants.CAPABILITY_ATTR_CLASS + "=${#class}")
public class EventGenerator {
private Processor[] processors;
#ServiceRef
public void setProcessors(Processor[] processors) {
this.processors = processors;
}
}
You can specify the necessary Processor OSGi services with an array of OSGi filters at the processors.target attribute of the component. The Component will start and it will be registered as a service after all processors are available.
To make the sameple above work, you must drop the following dependency (with their transitive dependencies, less than 200k) into your OSGi container:
<dependency>
<groupId>org.everit.osgi</groupId>
<artifactId>org.everit.osgi.ecm.extender.ri</artifactId>
<version>1.0.0</version>
</dependency>
There is a WebConsole plugin as well that shows the state of your component (why it is unsatisfied or failed):
<dependency>
<groupId>org.everit.osgi</groupId>
<artifactId>org.everit.osgi.ecm.component.webconsole</artifactId>
<version>1.0.0</version>
</dependency>

ServiceTracker and DS combined?

Let's imagine a bundle in which exists:
A component is responsible of listen all "Device" service instances in the service registry.
The same component needs an "adaptor factory" in order to create "Adaptors" by using the discovered devices.
The factory is owned by another bundle.
I can solve part of the problem by using a ServiceTracker (Activator + Service Tracker): the activator instantiates the ServiceTraker and it can register all changes in "Device" services.
But i can't inject to this service tracker the DS factory created in other bundle, because it will result in two instances (one created by activator AND without the member /// another created by osgi AND with member variable ok but can't listen the "Device" service changes).
So... how can i solve this scenario? How can i have a Service Tracker (perfect for me) with a DS as a class member?
Use no Activator, instead use a component or service (we will call it A) with a declarative services 'activate(ComponentContext)' method. Within the activate method, you can instantiate your ServiceTracker like normal.
When you instantiate the ServiceTracker within A's activate method, you can also pass in the AdapterFactory into the ServiceTracker. You can get the AdapterFactory by pulling it out of the BundleContext taken from ComponentContext or (even better) use DS and make it a service reference to your A component.
That said: why do you need ServiceTracker for this? Unless I misunderstand, you can use DS bind and unbind to receive events on the availability of a Service.
EDIT: An (OLD) example of Bind/Unbind behavior using multiple cardinality: http://blog.tfd.co.uk/2009/11/12/declarative-optional-multiple-references-flaky-in-osgi/
EDIT: A comparision of the two approaches but doesn't go into bind/unbind so much: http://njbartlett.name/2010/08/05/when-servicetrackers-trump-ds.html
EDIT2: That said: my general policy is to not use an Activator except in super rare cases. Use DS, ipojo, etc and use the components you define with those techs in order get access to the BundleContext to build more low level objects like ServiceTrackers.

Resources