You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@felix.apache.org by Remo Liechti <re...@swisslog.com> on 2016/08/25 06:23:06 UTC

LinkageError, but why?

Hi guys

I send this to you since this seems like a more technical issue than the felix user mailing list can help me with.
I am wrapping an existing osgi application that was running with equinoix into a j2ee application that runs on Weblogic. After a few issues, the application deploys and run totally fine.
I can access it sockets and connect the client to it without issues.

But when it comes to accessing the app using the OSGI Services, I can call a few methods. However, as soon as I call a method on a service that has non Java-Datatypes, I get LinkageErrors, like this one:
java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/felix/framework/BundleWiringImpl$BundleClassLoaderJava5) previously initiated loading for a different type with name "com/kuka/nav/robot/MobileRobotType"
at com.kuka.nav.fleet.simulation.internal.FleetSimulationImpl.addRobot(FleetSimulationImpl.java:137)
at com.kuka.nav.fleet.simulation.internal.FleetSimulationImpl.addRobot(FleetSimulationImpl.java:177)
at com.swisslog.wm6.test.MoveServlet.processRequest(MoveServlet.java:71)
at com.swisslog.wm6.test.MoveServlet.doGet(MoveServlet.java:95)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)

What I try to achieve is:
69: IResourceManager resMan = getService(IResourceManager.class);
70: FleetSimulation simulation = (FleetSimulation) resMan.getResource("FleetSimulation").getCapability(FleetSimulation.class);
71: simulation.addRobot(new BasicRobotType(7), "Robotinator");
72: simulation.startAllRobots();

As you can see, the type to pass to addRobot is of BasicRobotType.

We tried with a different method, that instead of a BasicRobotType takes a regular integer instead:
69: IResourceManager resMan = getService(IResourceManager.class);
70: FleetSimulation simulation = (FleetSimulation) resMan.getResource("FleetSimulation").getCapability(FleetSimulation.class);
71: simulation.addRobot(7, "Robotinator");
72: simulation.startAllRobots();
This works fine then. But this also means we would have to change the API significantly and to a low level API who nobody likes.

Information about the classes:
public interface MobileRobotType
public final class BasicRobotType implements MobileRobotType The java classes are in a single jar file and are not duplicated on the classpath.

@Resource(lookup = "java:app/osgi/Bundle") Bundle activatorBundle;
public <T> T getService(Class<T> serviceInterface) {
        return activatorBundle.getBundleContext()
                .getService(activatorBundle.getBundleContext().getServiceReference(serviceInterface));
    }


Any idea what can be done to solve the linkage error? Maybe any Devs out there of felix itself?

Thanks
This message may contain legally privileged or confidential information and is therefore addressed to the named persons only. The recipient should inform the sender and delete this message, if he/she is not named as addressee. The sender disclaims any and all liability for the integrity and punctuality of this message. The sender has activated an automatic virus scanning, but does not guarantee the virus free transmission of this message.

RE: LinkageError, but why?

Posted by Remo Liechti <re...@swisslog.com>.
> In your case it looks like the API is needed on the outside of the OSGi
> Framework, because it’s on the classpath of the webapp. This means you have
> to export it from the system bundle by setting the
> org.osgi.framework.system.packages.extra property. If you do this you can
> remove the copy that exists in the bundle, and allow that bundle to import the
> API.
Exactly, the API is needed outside of OSGI. Setting the extra property within Weblogic felix system bundle did not help. I know the extra property is respected since I had to put some javax.xml packages there in order to make the osgi bundles work that use javax.xml stuff.

> i don’t fully understand your scenario, but bear in mind that an OSGi application
> nearly always consists of multiple bundles.
Ok, let me try to explain further. We have a legacy osgi application that we want to use without big changes to it in our Weblogic infrastructure (yes, sure, we can always start it the old fashion way as a standalone application).
To achieve this, I wrapped the entire osgi application into a *.war web application. That war contains a main activator bundle that configures all the osgi bundles of the osgi application. Besides that, some weblogic configuration files that tell weblogic to look for the main activator in all the bundles that are put to its osgi-lib folder. Like this, the application boots up and functions normally.
Within the very same web application, I do have a java servlet that accesses the osgi application by the way oracle built that osgi bridge in Weblogic: https://docs.oracle.com/middleware/1212/wls/WLPRG/osgi.htm#WLPRG778
This serves as the only entry point I can get outside of the osgi application.

