Rebind/restart bundles which depend on other one - java

UPDATED:
I will like to know if is possible to force all the dependencies which have reference to other OSGi Service to unbind to it, for then rebind.
e.g.
I have A, B, C all OSGi services which have a service dependency to X. Then X change something and wants that all other services which are binded to it execute unbind and then bind. This without X being stopped or reloaded or change the code of the other services.
Is this possible with standard OSGi?

You seem to be confusing service dependencies and package (type) dependencies.
For service dependencies, when a service is unregistered and a replacement service registered, there are service events which are published. Clients of the service can react which is what Declarative Services, Blueprint and ServiceTracker all help with.
For package dependencies, if a bundle which exports a package is updated, then all dependent bundles which import the package are left wired to the old version of the package. These dependent bundles can be refreshed which will caused them to be stopped, get new class loaders wired to the updated package, and started again. See https://osgi.org/javadoc/r5/core/org/osgi/framework/wiring/FrameworkWiring.html#refreshBundles%28java.util.Collection,%20org.osgi.framework.FrameworkListener...%29.

Related

RESTful service in Karaf without blueprint xml

I am new to Karaf, hence was looking for resources to create a project for RESTful web services using felix annotations and without the use of BundleActivator class(i mean by an actual class that needs to be written by me, but its ok if some compiler or maven plugin does the same for me) and blueprint xml file. So far I got success in the first part(BundleActivator part) which now after compilation auto creates my MANIFEST.MF with import and export statements, creates the relevant XML file for each component class, and packages it into a a nice jar bundle which works very well when I deploy it on Karaf container. But what is not working is the RESTful services. The bundle is deployed correctly, but the REST urls are not exposed and hence I am unable to access them.
Please help me in getting this done. I don't want to write an XML file which needs to be modified everytime there is an addition or deletion of a rest service.
Thanks
If you want to completely avoid blueprint then you should use cxf-dosgi. You simply annotate your rest service using jaxrs and publish it as an OSGi service with some special properties.
See the cxf-dosgi rest sample.
The example uses the standard DS annotation and the maven bundle plugin to create the DS component xml on the fly.
If you prefer to have blueprint at runtime then you can use the blueprint-maven-plugin. See this example.
I figured out a way to do so without using the CXF feature. That is, create a component class and in activate method get the object of ConfigurationAdmin and put the required context path against the jersy server process(using jersey publisher jar). Using this mehtod, I was able to deploy any rest/serlvet in Karaf without using blueprint.xml file. I hope this helps.

Expose a Class to JMX which resides in a transient dependency jar

I have a Java Web App (Spring) with some classes exposed to JMX. Let's call this project 'A'.
A has a dependency jar called B. B in turn has a dependency C.
Now I would like to expose a Class in C via JMX. So I decorated the class with the following
#ManagedResource(objectName = "A:name=myClassInC")
public class MyClassInC
But this doesn't seem to have any effect and the MyClassInC doesn't show up in the JMX console along with the other classes that are visible from A. The Spring JMX configuration actually resides in the context files of A. So I'm guessing that classes in C should also pick up the same configuration and show up in the JMX console. I'm wondering how I can fix this. Thanks!

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