Osgi bundle cannot find osgi service - apache-felix

I have 2 osgi bundles (say A and B) running in Jboss Fuse. I am using Felix.
'A' bundle exposes a service which 'B' bundle uses. When I deploy both these bundles there is no problem. When I execute osgi:ls -u, I see that bundle 'B' is using service exposed by bundle 'A'
After I restart these 2 bundles together Bundle 'B' cannot find service exposed by Bundle 'A'. At this stage if I execute command
osgi:ls, I see OSGI service exposed by bundle 'A'. When I execute osgi:ls -u, I don't see that bundle 'B' is using service exposed by bundle 'A'
I got 2 workaround for this problem
At this stage if I restart only bundle 'B', then bundle 'B' finds
OSGI service exposed by Bundle 'A'. Restarting bundle is not obvious
official solution :)
In bundle 'B', while importing osgi service, if add cardinality
as 0:1 then I don't find any issue. But I cant do this as service
exposed by bundle 'A' is mandatory for some functionality in bundle
'B'
Can anyone tell me why I am observing this behavior and how I can resolve it ? ?

Noted that this could happen when bundle B creates its app ctx outside the normal spring extender process. For instance, bundle B creates an app ctx based on an external event and the app ctx imports the osgi service exported from the bundle A. If you are using spring-dm to export/import osgi services, use ServiceTracker via BundleActivator instead.

Related

Eclipse Virgo - classloader returns old class after bundle reload

I have bundle A and bundle B. Bundle B imports packages from bundle A and bundle B has Eclipse-RegisterBuddy set to bundle A. Bundle A loads class which is exported by B by Java reflection (Class.forName). When bundle B is redeployed, bundle A still has reference to classloader from old version of B, so Class.forName returns old class version from B. This causes that calling Class.isInstance from A returns false when argument is instance created in B and passed to method in A.
Is there some way to refresh classloader in A to be able return new version of classes from B? It is possible to call bundle refresh A command from Virgo console, this solves this problem, but this refresh causes that all dependent bundles (B and others) are stopped and started again. This is not suitable in our application because bundle B and others which import packages from A are long running batch jobs and cannot be stopped.
Class.forName() is an anti-pattern in OSGi, do not use that: http://wiki.osgi.org/wiki/Avoid_Classloader_Hacks
You should create an interface for your class. The interface should be stable. You should put this interface into a separate bundle like B.API. In bundle A, you should use this interface, instead of the class. After having the stable interface in a separate bundle, refreshing B will not cause the restart of your dependent bundles. You have several options to get the instance that you want:
Option 1
You should think in OSGi services and in their lifecycles. Bundle B should register an OSGi service that bundle A uses. You can write a ServiceTracker or use Declarative Services to get the service.
Option 2
You should choose option 1. I do not recommend option 2, but it can work if you do not want to use OSGi services due to some reason. Get bundle B in bundle A. Use bundleB.loadClass() to load the class type and cast it to the interface that is located in B.API.

EAR generated using ANT doesn't work on Websphere 8.5

The object is to build .ear by using ANT then deploy it on Websphere 8.5 with wsadmin.
Manually, the ear file is generated from a jar file and after deployment, the web application works very well.
But if I use the ear generated by ANT, after deployment (by hand or by wsadmin), I always have this error :
SRVE0255E: A WebGroup/Virtual Host to handle /WebApp$%7Blogout.url%7D has not been defined.
SRVE0255E: A WebGroup/Virtual Host to handle localhost:9080 has not been defined.
Someone knows which might invoke this problem. I met this message before while my colleague deploy on websphere with a war file directly from a Tomcat server.
Thanks in advance.
It looks like you have not defined web application bindings during deployment. There are several ways to do this, but before that I suggest that you read about Application bindings in WAS, especially the paragraph Virtual host bindings for web modules.
Required bindings can be provided either as parameters to install command of AdminApp or by including binding files directly inside WAR. In some cases WAS can generate default binding for you. For example, to install web application with default bindings you need to provide the following command to wsadmin (simplified):
AdminApp.install(path_to_your_war_file, [
'-appname', your_app_name,
'-CtxRootForWebMod', [
['.*', '.*', your_app_context_root]
],
'-usedefaultbindings'])
I also recommend deploying application once in WAS console to understand possible bindings.

Cannot access bean when deploying ejb module and web module separately?