You do this by the following code:
    Bundle bundle = null;
    try {
      Context initCtx = new InitialContext();
      bundle = (Bundle) initCtx.lookup("java:app/osgi/Bundle");
    } catch ....

This is the old fashion way to do this, today we use
    @Resource(lookup = "java:app/osgi/Bundle")
    Bundle bundle;

Which does all the stuff automatically.


So to me it seems like we have those classloaders in the game:
1) One Main Weblogic classloader that boots the server
2) One Webapplication Classloader that boots the non-osgi part of the war application, like the servlet
3) One Felix Classloader that boots up the osgi framework
4) One main activator bundle classloader that configures the other osgi bundles
5) One classloader for each osgi bundles, but those are handled by felix and should not cause issues

The main problem is to access from classloader 2) the stuff in 4) and 5) even though the extra property is set on 3) to export the classes.

I also tried to load all those osgi bundles into the 1) classloader by putting them into the osgi-lib folder of the weblogic server installation. This worked in a way where the libs were found and the application boots up, however the linkage error still happened.
Maybe it's just not possible, since the weblogic documentation states: "One specific OSGi bundle from the chosen framework instance can be used in the application classloader hierarchy."

So far I am out of ideas. If you are interested in this problem more deep we could also do some teamviewer session. I would love to solve this problem and understand the stuff behind the scenes.
This message may contain legally privileged or confidential information and is therefore addressed to the named persons only. The recipient should inform the sender and delete this message, if he/she is not named as addressee. The sender disclaims any and all liability for the integrity and punctuality of this message. The sender has activated an automatic virus scanning, but does not guarantee the virus free transmission of this message.

Re: LinkageError, but why?

Posted by Neil Bartlett <nj...@gmail.com>.
> On 25 Aug 2016, at 10:40, Remo Liechti <re...@swisslog.com> wrote:
> 
> 
>> Unless I have misunderstood you, that sounds like two places from which the
>> type is loaded: the lib folder of the web application (i.e. the application classpath
>> on which the OSGi Framework), and a bundle. That’s almost certainly the source
>> of the conflict.
> 
> Yes, you are right. The Class is loaded from within two classloaders. One is the weblogic WebApp classloader, the other one is the one from Felix. However, it's the same class file which is being loaded. There do not exsit multiple version of the same class file in different jars on the classpath.
> So if I understood you correctly - it does not matter if the class file is the same, the fact that the class is loaded in two different classloader alone is enough to create the LinkageError?

That’s correct. Bear in mind this is nothing to do with OSGi yet, it’s a core Java principle. The same class loader cannot be exposed to multiple definition of a class, even if those definitions are byte-for-byte identical.

> So the only solution would be to use standard java types  for passing params to the API instead?

Not at all. You can pass any type you like, as long as both sides are using the same definition of that type. Usually this is done by having a single export of the service API, and having both the consumer and the provider of the service import it.

In your case it looks like the API is needed on the outside of the OSGi Framework, because it’s on the classpath of the webapp. This means you have to export it from the system bundle by setting the org.osgi.framework.system.packages.extra property. If you do this you can remove the copy that exists in the bundle, and allow that bundle to import the API.

> 
>> If you are in a bundle you can always get your own BundleContext — you do not
>> need it to be supplied by JNDI.
> 
> Agreed, but the goal is not to be within a bundle, we want to access the osgi services outside from osgi in a j2ee web application, where we do not have an own BundleContext. But maybe I'm just no deep enough into osgi to understand this properly yet.
> 
>> I don’t think that’s true. Declarative Services is just a bundle, so you can add it to
>> any OSGi application. Weblogic doesn’t need to support it, or even know
>> anything about it.
> 
> We do not want to be in another bundle. We want to access the osgi application from the outside. But so far it seems to me that this is something which is not very common to do using regular osgi services but most likely using some webservie/Rest or the like instead.


i don’t fully understand your scenario, but bear in mind that an OSGi application nearly always consists of multiple bundles.


> This message may contain legally privileged or confidential information and is therefore addressed to the named persons only. The recipient should inform the sender and delete this message, if he/she is not named as addressee. The sender disclaims any and all liability for the integrity and punctuality of this message. The sender has activated an automatic virus scanning, but does not guarantee the virus free transmission of this message.


RE: LinkageError, but why?

