Passing arguments between parent application and OSGi Framework - java

I have to pass parameters between parent application and embeded OSGi. I use equinox and run OSGi by FrameworkFactory in my Launcher class, then I install and start bundles. It is possible to pass object reference or even some primitive type to bundle or service?

After launching the framework, you can get the system bundle context and access and call services registered by bundles in the framework. Care must be taken about the service types since the are likely loaded from bundles and thus the types are not directly visible to your launching code. But you can use reflection. Or you can put those types in the framework classloader and export them from the system bundle via org.osgi.framework.system.packages.extra framework property your launcher sets.

Related

PAX-CDI: how to get reference to BeanManager in bundle without using CDI

There is a bundle A and threre is a class MyClass in bundle A. And we suppose that pax-cdi+weld is on.
Can can I get reference to BeanManager of the bundle A inside MyClass without using #Inject and other CDI annotations? Via osgi service? Or how?
You can look up the CdiContainer OSGi service and invoke getBeanManager().
With recent versions of Pax CDI CDI.current().getBeanManager() should work as well.
Having said that, the whole idea of Pax CDI is to make CDI work in OSGi just like in Java EE. Accessing the BeanManager is a bit of a design smell, unless you are developing a CDI extension.

Can a non spring web application use a jar which is built using spring + hibernate

We are building a java application using spring hibernate maven. The jar will be used in a non spring web application that uses ejb and plain jdbc. Ejb will access the jar interface methods which in turn makes hibernate calls.
What changes are needed in the web application to load the spring context during start up? Is it feasible?
If you want to keep your jar decoupled from web application you should do this:
Copy your jar and all dependant jars to webapp WEB-INF\lib directory (or pom if maven)
Your Spring Context should be loaded in a static variable, in a safe thread manner; or if you want to integrate it to the webapp lifecycle you can do it in several ways: web.xml, web-fragment or using a servlet initializer. There are lot of documentation in Internet
If you continue to use hibernate or change to JDBC, the DataSource should be provided generally by the web container, so you must use InitialContext.lookup("") to get the actual DataSource.

Accessing osgi bundle classess from servlet

I have two projects.
An osgi bundle (eclipse plugin project).
A simple web application (deployable in tomcat).
I have started the felix container from tomcat with no problem by following the link below
http://felix.apache.org/documentation/subprojects/apache-felix-http-service.html#using-the-servlet-bridge
Now I am stuck how to call the classes of the bundle (already installed in the felix container) from a servlet. It is throwing class not found error as the bundle project is not in the classpath but in the following location
/WEB-IN/bundles.(I have to use this location for the bundles). So how it could be achieved?
The BundleContext of the framework bundle is put into the servlet context in ProvisionActivator:
servletContext.setAttribute(BundleContext.class.getName(), context);
This means that you can access the BundleContext via the servletContext (that is available in all of your ordinary servlets) like this:
BundleContext context = servletContext.getAttribute(BundleContext.class.getName());
You can access the classes inside the embedded OSGi container by:
Asking for the bundle that contains the class via the bundleContext
Getting the class with the bundle.loadClass("myClass") method. You will be able to use that class only if you cast to the interface available from the ordinary WAR or with reflection
This is the way to do it, however you should not use this method :). Design your solution in the way that in your bundles you register OSGi services that implement interface(s) coming from the WAR classpath. After that you should use the bundleContext object to retrieve the OSGi service objects.
Other good solution is if you implement the logic you need within bundles instead of classes coming from the WAR.

OSGi/Equinox, Declarative Service and Lazy Load