I was testing an EJB 2.x application. I created 2 module separately:
EJB module: contains a simple stateless session bean
Web module: contains a single servlet page to lookup EJB module.
I was using Jboss 4.2.3.
First, I deployed the EJB module and the deployment went well.
Second, I deployed the web module and the deployment went well.
Then I used the following code to look up the EJB module:
Context c = new InitialContext();
Object o = c.lookup("HelloJNDI"); // Line 1
HelloLocalHome rv = (HelloLocalHome) o; // Line 2
HelloLocal local = rv.create();
The lookup went well (Line 1), but Line 2 produced a class cast exception.
Then I test the above code in 2 scenarios:
I packaged the EJB and the Web module into a single EAR module. Then, deployed this EAR module in JBoss 4.2.3, and the lookup code above worked like a charm.
I tried to use JBoss 5, and even deployed the EJB module and the Web module separately, the lookup code above worked great.
So, why when I deployed the 2 modules separately in JBoss 4, things did not work out? I use local JNDI lookup only because the 2 modules were deployed in the same container.
Was I missing something or this is a flaw in JBoss 4?
Try using the following code instead of your cast:
HelloLocalHome rv = (HelloLocalHome)javax.rmi.PortableRemoteObject.narrow(o, HelloLocalHome.class);
If that does now work, then you have the infamous classloading problem. (One of the reasons JBoss 5's default server uses a different classloading mechanism). Easiest is to indeed place them in a single EAR (so the Home and remote classes are loaded once). The Home interface class in your web application is loaded by a different classloader than the one being returned by JNDI.
You can also remove the interfaces from your WAR file's classes or lib dirrectory

Shared libraries between web services on Glassfish

I need to deploy multiple web services on a jax-ws application server, glassfish 3. These web services need to have shared libraries, meaning shared instances of the same class.
I know I could do this by dropping a jar in the "~/glassfish3/glassfish/domains/domain1/lib" directory. But I wonder whether this is possible in a more elegant way: I want to place the shared library jar inside a web service war which I deploy and then access that library from another war I deploy on the same application server.
How can I do this?
I found a solution for Glassfish myself: Basically I just deploy a class (SharedClassLoader) which inherits from URLClassLoader as a shared library jar in the above mentioned directory. Then I use this classloader as a bootstrap: On calling the web service, the classloader hierarchy is extended as follows: A SharedClassLoader for an URL is instantiated if it does not exist yet and it is added as a delegate to the DelegatingClassLoader in the classloader tree. By doing this for every web service with the same SharedClassLoader instance, it acts as a bootstrap to pull in more class loading. The jar that SharedClassLoader refers to can also be deployed with one of the web services, because Glassfish unpacks the containers to $AS_HOME/domains/domain1/applications/APPLICATION_NAME/LIBRARY_NAME.jar.
I hope this helps anyone having the same problem. I solved this problem for my Bachelor Thesis. If anyone needs more information, just ask, I can send you my thesis.

deploy multiple RESTful service bundles in ServiceMix/FUSE 4.3

I am using the example cxf-jaxrs shipped with apache-servicemix-4.3.0-fuse-03-00.tar.gz to investigate how to deploy multiple bundles which provides different RESTful services. What I did is copied the cxf-jaxrs example into cxf-jaxrs-example-1, and modified the pom.xml and beans.xml. The modifications are :
1. pom.xml
version: 4.3.0-2-fuse-03-00
name: Apache ServiceMix Example 2:: CXF JAX-RS OSGI
2. beans.xml
<jaxrs:server id="customerService2" address="/crm2">
Then I made two packages. The one is the original example package cxf-jaxrs-4.3.0-fuse-03-00.jar and the other is the modified one cxf-jaxrs-4.3.0-2-fuse-03-00.jar and I copied them into "deploy" directory.
After servicemix started, I see both bundles are active and started succesfully.
But, I am only able to access the RESTful services in one bundle. When I type "http://localhost:8080/cxf/crm2/customerservice/customers/123", I got "No service was found." error. And when I stop the other example bundle(the original one), I can access "http://localhost:8080/cxf/crm2/customerservice/customers/123" with no problems.
What I did wrong?? It is supposed to provides the RESTful services in both context path "/crm" and "/crm2".
problem sovled. My bad. I forgot to modify the path annotation on CustomerService class