Posted by Remo Liechti <re...@swisslog.com>.
> Unless I have misunderstood you, that sounds like two places from which the
> type is loaded: the lib folder of the web application (i.e. the application classpath
> on which the OSGi Framework), and a bundle. That’s almost certainly the source
> of the conflict.

Yes, you are right. The Class is loaded from within two classloaders. One is the weblogic WebApp classloader, the other one is the one from Felix. However, it's the same class file which is being loaded. There do not exsit multiple version of the same class file in different jars on the classpath.
So if I understood you correctly - it does not matter if the class file is the same, the fact that the class is loaded in two different classloader alone is enough to create the LinkageError? So the only solution would be to use standard java types  for passing params to the API instead?

> If you are in a bundle you can always get your own BundleContext — you do not
> need it to be supplied by JNDI.

Agreed, but the goal is not to be within a bundle, we want to access the osgi services outside from osgi in a j2ee web application, where we do not have an own BundleContext. But maybe I'm just no deep enough into osgi to understand this properly yet.

> I don’t think that’s true. Declarative Services is just a bundle, so you can add it to
> any OSGi application. Weblogic doesn’t need to support it, or even know
> anything about it.

We do not want to be in another bundle. We want to access the osgi application from the outside. But so far it seems to me that this is something which is not very common to do using regular osgi services but most likely using some webservie/Rest or the like instead.
This message may contain legally privileged or confidential information and is therefore addressed to the named persons only. The recipient should inform the sender and delete this message, if he/she is not named as addressee. The sender disclaims any and all liability for the integrity and punctuality of this message. The sender has activated an automatic virus scanning, but does not guarantee the virus free transmission of this message.

Re: LinkageError, but why?

