Access Drools Guvnor from OSGI bundle - java

I am using following code to access Drools Guvnor:
KnowledgeAgentConfiguration kaconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent("MyAgent", kaconf);
kagent.applyChangeSet(ResourceFactory.newClassPathResource("drools/change-set.xml"));
StatefulKnowledgeSession ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
Unfortunately KnowledgeAgentFactory class does not seem to be OSGI ready as it uses Class.forName() to load agent provider. KnowledgeAgentFactory resides in knowledge-api bundle, and provider implementation in drools-core bundle. Obviously knowledge-api doesn't see drools-core in OSGI container. As a result I get following exception:
Caused by: java.lang.RuntimeException: Provider org.drools.agent.impl.KnowledgeAgentProviderImpl could not be set.
at org.drools.agent.KnowledgeAgentFactory.loadProvider(KnowledgeAgentFactory.java:191)[162:org.drools.api:5.5.0.Final]
at org.drools.agent.KnowledgeAgentFactory.getKnowledgeAgentProvider(KnowledgeAgentFactory.java:178)[162:org.drools.api:5.5.0.Final]
at org.drools.agent.KnowledgeAgentFactory.newKnowledgeAgentConfiguration(KnowledgeAgentFactory.java:129)[162:org.drools.api:5.5.0.Final]
Is there workaround for this issue?

You might help yourself with a require-bundle manifest entry since it doesn't seem to work correctly with those imports and I'd say at that point it's probably the best to get it working that way.
Require-Bundle as defined in the osgi wiki

Related

JAXB not available on Tomcat 9 and Java 9/10

