I am trying to use JAVA gRPC in an OSGi bundle. I am using maven and using org.apache.servicemix.bundles.grpc-1.30.2_1 which is locally built from the release tag for 1.30.2_1.
The OSGi bundle starts up fine without any issue but at runtime when a ManageChannel is created I get a java.lang.IllegalArgumentException: cannot find a NameResolver for localhost:4435 exception.
The relevant part of the stacktrace
java.lang.IllegalArgumentException: cannot find a NameResolver for localhost:4435
at io.grpc.internal.ManagedChannelImpl.getNameResolver(ManagedChannelImpl.java:724) ~[org.apache.servicemix.bundles.grpc-1.30.2_1.jar:?]
at io.grpc.internal.ManagedChannelImpl.<init>(ManagedChannelImpl.java:606) ~[org.apache.servicemix.bundles.grpc-1.30.2_1.jar:?]
at io.grpc.internal.AbstractManagedChannelImplBuilder.build(AbstractManagedChannelImplBuilder.java:518) ~[org.apache.servicemix.bundles.grpc-1.30.2_1.jar:?]
When I debug the gRPC code at runtime I can see that there is zero NameResolvers added. I think that this can be a classloading issue.
This is part of the config from the Apache Felix plugin,
<Import-Package>
...,
org.apache.servicemix.bundles.grpc.*; version="1.30.2_1",
io.grpc*;
</Import-Package>
<Embed-Dependency>org.apache.servicemix.bundles.grpc;scope=compile</Embed-Dependency>
Channel building code (This is using io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder)
ManagedChannel channel = NettyChannelBuilder.forAddress("localhost", 4435)
.usePlaintext()
.build();
I only need to get the gRPC client working in the OSGi bundle.
Any help on this is much appreciated.
Adding the relevant gRPC providers in the META-INF/services worked.
Got it figured out by referencing this, which also uses gRPC inside a OSGi bundle
https://github.com/wso2/micro-integrator/tree/v1.2.0-m4/components/mediation/inbound-endpoints/org.wso2.micro.integrator.inbound.endpoint
Related
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?
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?
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/
I am having problems with adding a protocol handler for LDAP on OSGi environment. I tried:
System.setProperty("java.protocol.handler.pkgs", "iaik.x509.net");
-Djava.protocol.handler.pkgs=iaik.x509.net in the Run Settings
but still get the java.net.MalformedURLException: unknown protocol: ldap
The protocol Handler for LDAP is in iaik.x509.net and is exported by its bundle.
I am importing that bundle (that has iaik.x509.net) too. To me it seems that the System cannot find the package though. How do I "register" that protocol handler correctly?
I am running equinox 3.6.0 using java 1.6.
Shouldn't the property be: -Djava.protocol.handler.pkgs=iaik.x509.net.ldap (it needs to be the package of the class extending URLConnection, from looking at this). To use it like this you'll have to add it to the Jar to boot classpath and export that package as part of the system bundle with org.osgi.framework.system.packages.extra=iaik.x509.net.ldap
Alternatively turn it into a first class OSGi component. Create a bundle that provides a wrapper for the handler with an implementation of org.osgi.service.url.URLStreamHandlerService that exports a service property url.handler.protocol=ldap
It's not much work to add a small bundle exporting the URLStreamHandlerService, this is definitely the way I'd go.
Try to install iaik.x509.net bundle as a Framework extension bundle. It should contain MANIFEST header:
Fragment-Host: system.bundle; extension:=bootclasspath
In this case LDAP protocol handler will be available for all bundles as a part of bootclasspath. Don't forget to set system property.
More details for extension bundles: OSGi Core Spec 4.2 - Chapter 3.14
I've a web-service that works fine when I access them from a J2SE (desktop) application. To access this service I do follow:
generate stub classes by wsdl link using java wsimport tool
then I create service using generated classes and run one of wsdl operations.It looks like this:
MyWebServiceService webService = new MyWebServiceService();
MyWebService port = webService.getMyWebServicePort();
webService.run("XYZ");
As I sad it work fine when I use it in a standalone application.
But...when I try to access web-service in the same way but from servlet-client, using generated stubs I get following error:
java.lang.ClassCastException: com.sun.xml.bind.v2.runtime.JAXBContextImpl cannot be cast to com.sun.xml.bind.api.JAXBRIContext
org.jboss.ws.metadata.umdm.EndpointMetaData.eagerInitializeAccessors(EndpointMetaData.java:686)
org.jboss.ws.metadata.umdm.EndpointMetaData.initializeInternal(EndpointMetaData.java:567)
org.jboss.ws.metadata.umdm.EndpointMetaData.eagerInitialize(EndpointMetaData.java:553)
org.jboss.ws.metadata.builder.jaxws.JAXWSClientMetaDataBuilder.rebuildEndpointMetaData(JAXWSClientMetaDataBuilder.java:314)
org.jboss.ws.core.jaxws.spi.ServiceDelegateImpl.getPortInternal(ServiceDelegateImpl.java:271)
org.jboss.ws.core.jaxws.spi.ServiceDelegateImpl.getPort(ServiceDelegateImpl.java:202)
javax.xml.ws.Service.getPort(Service.java:143...
I've searched google long time but found nothing helpful topics. Some topics show examples accessing web-services from servlet, but unfortunately I can't do this...( And don't know what is cause of trouble.
Application server: jboss 4.2.3GA
Is it possible to connect web-service from servlet? How?
I've tried use #WebServiceRef annotation, but it seem web-container can't inject web-service stub. And I think that container must not do this itself, because stub classes have already been generated by wsimport tool, and its enouph to use this classes for accessing of web-service.
Stub classes were generated using the following command:
wsimport -keep -p com.myhost.ws http://www.myhost.com/services/MyWebService?wsdl
Did you make sure your classpath does not contain multiple JAX-B Jars with differing versions ? The exception looks like a version conflict to me. Application servers usually have some kind of "endorsed" lib directory that holds JARS that are always added in front of web application classpaths. Maybe your app server has a conflicting JAX-B implementation there ?
If you use Maven to package your application, make sure transitive dependencies don't pull in unwanted JAX-B Jars (use 'mvn dependency:tree' to check this).
This definitely sounds like a JAXB conflict to me. Check out the jaxb versions that you have in your war and make sure that they are not conflicting with a jaxb jar that Jboss may have in its lib directory.
Addytionally if jbossws-native library was installed correctly the following packages should be deleted from jboss_home/lib/endorsed directory:
jboss-jaxrpc.jar
jboss-jaxws-ext.jar
jboss-jaxws.jar
jboss-saaj.jar
Otherwise you don't have ability to connect to web service through EJB or servlet.