Posted by Neil Bartlett <nj...@gmail.com>.
> On 25 Aug 2016, at 08:09, Remo Liechti <re...@swisslog.com> wrote:
> 
> Hi Neil
> 
> Thanks for answering. The point is I can make limited changes to the existing application only.
> Basically I created my own main bundle activator that registers the services again that previously were created using regular osgi.
> 
> What the activator is doing:
> - Configure bundles using the ConfigurationAdmin
> - the configured bundles expose their services itself within osgi. I cannot access them outside the main activator.
> - due to this, re-register the services again in the main activator, since weblogic classloader would throw classcast Class A to Class A when not doing it
> 
> Code of the main activator more or less:
> public void start(BundleContext context) throws IOException
>  ConfigurationAdmin configAdmin = getConfigurationAdminService(context);
>  configAdmin.getConfiguration("com.kuka.task.manager.component", null).update(getTaskManagerConfiguration());
>  ServiceReference<?> ref = context.getServiceReference(IExtendedTaskManager.class);
>  Object service = context.getService(ref);
>  context.registerService(IExtendedTaskManager.class.getName(), service, properties);
> 
> After that, the web application can access the task manager service from j2ee.
> 
> The @Resource annotation injects the main activator bundle into the web application (see https://docs.oracle.com/middleware/1212/wls/WLPRG/osgi.htm#WLPRG778). It basically is a JNDI lookup.
> You  tell the Weblogic container what application to inject like this:
> https://docs.oracle.com/middleware/1212/wls/WLPRG/osgi.htm#WLPRG765 Example 16-4 Adding the Framework and Bundle to weblogic-application.xml
> 
> The class that causes the Linkage Error is not in multiple jar files, it is within the com.kuka.nav.api bundle. It's there once only, and the jar file is also just once in the lib folder of the web application only.


Unless I have misunderstood you, that sounds like two places from which the type is loaded: the lib folder of the web application (i.e. the application classpath on which the OSGi Framework), and a bundle. That’s almost certainly the source of the conflict.


> 
>> Also the code in the method is dangerous. You should never lookup a service
>> using somebody else’s BundleContext — this could easily lead to errors since
> Well I do not have much of a choice since Weblogic just passes it to me using the @Ressource.


If you are in a bundle you can always get your own BundleContext — you do not need it to be supplied by JNDI.


> 
>> OSGi cannot perform its class-space integrity checks. Also where is the code in
>> which you release the reference to the service? You have thrown away the
>> ServiceReference object so I assume you don’t ever actually release the service.
> 
> You are right, a point for improvement. I will change this.
> 
>> This code would be much better if written as a Declarative Service component
>> with injection of the service using an @Reference annotation.
> Unfortunately, this is not supported by Weblogic OSGI to webapplications. This would work within the main activator only, where we cannot put the business logic/api calls.


I don’t think that’s true. Declarative Services is just a bundle, so you can add it to any OSGi application. Weblogic doesn’t need to support it, or even know anything about it.



> 
> Thanks,
> Remo
> 
> 
> 
>> -----Original Message-----
>> From: Neil Bartlett [mailto:njbartlett@gmail.com]
>> Sent: Donnerstag, 25. August 2016 08:41
>> To: dev@felix.apache.org
>> Subject: Re: LinkageError, but why?
>> 
>> 
>>> On 25 Aug 2016, at 07:23, Remo Liechti <re...@swisslog.com> wrote:
>>> 
>>> Hi guys
>>> 
>>> I send this to you since this seems like a more technical issue than the felix user
>> mailing list can help me with.
>> 
>> Not really… folks on that list can handle any level of technicality (they are mostly
>> the same folks as on this list)!
>> 
>>> I am wrapping an existing osgi application that was running with equinoix into
>> a j2ee application that runs on Weblogic. After a few issues, the application
>> deploys and run totally fine.
>>> I can access it sockets and connect the client to it without issues.
>>> 
>>> But when it comes to accessing the app using the OSGI Services, I can call a
>> few methods. However, as soon as I call a method on a service that has non
>> Java-Datatypes, I get LinkageErrors, like this one:
>>> java.lang.LinkageError: loader constraint violation: loader (instance of
>> org/apache/felix/framework/BundleWiringImpl$BundleClassLoaderJava5)
>> previously initiated loading for a different type with name
>> "com/kuka/nav/robot/MobileRobotType"
>>> at
>>> com.kuka.nav.fleet.simulation.internal.FleetSimulationImpl.addRobot(Fl
>>> eetSimulationImpl.java:137) at
>>> com.kuka.nav.fleet.simulation.internal.FleetSimulationImpl.addRobot(Fl
>>> eetSimulationImpl.java:177) at
>>> com.swisslog.wm6.test.MoveServlet.processRequest(MoveServlet.java:71)
>>> at com.swisslog.wm6.test.MoveServlet.doGet(MoveServlet.java:95)
>>> at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
>> 
>> LinkageError occurs when a ClassLoader is asked to define a type that has
>> already been defined. It would be useful for you to read the OSGi R6 Core
>> specification about Class Spaces, i.e. section 3.5 of OSGi.
>> 
>> In OSGi this usually happens when a type is included as a private package in
>> multiple bundles. The usual things to look out for are:
>> 1. Which bundle(s) export the package com.kuka.nav.robot? This can include the
>> system bundle if you are exporting into the framework from outside.
>> 2. Do any bundles contain their own copy of types in that package, including
>> MobileRobotType?
>> 3. How is boot delegation configured in your framework? If this is “*” then it
>> could lead to conflicts with bundles.
>> 
>> 
>>> 
>>> What I try to achieve is:
>>> 69: IResourceManager resMan = getService(IResourceManager.class);
>>> 70: FleetSimulation simulation = (FleetSimulation)
>>> resMan.getResource("FleetSimulation").getCapability(FleetSimulation.cl
>>> ass);
>>> 71: simulation.addRobot(new BasicRobotType(7), "Robotinator");
>>> 72: simulation.startAllRobots();
>>> 
>>> As you can see, the type to pass to addRobot is of BasicRobotType.
>>> 
>>> We tried with a different method, that instead of a BasicRobotType takes a
>> regular integer instead:
>>> 69: IResourceManager resMan = getService(IResourceManager.class);
>>> 70: FleetSimulation simulation = (FleetSimulation)
>>> resMan.getResource("FleetSimulation").getCapability(FleetSimulation.cl
>>> ass);
>>> 71: simulation.addRobot(7, "Robotinator");
>>> 72: simulation.startAllRobots();
>>> This works fine then. But this also means we would have to change the API
>> significantly and to a low level API who nobody likes.
>>> 
>>> Information about the classes:
>>> public interface MobileRobotType
>>> public final class BasicRobotType implements MobileRobotType The java
>> classes are in a single jar file and are not duplicated on the classpath.
>>> 
>>> @Resource(lookup = "java:app/osgi/Bundle") Bundle activatorBundle;
>>> public <T> T getService(Class<T> serviceInterface) {
>>>       return activatorBundle.getBundleContext()
>>> 
>> .getService(activatorBundle.getBundleContext().getServiceReference(serviceInt
>> erface));
>>>   }
>> 
>> 
>> I’m not familiar with this @Resource annotation, who defines it and what does
>> it do?
>> 
>> Also the code in the method is dangerous. You should never lookup a service
>> using somebody else’s BundleContext — this could easily lead to errors since
>> OSGi cannot perform its class-space integrity checks. Also where is the code in
>> which you release the reference to the service? You have thrown away the
>> ServiceReference object so I assume you don’t ever actually release the service.
>> 
>> This code would be much better if written as a Declarative Service component
>> with injection of the service using an @Reference annotation.
>> 
>> Regards,
>> Neil
>> 
>>> 
>>> 
>>> Any idea what can be done to solve the linkage error? Maybe any Devs out
>> there of felix itself?
>>> 
>>> Thanks
>>> This message may contain legally privileged or confidential information and is
>> therefore addressed to the named persons only. The recipient should inform the
>> sender and delete this message, if he/she is not named as addressee. The sender
>> disclaims any and all liability for the integrity and punctuality of this message.
>> The sender has activated an automatic virus scanning, but does not guarantee
>> the virus free transmission of this message.
> 
> This message may contain legally privileged or confidential information and is therefore addressed to the named persons only. The recipient should inform the sender and delete this message, if he/she is not named as addressee. The sender disclaims any and all liability for the integrity and punctuality of this message. The sender has activated an automatic virus scanning, but does not guarantee the virus free transmission of this message.


RE: LinkageError, but why?

Posted by Remo Liechti <re...@swisslog.com>.
Hi Neil

Thanks for answering. The point is I can make limited changes to the existing application only.
Basically I created my own main bundle activator that registers the services again that previously were created using regular osgi.

What the activator is doing:
- Configure bundles using the ConfigurationAdmin
- the configured bundles expose their services itself within osgi. I cannot access them outside the main activator.
- due to this, re-register the services again in the main activator, since weblogic classloader would throw classcast Class A to Class A when not doing it

Code of the main activator more or less:
public void start(BundleContext context) throws IOException
  ConfigurationAdmin configAdmin = getConfigurationAdminService(context);
  configAdmin.getConfiguration("com.kuka.task.manager.component", null).update(getTaskManagerConfiguration());
  ServiceReference<?> ref = context.getServiceReference(IExtendedTaskManager.class);
  Object service = context.getService(ref);
  context.registerService(IExtendedTaskManager.class.getName(), service, properties);

After that, the web application can access the task manager service from j2ee.

The @Resource annotation injects the main activator bundle into the web application (see https://docs.oracle.com/middleware/1212/wls/WLPRG/osgi.htm#WLPRG778). It basically is a JNDI lookup.
You  tell the Weblogic container what application to inject like this:
https://docs.oracle.com/middleware/1212/wls/WLPRG/osgi.htm#WLPRG765 Example 16-4 Adding the Framework and Bundle to weblogic-application.xml

The class that causes the Linkage Error is not in multiple jar files, it is within the com.kuka.nav.api bundle. It's there once only, and the jar file is also just once in the lib folder of the web application only.

> Also the code in the method is dangerous. You should never lookup a service
> using somebody else’s BundleContext — this could easily lead to errors since
Well I do not have much of a choice since Weblogic just passes it to me using the @Ressource.

> OSGi cannot perform its class-space integrity checks. Also where is the code in
> which you release the reference to the service? You have thrown away the
> ServiceReference object so I assume you don’t ever actually release the service.

 You are right, a point for improvement. I will change this.

> This code would be much better if written as a Declarative Service component
> with injection of the service using an @Reference annotation.
Unfortunately, this is not supported by Weblogic OSGI to webapplications. This would work within the main activator only, where we cannot put the business logic/api calls.

Thanks,
Remo



> -----Original Message-----
> From: Neil Bartlett [mailto:njbartlett@gmail.com]
> Sent: Donnerstag, 25. August 2016 08:41
> To: dev@felix.apache.org
> Subject: Re: LinkageError, but why?
>
>
> > On 25 Aug 2016, at 07:23, Remo Liechti <re...@swisslog.com> wrote:
> >
> > Hi guys
> >
> > I send this to you since this seems like a more technical issue than the felix user
> mailing list can help me with.
>
> Not really… folks on that list can handle any level of technicality (they are mostly
> the same folks as on this list)!
>
> > I am wrapping an existing osgi application that was running with equinoix into
> a j2ee application that runs on Weblogic. After a few issues, the application
> deploys and run totally fine.
> > I can access it sockets and connect the client to it without issues.
> >
> > But when it comes to accessing the app using the OSGI Services, I can call a
> few methods. However, as soon as I call a method on a service that has non
> Java-Datatypes, I get LinkageErrors, like this one:
> > java.lang.LinkageError: loader constraint violation: loader (instance of
> org/apache/felix/framework/BundleWiringImpl$BundleClassLoaderJava5)
> previously initiated loading for a different type with name
> "com/kuka/nav/robot/MobileRobotType"
> > at
> > com.kuka.nav.fleet.simulation.internal.FleetSimulationImpl.addRobot(Fl
> > eetSimulationImpl.java:137) at
> > com.kuka.nav.fleet.simulation.internal.FleetSimulationImpl.addRobot(Fl
> > eetSimulationImpl.java:177) at
> > com.swisslog.wm6.test.MoveServlet.processRequest(MoveServlet.java:71)
> > at com.swisslog.wm6.test.MoveServlet.doGet(MoveServlet.java:95)
> > at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
>
> LinkageError occurs when a ClassLoader is asked to define a type that has
> already been defined. It would be useful for you to read the OSGi R6 Core
> specification about Class Spaces, i.e. section 3.5 of OSGi.
>
> In OSGi this usually happens when a type is included as a private package in
> multiple bundles. The usual things to look out for are:
> 1. Which bundle(s) export the package com.kuka.nav.robot? This can include the
> system bundle if you are exporting into the framework from outside.
> 2. Do any bundles contain their own copy of types in that package, including
> MobileRobotType?
> 3. How is boot delegation configured in your framework? If this is “*” then it
> could lead to conflicts with bundles.
>
>
> >
> > What I try to achieve is:
> > 69: IResourceManager resMan = getService(IResourceManager.class);
> > 70: FleetSimulation simulation = (FleetSimulation)
> > resMan.getResource("FleetSimulation").getCapability(FleetSimulation.cl
> > ass);
> > 71: simulation.addRobot(new BasicRobotType(7), "Robotinator");
> > 72: simulation.startAllRobots();
> >
> > As you can see, the type to pass to addRobot is of BasicRobotType.
> >
> > We tried with a different method, that instead of a BasicRobotType takes a
> regular integer instead:
> > 69: IResourceManager resMan = getService(IResourceManager.class);
> > 70: FleetSimulation simulation = (FleetSimulation)
> > resMan.getResource("FleetSimulation").getCapability(FleetSimulation.cl
> > ass);
> > 71: simulation.addRobot(7, "Robotinator");
> > 72: simulation.startAllRobots();
> > This works fine then. But this also means we would have to change the API
> significantly and to a low level API who nobody likes.
> >
> > Information about the classes:
> > public interface MobileRobotType
> > public final class BasicRobotType implements MobileRobotType The java
> classes are in a single jar file and are not duplicated on the classpath.
> >
> > @Resource(lookup = "java:app/osgi/Bundle") Bundle activatorBundle;
> > public <T> T getService(Class<T> serviceInterface) {
> >        return activatorBundle.getBundleContext()
> >
> .getService(activatorBundle.getBundleContext().getServiceReference(serviceInt
> erface));
> >    }
>
>
> I’m not familiar with this @Resource annotation, who defines it and what does
> it do?
>
> Also the code in the method is dangerous. You should never lookup a service
> using somebody else’s BundleContext — this could easily lead to errors since
> OSGi cannot perform its class-space integrity checks. Also where is the code in
> which you release the reference to the service? You have thrown away the
> ServiceReference object so I assume you don’t ever actually release the service.
>
> This code would be much better if written as a Declarative Service component
> with injection of the service using an @Reference annotation.
>
> Regards,
> Neil
>
> >
> >
> > Any idea what can be done to solve the linkage error? Maybe any Devs out
> there of felix itself?
> >
> > Thanks
> > This message may contain legally privileged or confidential information and is
> therefore addressed to the named persons only. The recipient should inform the
> sender and delete this message, if he/she is not named as addressee. The sender
> disclaims any and all liability for the integrity and punctuality of this message.
> The sender has activated an automatic virus scanning, but does not guarantee
> the virus free transmission of this message.

This message may contain legally privileged or confidential information and is therefore addressed to the named persons only. The recipient should inform the sender and delete this message, if he/she is not named as addressee. The sender disclaims any and all liability for the integrity and punctuality of this message. The sender has activated an automatic virus scanning, but does not guarantee the virus free transmission of this message.

Re: LinkageError, but why?

Posted by Neil Bartlett <nj...@gmail.com>.
> On 25 Aug 2016, at 07:23, Remo Liechti <re...@swisslog.com> wrote:
> 
> Hi guys
> 
> I send this to you since this seems like a more technical issue than the felix user mailing list can help me with.

Not really… folks on that list can handle any level of technicality (they are mostly the same folks as on this list)!

> I am wrapping an existing osgi application that was running with equinoix into a j2ee application that runs on Weblogic. After a few issues, the application deploys and run totally fine.
> I can access it sockets and connect the client to it without issues.
> 
> But when it comes to accessing the app using the OSGI Services, I can call a few methods. However, as soon as I call a method on a service that has non Java-Datatypes, I get LinkageErrors, like this one:
> java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/felix/framework/BundleWiringImpl$BundleClassLoaderJava5) previously initiated loading for a different type with name "com/kuka/nav/robot/MobileRobotType"
> at com.kuka.nav.fleet.simulation.internal.FleetSimulationImpl.addRobot(FleetSimulationImpl.java:137)
> at com.kuka.nav.fleet.simulation.internal.FleetSimulationImpl.addRobot(FleetSimulationImpl.java:177)
> at com.swisslog.wm6.test.MoveServlet.processRequest(MoveServlet.java:71)
> at com.swisslog.wm6.test.MoveServlet.doGet(MoveServlet.java:95)
> at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)

