I need to register multiple services from one bundle, I think I cannot use service factory because I have only one bundle that consumes services
put in another way, I have a bundle which represent a physical device(e.g temperature sensor) ,since I have multiple physical device (e.g 10 temperature sensors, each has a unique ID) then I need to have multiple (10) instances of my service from the same bundle, How can I do that ?
Multiple instances of the service can be registered simply through repeated calls to context.registerService(). Each registration can carry a distinct set of properties, for example:
Properties props1 = new Properties();
props1.put("my_id", "ID1");
context.registerService(Foo.class.getName(), new FooImpl(), props1);
// ...
Properties props2 = new Properties();
props2.put("my_id", "ID2");
context.registerService(Foo.class.getName(), new FooImpl(), props2);
// ...
(Note a terminology quibble that may save you some confusion. Bundles do not register themselves as services. They create Objects and register those as service. A bundle is a deployment unit or a container for executable code. Bundles can register zero to many services, and/or consume the services registered by other bundles.)
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.
I have a web app running in Tomcat correctly that I want to run on the new OpenLiberty server, the app is starting correctly inside OpenLiberty but at the moment of the database connection initiation is throwing the following exception:
[Default Executor-thread-15] 2018-03-15 15:02:30 ERROR TomcatConnectionManager:41 - Loading jdbc/mysql/myaap failure
javax.naming.NameNotFoundException: java:/comp/env
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLName.<init>(JavaURLName.java:83)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLNameParser.parse(JavaURLNameParser.java:39)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLNameParser.parse(JavaURLNameParser.java:60)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext$NameUtil.<init>(JavaURLContext.java:474)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext.lookup(JavaURLContext.java:321)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext.lookup(JavaURLContext.java:370)
at org.apache.aries.jndi.DelegateContext.lookup(DelegateContext.java:161)
The above exception is thrown during the lookup phase:
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
Is there any way to make it work on OpenLiberty doing less changes possible?
On OpenLiberty the equivalent lookup would look like this:
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:comp/env");
The key is that you need to use java:comp/... instead of java:/comp/...
The reason why Tomcat is different than Liberty is because Tomcat is just a servlet container and Liberty conforms to the full Java EE specification.
According to section EE.5.2.2 of the Java EE 7 spec:
The application component’s naming environment is composed of four logical
namespaces, representing naming environments with different scopes. The four
namespaces are:
java:comp – Names in this namespace are per-component (for example, per enterprise
bean). Except for components in a web module, each component gets
its own java:comp namespace, not shared with any other component. Components
in a web module do not have their own private component namespace.
See note below.
java:module – Names in this namespace are shared by all components in a
module (for example, all enterprise beans in a single EJB module, or all components
in a web module).
java:app – Names in this namespace are shared by all components in all modules
in a single application, where “single application” means a single deployment
unit, such as a single ear file, a single module deployed standalone, etc.
For example, a war file and an EJB jar file in the same ear file would both have
access to resources in the java:app namespace.
java:global – Names in this namespace are shared by all applications deployed
in an application server instance. Note that an application server instance
may represent a single server, a cluster of servers, an administrative
domain containing many servers, or even more. The scope of an application
server instance is product-dependent, but it must be possible to deploy multiple
applications to a single application server instance.
Had a similar problem going between WebSphere and Tomcat. I'm developing and testing on a Tomcat server and using utilities I can't change that handle the DB connection to our DB2. On WebSphere it uses a constant set to "jdbc/COMPDB2" to retrieve the DataSource when I configure Tomcat and my Web.xml file it resolves to "java:comp/env/jdbc/SFCCDB2"
My work around for on local work space it to add a listener to copy the resource to the level in the InitialContext. I'm not very experienced with the server side of things but this is working so far using TomEE 7.0.81.
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/SFCCDB2");
javax.naming.Context envCtx = (javax.naming.Context) ctx.lookup("java:comp/env");
try{
/*
Added this because after redeploying code to the server it would error
connecting to the DB with an SQLException Datasource is closed
*/
DataSource dataSource = (DataSource) ctx.lookup("jdbc/COMPDB2");
ctx.destroySubcontext("jdbc");
} catch (NamingException e){
//Doesn't exist; safe to just add
}
ctx.createSubcontext("jdbc");
ctx.bind("jdbc/COMPDB2", ds);
ctx.close();
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>
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.