TLDR: On Java 9/10, a web app in Tomcat has no access to JAXB even though its reference implementation is present on the class path.
Edit: No, this is not a duplicate of How to resolve java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException in Java 9 - as you can tell by the What I tried section, I already tried the proposed solutions.
The Situation
We have a web app that runs on Tomcat and depends on JAXB. During our migration to Java 9 we opted for adding the JAXB reference implementation as a regular dependency.
Everything worked when launching the app from the IDE with embedded Tomcat, but when running it on a real Tomcat instance, I get this error:
Caused by: java.lang.RuntimeException: javax.xml.bind.JAXBException:
Implementation of JAXB-API has not been found on module path or classpath.
- with linked exception:
[java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory]
at [... our-code ...]
Caused by: javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:278) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.find(ContextFinder.java:421) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662) ~[jaxb-api-2.3.0.jar:2.3.0]
at [... our-code ...]
Caused by: java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory
at jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582) ~[?:?]
at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:190) ~[?:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:499) ~[?:?]
at javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:122) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:155) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:276) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.find(ContextFinder.java:421) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662) ~[jaxb-api-2.3.0.jar:2.3.0]
at [... our-code ...]
Note:
Implementation of JAXB-API has not been found on module path or classpath.
These are the relevant files in webapps/$app/WEB-INF/lib:
jaxb-api-2.3.0.jar
jaxb-core-2.3.0.jar
jaxb-impl-2.3.0.jar
What is going on here?
What I tried
Adding JARs to Tomca's CLASSPATH
Maybe it helps to add the JARs to Tomcat's class path in setenv.sh?
CLASSPATH=
.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar:
.../webapps/$app/WEB-INF/lib/jaxb-impl-2.3.0.jar:
.../webapps/$app/WEB-INF/lib/jaxb-core-2.3.0.jar:
.../webapps/$app/WEB-INF/lib/javax.activation-1.2.0.jar
Nope:
Caused by: javax.xml.bind.JAXBException: ClassCastException: attempting to cast
jar:file:.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar!/javax/xml/bind/JAXBContext.class to
jar:file:.../webapps/$app/WEB-INF/lib/jaxb-api-2.3.0.jar!/javax/xml/bind/JAXBContext.class.
Please make sure that you are specifying the proper ClassLoader.
at javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:157) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:300) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:286) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.ContextFinder.find(ContextFinder.java:409) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721) ~[jaxb-api-2.3.0.jar:2.3.0]
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662) ~[jaxb-api-2.3.0.jar:2.3.0]
at de.disy.gis.webmapserver.factory.DefaultWmsRequestFactory.initializeCommandExtractor(DefaultWmsRequestFactory.java:103) ~[cadenza-gis-webmapserver-7.7-SNAPSHOT.jar:7.6]
at de.disy.gis.webmapserver.factory.DefaultWmsRequestFactory.lambda$new$0(DefaultWmsRequestFactory.java:87) ~[cadenza-gis-webmapserver-7.7-SNAPSHOT.jar:7.6]
That's clearly the same class, so apparently it has been loaded by two class loaders. I suspect the system class loader and the app's class loader, but why would loading JAXBContext be delegated to the system class loader once but not always? It almost looks as if the delegation behavior of the app's class loader changes while the program runs.
Adding the module
I don't really want to add java.xml.bind, but I tried it anyways by adding this to catalina.sh:
JDK_JAVA_OPTIONS="$JDK_JAVA_OPTIONS --add-modules=java.xml.bind"
Doesn't work either, though:
Caused by: java.lang.ClassCastException:
java.xml.bind/com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl
cannot be cast to com.sun.xml.bind.v2.runtime.JAXBContextImpl
at [... our-code ...]
Apart from the different class and stack trace, this is in line with what happened earlier: The class JAXBContextImpl was loaded twice, once from java.xml.bind (must have been the system class loader) and one other time (I assume by the app's loader from the JAR).
Searching for bugs
Searching Tomcat's bug database I found #62559. Could that be the same error?
Adding JAR's to Tomcat's lib
Following advice given on the Tomcat user mailing list, I added the JAXB JARs to Tomcat's CATALINA_BASE/lib directory, but got the same error as in the application's lib folder.
Analysis
First some random facts:
if not given a class loader, JAXBContext::newInstance will use the thread's context class loader when looking for the JAXB implementation - this is the case even if you call newInstance(Class...) (one might mistakenly think it uses the provided class instances' loader)
Tomcat builds a small class loader hierarchy to separate web applications from one another
by not relying on the module java.xml.bind, in Java 9, JAXB classes are not loaded by the bootstrap or system class loader
So here's what happened on Java 8:
we don't pass a class loader to JAXB (oops), so it uses the thread's context class loader
our conjecture is that Tomcat does not explicitly set the context class loader and so it will end up being the same one that loaded Tomcat: the system class loader
that's dandy because the system class loader sees the entire JDK and hence the JAXB implementation included therein
Java 9 enters - the piano stops playing and everybody puts down their scotch:
we added JAXB as a regular dependency and so it is loaded by the web app's class loader
just as on Java 8, JAXB searches the system class loader, though, and that one can't see the app's loader (only the other way around)
JAXB fails to find the implementation and goes belly up
Solution
The solution is to make sure JAXB uses the right class loader. We know of three ways:
call Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); but that's not really a good idea
create a context resolver, but that requires JAX-WS and that feels like replacing one evil with another
use the package-accepting variant of JAXBContext::newInstance (Javadoc from Java EE 7) that also takes a class loader and pass the correct loader, although that requires some refactoring
We used the third option and refactored towards the package-accepting variant of JAXBContext::newInstance. Menial work, but fixed the problem.
Note
User curlals provided the critical piece of information, but deleted their answer. I hope it was not because I asked for a few edits. All credit/karma should go to them! #curlals: If you restore and edit your answer, I will accept and upvote it.
Try the following and its dependencies. See a Maven repository for latest version.
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.0.1</version>
</dependency>
It also contains the Java Service Loader descriptors. See Using JAXB in Java 9+
I had this issue using Spring Boot (version 2.2.6) with embedded Tomcat in a specific part of my code where I used a CompletableFuture. The code worked perfectly with Java 8 and related unit test passed in Java 12. The issue appeared only when the application was executed inside Tomcat using Java 11 or 12.
Debugging the problem I discovered the issue was related to the fact that a different ClassLoader is used inside the CompletableFuture's Runner.
// here Thread.currentThread().getContextClassLoader().getClass()
// returns org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader
return CompletableFuture.runAsync(() -> {
// here returns jdk.internal.loader.ClassLoaders$AppClassLoader
});
The second ClassLoader is not able to load the JAXB classes. This behavior seems to be present only with Java 9+, indeed before Java 9 ForkJoinPool.common() returned an Executor with a ClassLoader of your main Thread, but after Java 9 it returns an executor with system ClassLoader.
Since the CompletableFuture.runAsync() method accepts an Executor as second parameter, it is possible to set the desired Executor in the code. Here an example of a possible solution.
First, define a proper ForkJoinWorkerThreadFactory:
public class JaxbForkJoinWorkerThreadFactory implements ForkJoinWorkerThreadFactory {
private final ClassLoader classLoader;
public JaxbForkJoinWorkerThreadFactory() {
classLoader = Thread.currentThread().getContextClassLoader();
}
#Override
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
ForkJoinWorkerThread thread = new JaxbForkJoinWorkerThread(pool);
thread.setContextClassLoader(classLoader);
return thread;
}
private static class JaxbForkJoinWorkerThread extends ForkJoinWorkerThread {
private JaxbForkJoinWorkerThread(ForkJoinPool pool) {
super(pool);
}
}
}
Then pass an Executor using that factory to the runAsync() method:
return CompletableFuture.runAsync(() -> {
// now you have the right ClassLoader here
}, getJaxbExecutor());
private ForkJoinPool getJaxbExecutor() {
JaxbForkJoinWorkerThreadFactory threadFactory = new JaxbForkJoinWorkerThreadFactory();
int parallelism = Math.min(0x7fff /* copied from ForkJoinPool.java */, Runtime.getRuntime().availableProcessors());
return new ForkJoinPool(parallelism, threadFactory, null, false);
}
TL;DR
A simple solution that worked for me is just to upgrade the Hibernate version.
I used Hibernate with version of 5.2.10.Final and they rely on JAXB. However, when I replaced undertow with Tomcat, that dependency went missing. I found this issue but none of the answers really solved my issue. When I found that jpa-model-gen was the issue I quickly realized, that it is the onlt Hibernate dependecy only that is looking for JAXB. Updating the hibernate version to a higher one solved my problem.
I too have experienced with the similar issue while using JAXB, i.e
Implementation of JAXB-API has not been found
which occurs randomly and it was harder to reproduce. Fortunately I had found a system environment where the above error is continuous, while other environments it worked smoothly.
Observation
With the extensive research into this issue, I found a classloader issue that causes this problem. Further I noticed,
JAXB implementation is visible to ParallelWebappClassLoader, a classloader present in Tomcat server
Sometimes it is not visible to jdk internal classloaders like AppClassLoader,(Even though it was visible for many cases)
Solution
JAXBContext object is thread-safe (while marshaller/unmarshaller is not) and can be re-used once initiated. Therefore,
I found a thread that works with ParallelWebappClassLoader (i.e that given thread's context class loader is ParallelWebappClassLoader) and created JAXBContext there and stored in a map for later usage
Retrieved the stored JAXBContext whenever necessary (other threads that uses different class loaders) and carried out marshall/unmarshall tasks. That saved the day for me :)