LinkageError occurs when a ClassLoader is asked to define a type that has already been defined. It would be useful for you to read the OSGi R6 Core specification about Class Spaces, i.e. section 3.5 of OSGi.

In OSGi this usually happens when a type is included as a private package in multiple bundles. The usual things to look out for are:
1. Which bundle(s) export the package com.kuka.nav.robot? This can include the system bundle if you are exporting into the framework from outside.
2. Do any bundles contain their own copy of types in that package, including MobileRobotType?
3. How is boot delegation configured in your framework? If this is “*” then it could lead to conflicts with bundles.


> 
> What I try to achieve is:
> 69: IResourceManager resMan = getService(IResourceManager.class);
> 70: FleetSimulation simulation = (FleetSimulation) resMan.getResource("FleetSimulation").getCapability(FleetSimulation.class);
> 71: simulation.addRobot(new BasicRobotType(7), "Robotinator");
> 72: simulation.startAllRobots();
> 
> As you can see, the type to pass to addRobot is of BasicRobotType.
> 
> We tried with a different method, that instead of a BasicRobotType takes a regular integer instead:
> 69: IResourceManager resMan = getService(IResourceManager.class);
> 70: FleetSimulation simulation = (FleetSimulation) resMan.getResource("FleetSimulation").getCapability(FleetSimulation.class);
> 71: simulation.addRobot(7, "Robotinator");
> 72: simulation.startAllRobots();
> This works fine then. But this also means we would have to change the API significantly and to a low level API who nobody likes.
> 
> Information about the classes:
> public interface MobileRobotType
> public final class BasicRobotType implements MobileRobotType The java classes are in a single jar file and are not duplicated on the classpath.
> 
> @Resource(lookup = "java:app/osgi/Bundle") Bundle activatorBundle;
> public <T> T getService(Class<T> serviceInterface) {
>        return activatorBundle.getBundleContext()
>                .getService(activatorBundle.getBundleContext().getServiceReference(serviceInterface));
>    }


I’m not familiar with this @Resource annotation, who defines it and what does it do?

Also the code in the method is dangerous. You should never lookup a service using somebody else’s BundleContext — this could easily lead to errors since OSGi cannot perform its class-space integrity checks. Also where is the code in which you release the reference to the service? You have thrown away the ServiceReference object so I assume you don’t ever actually release the service.

This code would be much better if written as a Declarative Service component with injection of the service using an @Reference annotation.

Regards,
Neil

> 
> 
> Any idea what can be done to solve the linkage error? Maybe any Devs out there of felix itself?
> 
> Thanks
> This message may contain legally privileged or confidential information and is therefore addressed to the named persons only. The recipient should inform the sender and delete this message, if he/she is not named as addressee. The sender disclaims any and all liability for the integrity and punctuality of this message. The sender has activated an automatic virus scanning, but does not guarantee the virus free transmission of this message.