Using declarative services with embedded Felix framework - osgi

I am developing a desktop OSGi app with declarative services on Mac OS X using Netbeans and Maven. I start the Felix framework from within a Java application and load my OSGi bundles using AutoProcessor.process().
However, I cannot get services referenced in other services to activate. As an example, I have a service AImpl which refers to service B as follows:
interface A {}
interface B {}
#Component
#Service(A.class)
class AImpl implements A {
#Reference(strategy = EVENT)
B b;
...
}
#Component
#Service(B.class)
class BImpl implements B { ... }
The value of AImpl.b is always null after I have created a bundle of type A.
My code to start the Felix framework looks like this:
Map felixConfiguration = ...;
try {
framework = new Felix(felixConfiguration);
framework.init();
final BundleContext frameworkBundleContext = framework.
getBundleContext();
AutoProcessor.process(felixConfiguration, frameworkBundleContext);
framework.start();
framework.waitForStop(0);
System.exit(0);
} catch (Exception ex) {
log.error("Could not start framework", ex);
System.exit(-1);
}
felixConfiguration contains – amongst many other things – the definition of the directory from which the bundles containing the DS services are to be loaded.
However, I get error messages like the following:
DEBUG: BundleA (12): [AImpl(6)] Updating target filters
DEBUG: BundleA (12): [AImpl(6)] No change in target property for dependency b: currently registered: false
DEBUG: BundleA (12): [AImpl(6)] No existing service listener to unregister for dependency b
DEBUG: BundleA (12): [AImpl(6)] Setting target property for dependency b to null
DEBUG: BundleA (12): [AImpl(6)] New service tracker for b, initial active: false, previous references: {}
DEBUG: BundleA (12): [AImpl(6)] dm b tracker reset (closed)
DEBUG: BundleA (12): [AImpl(6)] dm b tracker opened
DEBUG: BundleA (12): [AImpl(6)] registering service listener for dependency b
DEBUG: BundleA (12): [AImpl(6)] Component enabled
DEBUG: BundleA (12): [AImpl(6)] ActivateInternal
DEBUG: BundleA (12): [AImpl(6)] Activating component from state 4
DEBUG: BundleA (12): [AImpl(6)] Dependency not satisfied: b
DEBUG: BundleA (12): [AImpl(6)] Not all dependencies satisfied, cannot activate
It seems to me that some SCR code is missing that will make the Felix framework deal with DS services. I have included org.apache.felix.scr-1.8.2.jar (and alternatively org.apache.felix.scr-2.0.2.jar and org.apache.felix.scr.compat-1.0.2.jar) in the dependencies, but that does not seem to be enough.
An additional symptom, which I assume is related to the same problem: gogo starts but doesn't recognise commands like help, lb etc., although all three bundles (command, runtime, shell) are available.
I have simplified the examples and changed the names of the parties involved to protect the innocent :-) I hope that the structure is clear enough to show what I am trying to do and what is not working.
I have googled terms like felix ds embedded and found articles like this, which make it sound as easy as I wish it was. Clearly I am making a mistake somewhere: I'd be grateful for pointers.

What you do looks good at first glance. It is difficult to tell without all details.
You seem to be using the scr annotations. As there are standard DS annotations now I propose you give them a try. I got a full example here.
I typically use karaf for my examples but it should also work in plain felix.
One thing your could try is to install your bundles into karaf and use the karaf shell to analyze if there is anything strange. Just install the scr feature and put your bundles into the deploy dir.
If that works then your bundle are correct and there is probably a problem with your felix deployment.
In any case you should check that all bundles can be resolved. Of course this is a bit difficult as long as the shell does not work.

I've solved the problem after stripping the application right down to the basics, which in this case is the code to start the Felix framework.
The key to the problem was the recognition that an OSGi framework embedded in a normal Java program is a meeting of two worlds: bundles and POJOs. These days lots of POJOs are distributed with OSGi-compatible manifests, but they are still POJOs and not bundles. But I was sticking everything with an OSGi manifest into the bundles directory and loading them with AutoProcessor.process(). This included things like org.apache.felix.framework and org.apache.felix.main, but also various POJOs dealing with logging. That seems to have caused the behaviour described above.
I fixed this by linking org.apache.felix.framework, org.apache.felix.main and the logging POJOs in the classic fashion and excluding them from AutoProcessor.process().
Unfortunately, slf4j-api seems to lead a double life, and there are lots of bundles out there, some of which I am using, which need it as a bundle. Rather than experiment with loading it twice (classical linking and AutoProcessor.process()) I simply added pax-logging-api and pax-logging-service to my bundles directory and let AutoProcessor.process() load them instead.
It all makes perfect sense with hindsight ;-)