java.lang.NoClassDefFoundError: Could not initialize class com.amazonaws.ClientConfiguration

Using this bundle - aws-java-sdk-osgi-1.11.26.jar in OSGI Server
Below Error is thrown when this is executed AmazonS3 s3 = new AmazonS3Client( credentials );
java.lang.NoClassDefFoundError: Could not initialize class com.amazonaws.ClientConfiguration
at com.amazonaws.ClientConfigurationFactory.getDefaultConfig(ClientConfigurationFactory.java:46)
at com.amazonaws.ClientConfigurationFactory.getConfig(ClientConfigurationFactory.java:36)
at com.amazonaws.services.s3.AmazonS3Client.<init>(AmazonS3Client.java:440)
Any solution to fix this?
Thanks for all suggestions
The ClientConfiguration of
aws-java-sdk-osgi-1.11.26.jar is dependent of Jackson-databind.jar
Jackson-databind.jar is dependent on Jackson-core.jar
So it is not able to initialize ClientConfiguration.
Added Import-Package importing all from jackson-core-osgi.jar in Manifest of Jackson-databind-osgi.jar
Then the issue is resolved
Note: All dependent jars are converted to OSGI jars and deployed
Well, make sure that aws-java-sdk-osgi-1.11.26.jar is present on your classpath, because the class itself is present in the jar.
I've just downloaded the jar.
I guess you are missing an Import-Package statement in your bundle Manifest. Not sure how you build your bundle but I would recommend to use bnd in some form for it. For example I typically use the maven-bundle-plugin which uses bnd under the hood. Bnd is able to figure out the imports automatically for most cases.
In my case, restarting the flink cluster solved the problem.