I'm attempting to use Declarative Services to create a service bundle that provides functionality to another bundle. However, I want my Service Provider bundle to not start until it is needed. Let me describe my conditions.
There are two bundles:
-com.example.serviceprovider
-com.example.serviceconsumer
The Service Provider bundle provides a services using Declarative Services as follows:
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" enabled="true" immediate="true" name="samplerunnable1">
<implementation class="com.example.serviceprovider.SampleRunnable"/>
<service>
<provide interface="java.lang.Runnable"/>
</service>
The Service Consumer references the provided services as follows:
<reference name="SampleRunnable"
interface="java.lang.Runnable"
bind="setRunnable"
unbind="unsetRunnable"
cardinality="1..n"
policy="dynamic"/>
When both of these bundles are "ACTIVE" on start up, the Service Consumer has no trouble communicating with the service declared by the Service Provider. The problem happens when I try and have the service provider start in a lazy fashion.
After the Service Provider is set to load lazy this is what I get in the OSGi console:
osgi> ss
"Framework is launched."
id State Bundle
15 STARTING com.example.serviceconsumer_1.0.0.X
16 RESOLVED com.example.serviceprovider_1.0.0.X
What I would expect to see, is that even though bundle 16 is only "RESOLVED" that it would have at least registered is service. But when I call the "bundle" command, it states "No registered services."
osgi> bundle 16
com.example.serviceprovider_1.0.0.X [17]
Id=17, Status=RESOLVED Data Root=C:\apache\apache-tomcat-.0.40\work\Catalina\localhost\examplesX\eclipse\configuration\org.eclipse.osgi\bundles\17\data
"No registered services."
No services in use.
No exported packages
Imported packages
org.osgi.framework; version="1.7.0"<org.eclipse.osgi_3.8.0.v20120529-1548 [0]>
No fragment bundles
Named class space
com.example.serivceprovider; bundle-version="1.0.0.X"[provided]
No required bundles
Maybe I've missed the fundamental concept of lazy loaded bundles and services registration. If a bundle is in a "RESOLVED" state, shouldn't it have all it's "wires" connected? (ie, has a classloader, resolved import and export dependencies and services registered.) If the Service Consumer tries to access the service shouldn't that bundle transition to the "ACTIVE" state? What piece am I missing here?
Bundles in the RESOLVED state cannot provide services, and they will be ignored by Declarative Services. You should in general start all bundles during launch time, even if you want lazy loading behaviour. The key is to make the activation of the bundles cheap (or free!), and only pay for initialization of components when they are required.
DS takes care of lazy activation by default already. There is nothing you need to enable or change for this to happen. Essentially DS publishes the service entry in the registry, but it does not actually instantiate your component (or even load its class) until some client tries to use the service.
Furthermore, because DS does not load the class until required, OSGi does not even need to create a ClassLoader for the bundle, so long as your bundle does not have a BundleActivator.
To reiterate, you should not seek to make your bundles stay in RESOLVED state. Such bundles can only export static code and resources, but they cannot "do" anything and they cannot participate in the service registry.
Declarative services were designed for this case. Starting a bundle means that's functionality should be available, it does not mean it actually uses resources. Only stop bundles when you don't want is function.
This question is a good example of trying to control too much. In a component oriented world programmers should use lazy initialisation as much as possible but they should never attempt to control the life cycle.

Adding aspects on services across OSGi bundles

I have an OSGi bundle (that is not owned by me - so I cannot change it!) that exposes (exports) a service EchoService, and I want to attach an aspect to methods of this service (so as to perform some pre/post processing around it). These are deployed on the Apache Felix container.
I've written my own OSGi bundle (that obviously imports the EchoService), and attaches Spring aspects to it using standard Spring AOP. However, looks like the aspects are not attached and my interceptor is not being invoked.
I suspect that this is because I'm trying to intercept a service that does not belong to my bundle (which seems reasonable). Is that correct? How can I overcome this?
Here's what my interceptor/aspect looks like:
#Before("serviceOperation()")
public void before(JoinPoint jp) {
logger.debug("Entering method: " + jp.toShortString());
}
#AfterReturning("serviceOperation()")
public void after(JoinPoint jp) {
logger.debug("Exiting method: " + jp.toShortString());
}
I'm not an AOP nor a Spring expert, but maybe I could give you some ideas. As far as I see Spring use standard J2SE dynamic proxies for AOP proxies. Hence your clients should use the proxy instead of the original EchoService object. This is also true when you're using CGLIB proxies because "the proxies are created by sub-classing the actual class".
If your client bundles asking for an EchoService you have to pass them the proxy somehow. For this inside an OSGi container you should also export an EchoService (proxy) and make sure that the clients use the proxied service/bundle, not the original. You can accomplish this by setting a different version number for the (proxied) package and set this version as an import requirement in your client bundles. (I suppose you can modify the clients of EchoService.) For services you can set a property when you're registering it and modify the clients to query only for services which have this property.
If you are not able to modify the client bundles another solution could be wrapping the original bundle as an internal jar in your bundle. You can call the wrapped bundle's activator from your activator and pass them a modified BundleContext. This BundleContext should catch the registering service calls and register the proxy object instead of the original EchoService. You can use simple delegate pattern since BundleContext, ServiceListener etc. are usually interfaces. I suppose it could work but it maybe has other challenges.

Categories