Related

Are services in AEM really singleton?

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.
}
}

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>

Amdatu JPA (bndtools, felix DM) not resolving DataSource service

So I was loosely following the Amdatu JPA video tutorial and I almost got it working...
At a glance everything seems to be fine, only DataSource service is not resolved and I don't know why. It seems to me that it is registered. So how would I go debugging this, there should be some way to debug this, right?
When starting I have this in msg log:
[CM Configuration Updater (Update: pid=org.amdatu.jpa.datasourcefactory.dd8bf61e-01b1-4732-9b0c-bba96e1f5aff)] DEBUG org.amdatu.jpa.datasourcefactory - ServiceEvent REGISTERED - [javax.sql.DataSource] - org.amdatu.jpa.datasourcefactory
Output of "dm":
[5] org.amdatu.jpa.datasourcefactory
org.osgi.service.cm.ManagedServiceFactory(service.pid=org.amdatu.jpa.datasourcefactory) registered
org.osgi.service.log.LogService service optional available
javax.sql.DataSource(validationQuery=SELECT 1,name=ManagedDS,driverName=postgresql,serviceName=ManagedDS) registered
org.osgi.service.log.LogService service optional available
org.osgi.service.jdbc.DataSourceFactory (osgi.jdbc.driver.class=org.postgresql.Driver) service required available
javax.transaction.TransactionManager service required available
So the output above should mean that DataSource is registered, right?
[31] org.amdatu.jpa.extender
org.amdatu.jpa.extender.PersistenceBundleManager() registered
org.osgi.service.log.LogService service optional available
javax.persistence.spi.PersistenceProvider service required available
active (Meta-Persistence=*) bundle optional available
java.lang.Object(bundle=32) registered
org.osgi.service.log.LogService service optional available
org.amdatu.jpa.extender.PersistenceBundleManager service required available
org.amdatu.jpa.extender.PersistenceUnitInfoImpl#7175ee92 unregistered
javax.persistence.spi.PersistenceProvider (javax.persistence.provider=org.eclipse.persistence.jpa.PersistenceProvider) service required available
javax.sql.DataSource (name=ManagedDS) service required unavailable
Everything further that depends on DataSource is obviously not resolved
javax.persistence.EntityManager service required unavailable
So what I don't get is why is DataSource not resolved there? I checked and it seems it is registered with property name=ManagedDS, but I am quite new to Felix DS so I am not really sure what is happening here.
I also tried adding this
#ServiceDependency(filter="(name=ManagedDS)")
private volatile DataSource ds;
to one of my services, but that too cannot be resolved. Thanks for any help regarding this, but what I would be most grateful of would be a way to debug and solve this myself.
So, Amdatu video tutorial suggested I should add
Import-Package: javax.sql;version=1.0.0
to my bundles. I tried removing that and it works (I did that when it stopped resolving that import after I set all versions to small ranges. Still don't know why it did that and wish that I tried that sooner)
So my guess as to why it works now - packages in my OSGi container were probably using two different versions/instances of javax.sql.DataSource. Probably one from postgres package and other someplace else (system?). Maybe one of the OSGi gurus can comment on this and clear it up?
Another sub-question is as that video suggested it is a good thing to add that import, what can I do to make it work or if it not important should I just not bother?

OSGI Bundle Lazy Activation

I am really new on this one (OSGI), trying to do simple examples. I cant make lazy actication work. I know there a few Blueprint impl out there to resolve such issues, but before proceeding with one, I thought it would be good to learn a few basics.
Bundle DataService:
Manifest-Version: 1.0
Bundle-Version: 1.0.0
Bundle-Name: DataService
Bundle-ManifestVersion: 2
Bundle-Activator: DataService.Activator
Import-Package: org.osgi.framework
Bundle-SymbolicName: DataService
Export-Package: DataService;version="1.0.0"
Bundle-ActivationPolicy: lazy
Bundle DataServiceClient:
Manifest-Version: 1.0
Bundle-Version: 1.0.0
Bundle-Name: DataServiceClient
Bundle-ManifestVersion: 2
Bundle-Activator: DataServiceClient.Activator
Import-Package: org.osgi.framework, DataService;version="[1.0.0,1.0.0]"
Bundle-SymbolicName: DataServiceClient
Ok I have changed my code, but still no luck.
Outer application, install bundles, starts framework and then only starts DataServiceClient bundle.
No access to any bundle class.
File bundleDir = new File("./bundles/");
String[] bundleResources = bundleDir.list();
for(String bundleResourcePath : bundleResources) {
File bundleResource = new File(bundleDir, bundleResourcePath);
InputStream bs =new FileInputStream(bundleResource);
mFramework.getBundleContext().installBundle(bundleResource.getName(), bs);
}
mFramework.start();
bl = mFramework.getBundleContext().getBundles();
for(Bundle b : bl) {
if (b.getBundleId() != 0 && b.getSymbolicName().contains("DataServiceClient")) {
b.start();
}
}
Here is the start of DataServiceClient:
System.out.println("DataServiceClient Start");
IDataService service = new DummyService();
System.out.println(service.getData());
Here is the DummyService class in "DataService" bundle.
public class DummyService implements IDataService {
#Override
public String getData() {
return "DummyService Data";
}
}
Here is the start of "DataService" bundle:
System.out.println("DataService Start");
The output I am getting:
DataServiceClient Start
DummyService Data
However I expect to see:
DataServiceClient Start
DataService Start
DummyService Data
a little quatation from http://www.osgi.org/Design/LazyStart
Lazy Activation
Lazy activation is a life cycle policy that mandates a bundle MUST be activated upon the first successful request to load a class from that bundle.
However since it doesnt work, i guess i completely misunderstand the concept of lazy activation or i am doing something wrong.
Unless I explicitly call start for DataService bundle, it seems it doesnt invoke Activator.start for DataService bundle. This is what I am not getting atm.
Thx for your time
Are you sure, your Activator is really not called. I often had the case that the activator was called but experienced and exception which OSGi swallowed. Can you try a println on the first line in the Activator.start to check this. A try catch with logging also is useful in this case.
Btw. Naming a package with an upper case letter is highly unusual. Not sure if it is a problem but I would avoid that.
It's not clear what's going on when you call DummyClient.GetData(). You say that it invokes a class in the DataService bundle, but how?? DataService is an ordinary bundle and your code is the main Java launcher application, and there is no way in OSGi for the "outer" application to depend statically upon an ordinary bundle.
Anyway, even if you could do this, you execute this line of code before the bundle is started. The bundle activator will certainly not be called before the bundle is started!! I would expect your activator to be called at line 36, i.e. where you call bundle.start() on each bundle.
But really... what on earth are you trying to do?? The Bundle-ActivationPolicy: lazy flag is almost completely useless. I have eight years' experience of OSGi, and have only ever used this setting in Eclipse RCP applications, for legacy reasons. Unless you are writing an Eclipse plug-in or an Eclipse RCP application, you should not use Bundle-ActivationPolicy: lazy in OSGi.
The proper way to get lazy (or "just in time") instantiation in OSGi is to use Declarative Services (DS). All service objects published by DS are instantiated on demand, when a client first tries to invoke them rather than at the time they are registered. You do not need to do anything special to enable this.
Regarding the changed code... you never actually start the bundle DataServiceClient, so its activator cannot be called. You have explicitly excluded it by name from the loop in which you start the bundles. OSGi will only ever call the BundleActivator on bundles that have been started with bundle.start().
This is a very widely misundertood point... OSGi never automatically starts bundles, even with the Bundle-ActivationPolicy: lazy flag enabled.
Probably what you meant to do is start the bundle as follows:
bundle.start(Bundle.START_ACTIVATION_POLICY).
In fact you do this for all bundles rather than arbitrarily starting a subset of bundles.
But again, I must reiterate the point I made in my other answer. Using Bundle-ActivationPolicy: lazy is pointless, except if you are developing Eclipse RCP applications, in which case you sometimes have to use it for stupid legacy reasons.

WAS 8.5 - Can a blueprint managed OSGI service have a reference to a declarative services managed OSGI service?

We use WebSphere 8.5 (NON-Liberty Profile… just straight-up WAS) and we have a Spring 3.2 web app that is accessing an OSGI service which is using the blueprint component model via an SCA service bridge. We did this this way because to our understanding, this was the only way to be able to access the OSGI services layer from within our current architecture. If anyone might know of another/better way, I'm also all-ears on this as well.
From within this blueprint managed service, we'd like to have a reference to another service. This other service(and any service references within it) we'd like to have managed by the declarative services component model.
My question is… is this possible? Does anyone know if this mixing of these two component models from within WAS 8.5 is do-able in any way, shape, or form??
And if it is possible, might anyone be able to point me in the right direction on how to approach this?
Edit - Dec 5th
So the approach I decided to take was to first, build a small proof-of-concept application that uses three different OSGI bundles all using blueprint. Then once I have this working, take one of the blueprint managed services, and attempt to convert it to a ds managed service.
Here's what I've got so far:
I have ran through and created the tutorial located here. I currently have the CounterApp OSGI bundle Application containing the following bundles as application content:
CounterServiceBundle
CounterWebBundle
CounterWorldBundle
As is stated in the tutorial, all of the above are tied together using the blueprint component model via the blueprint.xml files.
So it all breaks down as follows:
From within the doGet method of the CounterWebBundle's CounterServlet I have a Greet service being used in the following manner:
Greet greet;
try {
InitialContext ic = new InitialContext();
greet = (Greet) ic.lookup("osgi:service/"+Greet.class.getName());
String greetText = greet.getText();
String output = "greet.getText()="+greetText;
response.getOutputStream().println(output);
} catch (NamingException e) {
e.printStackTrace(System.out);
}
This "greet" service is defined in the blueprint xml as "GreetBeanService". Now, within its implementation class it has references to two other services, "CounterBean" and "WorldRef".
Here is the blueprint.xml file to clarify:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<bean id="CounterBean" class="com.ibm.ws.eba.counter.CounterImpl"
init-method="init"></bean>
<service id="CounterBeanService" ref="CounterBean"
interface="com.ibm.ws.eba.counter.Counter" />
<bean id="GreetBean" class="com.ibm.ws.eba.counter.GreetImpl"
init-method="init">
<property name="counter" ref="CounterBean"/>
<property name="worldBean" ref="WorldRef"/>
</bean>
<service id="GreetBeanService" ref="GreetBean"
interface="com.ibm.ws.eba.counter.Greet" />
<reference id="WorldRef" interface="com.ibm.ws.eba.world.World" />
</blueprint>
So the thing is this:
I'm aiming to convert the "WorldRef" service to a DS managed service with a component.xml file and the following added to the MANIFEST.MF header Service-Component: OSGi-INF/component.xml of the implementation Class, not the API Class if I'm understanding correctly.
Would this be all I would need to do for the conversion? Or do I also need to add an Activator for the Class? Also, would I need to add 'activate' and 'deactivate' methods in the API implementation Class?
Also I'm of the understanding that I have to somehow include the service component runtime, as a separate bundle and include it in the "CounterApp" application, how exactly would I do this? Do I have to create a separate bundle project consisting of the following bundle/jars
org.eclipse.equinox.util
org.eclipse.equinox.ds
org.eclipse.osgi.services
where I would then re-export all of the exported interfaces from all of these jars?
Or do I have to define some sort of service to export that exposes the SCR?
Edit - Dec 6th
I went ahead and created a new DS OSGI bundle/jar containing all of the above mentioned jar files required to provide the equinox DS implementation, then just passed on the exports of each jar in this new bundle. I then added this DS bundle to my CounterApp application and imported each of these DS bundle exports into the bundle containing the WorldRef service.
This is where I appear to be getting hung up:
The OSGI framework is loading the bundle containing the WorldRef service but the service is not being added to the registry, which suggests that the component.xml file defining the service isn't being read, which, intern suggests that the SCR is not running because it is what reads that file to my understanding.
So still stuck on the ability to get the SCR running. I am under a very tight deadline (I know… who isn't, right?

Resources