Can't get a working reference to an OSGi service

I'm trying to embed apache felix into a simple hello world java project with maven, but I can't find a way to get a reference to a service of a bundle. I've installed org.apache.felix.bundlerepository bundle into OSGi from a jar and also added it as a maven dependency to my project. After that I'm starting the bundle, getting BundleContext from it and then calling getServiceReference(RepositoryAdmin.class.getName()) on that bundle context. The first thing I'm unhappy with is that I have to use BundleContext from the installed bundle, if I'd use BundleContext of the Framework the ServiceReference will be always null. This is not convinient.
The second, more important issue, is that when I finally receiving a reference to RepositoryAdmin service from bundlerepository bundle I can't cast it to org.apache.felix.bundlerepository.RepositoryAdmin, executing the following code:
(RepositoryAdmin)admin.getBundleContext().getService(ref)
will throw this exception:
java.lang.ClassCastException: org.apache.felix.bundlerepository.impl.RepositoryAdminImpl cannot be cast to org.apache.felix.bundlerepository.RepositoryAdmin
I know this is a kind of classpath issue and may be caused by incompatibility of interfaces, but I'm using a bundle jar of the same version (2.0.2) as a maven dependency of my project.
I'm also aware of Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA osgi configuration option which should force a bundle to use a package from the host application, but it didnt help me.
Here is the main class of my project https://github.com/ArtemZ/osgi-study/blob/master/src/main/java/com/artemz/demo/Main.java which is messy because I was trying different things on it in order to get a reference to a service, but none actually worked for me.
Hope someone will help me, because I'm really desperate with this issue.
Thanks for giving some more details about what you are doing. I already followed the mails on the felix list.
Now I think I understand what happens. The reason why you can not get the service from outside the RepositoryAdmin bundle is that the package you define in
FRAMEWORK_SYSTEMPACKAGES_EXTRA is "org.apache.felix.bundlerepository; version=2.0.2"
is not the same version as the package from the RepositoryAdmin bundle. I downloaded the bundle and looked into the Manifest:
Export-Package: org.osgi.service.repository;version="1.0";uses:="org.osg
i.resource",org.apache.felix.bundlerepository;version="2.1";uses:="org.
osgi.framework"
So as you see the version you should export from the system bundle is 2.1 not 2.0.2.
In OSGi the versions are defined per package not on the bundle level. So while most times they are the same this is not always true. Espcecially for OSGi spec packages.
So when the package version are different you have two effects:
1. You will not be able to find a service with a different package
2. If you get a service object in some other way like you did then you will have a class cast exception as they are loaded by different classloaders.
So can you try the 2.1 version and report if it works?

LogConfigurationException when using HttpClient

