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.
Related
I have an interface which I have implemented. I have annoted the impl with #Component and #Service of the package org.apache.felix.scr.annotations.
I wrote a simple constructor for my impl
public MyImpl(){
LOG.info("New instance created!!");
}
I also added loggers in #activate and #deactivate method.
I expected to see "New instance created!!" only once BUT I can see activate and deactivate method being called per request I make on a page(This service is invoked by A Sling Model which is used in that page)
What I saw was "New instance created!!" logged several times.
This means the OSGi container create multiple instances of my Service and called the activate and deactivate method every time.
This shows that this is not a Singleton.
The Object should be discarded only when I uninstall my bundle.
Please help me understand what is going on here.
I WANT TO IMPLEMENT A TRUE SINGLETON IN AEM
I have implemented this in AEM 6.5 instance which uses Apache Felix.
Edit:
Adding Service properties:
aemRootUrl http://localhost:8080
api.http.connections_manager.timeout 60000
api.http.cookie_max.age 18000
api.http.max_connections 200
api.http.max_connections_per_host 20
api.http.timeout.connection 300000
api.http.timeout.socket 300000
api.server.ssl.trust_all_certs true
api.server.url https://10asdasdsad
api.server.username admin
component.id 3925
component.name com.example.foundation.core.connection.impl.HybrisConnectionImpl
non_akamai.api.server.url hadasdadasd
service.bundleid 585
Service PID com.example.foundation.core.connection.impl.HybrisConnectionImpl
service.scope bundle
Using Bundles com.example.dumb-foundation.core (585)
Values altered to hide client specific information
EDIT::
I've removed the SCR annotations and replaced them with OSGI annotations here I've explictly specified
#Component(service =HybrisConnection.class, immediate=true,scope = ServiceScope.SINGLETON)
But still is shows as scope=bundle.
Should I enforce Singleton and OSGi annotations on it's dependencies as well for this to be a proper Singleton?
In declarative services (which is what you use behind the scenes) there are some cases when a component (and its service) is unpublished.
By default a simple component with immediate=true will come up when the bundle starts and go down when it stops.
If your component has any mandatory service dependencies (#Reference) then it will only be active while all dependencies are present. So if at least one dependent service goes away the component will be deactivated.
In addition the component might get restarted when config is not present at start but added later. If you want to avoid this make the config required.
Every thing #Christian Schneider said is true.
They AEM services are Singletons but are deactivated/unpublished at times. This might be for various reasons.
I faced a horrible issue because of ConfigurationAdmin service. Using this services caused our OSGi config files to be bound to the wrong bundle i.e. SlingModels. bundle within AEM.
the only way to access this is by getting the service using configAdmin.getConfig(PID).setBundleLocation(null);
BUT Doing this causes the service that is linked to this configuration to restart.
So every time I did config.setBundleLocation(null) the service restarted.
The best and most awesome way to resolve this is use OCD to define configuration for OSGi Services linked to OSGi config.xmls
AND NEVER EVER EVER use configuration Admin
If you want to access properties of another service Say ServiceA want to read ServiceB's title property set in com.example.serivce.impl.ServiceB.xml
Then in ServiceB in the #activate method read the props from OCD config and set it in instance level and have ServiceA inject ServiceB as it's dependency and use the property needed.
eg.
class ServiceA{
#Reference
private ServiceB serviceB;
public void someMethod(){
serviceB.getTitle(); // Successfully read property of another service i.e.
ServiceB without using ConfigurationAdmin.
}
}
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.
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>
I'm refactoring one of my controller to make it a service and I want to know if there is a performance impact to not inject whole service container into my controller.
Is this is more efficient :
innova.path.controller:
class: %innova.controller.path.class%
arguments:
entityManager: #doctrine.orm.entity_manager
session: #session
securityContext: #security.context
router: #router
translator: #translator
pathManager: #innova.manager.path_manager
calls:
- [setRequest, ["#?request="]]
scope: request
than this, for example ?
innova.path.controller:
class: %innova.controller.path.class%
arguments: [#service_container]
Official documentation explicitly tell to not inject whole DIC into a Controller (thanks #NHG for link).
Section How to work with scopes :
Injecting the whole container into a service is generally not a good
idea (only inject what you need).
But in section Service container :
When you ask for the my_mailer service from the container, the
container constructs the object and returns it. This is another major
advantage of using the service container. Namely, a service is never
constructed until it's needed. If you define a service and never use
it on a request, the service is never created. This saves memory and
increases the speed of your application. This also means that there's
very little or no performance hit for defining lots of services.
Services that are never used are never constructed.
So injecting the whole DIC to controller will not have performances impact because only the services used in controller are instanciated.
The idea of using controllers as service is injecting only necessery services. Standard controller extends Symfony\Bundle\FrameworkBundle\Controller\Controller which extending Symfony\Component\DependencyInjection\ContainerAware. So, injecting whole container is makes no sense...
Generally, injecting less service is more efficient than injecting whole container.
Additionally you should familiarize with base Symfony2 Controller class.
I have an interface that has two implementations. I want to expose both implementations as OSGi services, but when I am doing that one overrides the other. Please find the configuration that I am doing:
<bean id="formService" class="com.dbt.form.service.FormService"/>
<bean id="formAPIService" class="com.dbt.form.service.FormAPIService"/>
<osgi:service
ref="formAPIService"
interface="com.dbt.form.service.ifc.IFormService"/>
<osgi:service
ref="formService"
interface="com.dbt.form.service.ifc.IFormService" />
Here formService is overriden by formAPIService implementation.
Please help me on how to sort out this issue.
The second service does NOT override the first... both of these services will be published separately, and you can confirm this by typing the inpect cap service command in the OSGi Gogo shell.
What MAY happen is that your consumer code will only choose one of the available service instances. In this case you need to write your consumer to either bind to all instances, or use a combinations of rankings or target filters to determine which particular service you want. You should give more information on how you are using these services since that is where the problem lies (probably).
Read this page...Chapter 8. The Service Registry section 8.2.2.3.
You can use bean-name attribute of osgi reference tag. While importing a service bean-name refers to the id attribute of that service when its exported.