When my code executes this line:
DefaultHttpClient httpclient = new DefaultHttpClient();
I'm getting this Exception:
org.apache.commons.logging.LogConfigurationException: Class org.apache.commons.logging.impl.Log4JLogger does not implement Log
does somebody know how can I solve that?
Maybe is not important (or maybe it is), but the app is a plugin for Jira, and is using Maven for the dependencies.
Thanks !
EDIT:
EDIT 2:
Could this be related with OSGi from Jira?
How can I use commons-logging in an OSGi environment?
From here:
http://wiki.apache.org/commons/Logging/FrequentlyAskedQuestions
Commons-logging was not designed with OSGi in mind. This is why it is
difficult to get commons-logging working in OSGi environments:
LogFactory loads Log implementations by name (see
Class.forName(String)). This is usually not possible in OSGi since
every bundle classloader can only see the classes a bundle defines
imports for. The bundle class loader that loads the commons-logging
bundle will not have access to user provided
commons-logging.properties files. commons-logging-api.jar contains
classes that are also included in commons-logging.jar. This is
contrary to traditional OSGi application architectures where one
bundle defines an API and other bundles provide implementations for
that API. There alternatives to using commons-logging directly in OSGi
are:
Rebundled versions that contain proper OSGi meta data are available
from Apache Felix, SpringSource and Eclipse Orbit. Using Pax logging.
Further information about this topic is available in the archives of
the commons dev ML and the felix dev ML and in Jira.
and when I try to access to the OSGi tab from Jira (going to JIRASERVER/plugins/servlet/upm/osgi#osgi) I can see an exception:
classNotFoundException: org.apache.commons.logging.impl.SLF4JLogFactory
And also I can see from the IDE (when searching for Log4JLogger class) that I have two definitions:
package org.apache.commons.logging.impl.Log4JLogger
public class Log4JLogger implements Log, Serializable {
and
package com.atlassian.extras.common.log;
class Log4jLogger implements com.atlassian.extras.common.log.Logger.Log {
this is really confusing....
I'm not sure, but could it be that the logger you configured does not correspond to the logger in your pom dependencies? Perhaps a different version?

REST client inside of OSGi application

I need to integrate a REST client into an existing OSGi application implemented using Apache Felix. The REST service is based on RESTeasy implementation (version 2.3.2.Final) of JAX-RS. I created a separate bundle with clients' dependencies, exporting required RESTeasy packages and importing them in the bundle where the client is used, but unfortunately I cannot get it working inside of the OSGi context.
I tried two different approaches. First one using the generic ClientRequest:
ClientRequest request = new ClientRequest(MyService.URL_TEST+"/stats");
request.body(javax.ws.rs.core.MediaType.APPLICATION_XML, stats);
ClientResponse<String> response = request.post(String.class);
The error that I get in this case is pretty weird:
[java] java.lang.RuntimeException: java.lang.ClassCastException:
org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor cannot be cast to
org.jboss.resteasy.client.ClientExecutor
where I it is known for sure that ApacheHttpClient4Executor implements the ClientExecutor interface.
When I try to use my own REST client wrapper around RESTeasy like this:
MyService myService = MyServiceClient.getInstance();
myService.saveStatistics(stats);
I get a different exception:
[java] java.lang.LinkageError: ClassCastException: attempting to
castjar:file:/D:/Development/Eclipses/eclipse_4.2_j2ee_x64/lib/jaxrs-api-2.3.2.Final.jar
!/javax/ws/rs/ext/RuntimeDelegate.classtobundle:
//78.0:1/javax/ws/rs/ext/RuntimeDelegate.class
As far as I understand, the LinkageError most probably has to do with the way RESTeasy initializes the RuntimeDelegate using some classloader tricks, which probably fall under the restrictions of OSGi framework. I get the suspicion that the java.lang.ClassCastException mentioned first has the same source.
Is there any way to get RESTeasy working inside of OSGi?
PS: discussion about a similar issue with RESTeasy, but outside of OSGi: java.lang.LinkageError: ClassCastException
Update:
these are the libraries included into restclient bundle:
activation-1.1.jar commons-codec-1.2.jar commons-httpclient-3.1.jar commons-io-2.1.jar commons-logging-1.0.4.jar flexjson-2.1.jar httpclient-4.1.2.jar httpcore-4.1.2.jar javassist-3.12.1.GA.jar jaxb-api-2.2.3.jar jaxb-impl-2.2.4.jar jaxrs-api-2.3.2.Final.jar jcip-annotations-1.0.jar jettison-1.3.1.jar jsr250-api-1.0.jar junit-4.10.jar log4j-1.2.14.jar resteasy-jaxb-provider-2.3.2.Final.jar resteasy-jaxrs-2.3.2.Final.jar resteasy-jettison-provider-2.3.2.Final.jar scannotation-1.0.3.jar slf4j-api-1.6.4.jar slf4j-log4j12-1.6.4.jar myservice-common-0.1.0.3.jar my-service-client-0.1.0.3-SNAPSHOT.jar stax-api-1.0-2.jar xmlpull-1.1.3.1.jar xpp3_min-1.1.4c.jar xstream-1.4.2.jar
These are the exports from the restclient bundle: javax.ws.rs, javax.ws.rs.ext, javax.ws.rs.core, org.jboss.resteasy.client, org.jboss.resteasy.client.cache, org.jboss.resteasy.client.extractors, org.jboss.resteasy.client.marshallers, org.jboss.resteasy.client.core.executors, javax.xml.bind.annotation, org.jboss.resteasy.plugins.providers, org.jboss.resteasy.plugins.providers.jaxb, org.jboss.resteasy.spi
Have a look at the SpringSource Bundle Repo, it's got some very useful pre-built bundles of common libraries including the Apache HTTP Client which we are using (in conjunction with gson) to do our RESTful comms.
(unfortunately a legacy module of my project still uses OSGi, but using RESTeasy 3.0.16 now)
When I need to OSGify a dependency my preferred solution now is to wrap it using the excellent Apache Ops4j Pax Tipi project.
The project provides a preconfigured Maven setup (parent POM handles the bundling) and you just have to adapt the GAV coordinates of the original project in a Tipi sub module with a org.apache.ops4j.pax.tipi prefix and build the new bundle project which draws in the original dependency, unpacks and wraps it as OSGi bundle.
You can start from an existing Tipi sub project that best matches your project setup (dependencies, etc.) and adapt any OSGi imports/exports missing (most often, these are created automatically by the maven-bundle-plugin anyway).
This worked quite well for me as long as the original project did not contain too many exotic or malformed dependencies.
However you may run into snags like transitive dependencies using the root package, as I currently experience, which can be a real show stopper (finding out which library is a real nightmare).
Unfortunately, RESTeasy seems to be affected by this, as I get exactly the same error (default package , even after declaring non-test and non-provided dependencies as optional:
The default package '.' is not permitted by the Import-Package syntax.
Upgrading the maven-bundle-plugin to the latest release 3.0.1 yields a different error (even less helpful):
[ERROR] Bundle org.ops4j.pax.tipi:org.ops4j.pax.tipi.resteasy-jaxrs:bundle:3.0.16.Final.1 : Can not parse name from bundle native code header:
[ERROR] Error(s) found in bundle configuration
Update seems to be solved by upping Tipi version in POM to 1.4.0, testing...
Is RESTEasy mandatory ?
I personally use jersey in OSGi and it is working perfectly, both as client and server.
This problem isn't limited to RESTeasy. It also occurs with Jersey.
It is occurring because you have two copies of the JAX-RS classes on the classpath.
You can see this in the LinkageError:
[java] java.lang.LinkageError: ClassCastException: attempting to cast jar:file:/D:/Development/Eclipses/eclipse_4.2_j2ee_x64/lib/jaxrs-api-2.3.2.Final.jar!/javax/ws/rs/ext/RuntimeDelegate.class to bundle://78.0:1/javax/ws/rs/ext/RuntimeDelegate.class
i.e. one copy is coming from:
D:/Development/Eclipses/eclipse_4.2_j2ee_x64/lib/jaxrs-api-2.3.2.Final.jar
and the other from the OSGI bundle.
This causes problems for the RuntimeDelegate class, which by default uses the system class loader to create the RuntimeDelegate implementation (see javax.ws.rs.ext.FactoryFinder).
The problem can also occur if the same jar is loaded via two different class loaders.
There are a couple of workarounds:
remove the jaxrs-api-2.3.2.Final.jar from the system class path
set the thread context class loader to that of your bundle, prior to making any JAX-RS calls.
The FactoryFinder will use this to load the RuntimeDelegate.
To avoid polluting your code with calls to Thread.currentThread().setContextClassLoader(myBundleClassLoader), you can wrap your JAX-RS client using a Proxy. e.g. see the Thread context classloader section of https://puredanger.github.io/tech.puredanger.com/2007/06/15/classloaders/

Categories

Resources