OSGi Equinox: howto add protocol handler for LDAP? - java

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

Related

gRPC Java cannot find a NameResolver when using in OSGi bundle

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

BundleException while trying to start an osgi bundle

I'm trying to install & start a bundle from a osgi jar in the filesystem
Bundle bundle = context.installBundle("reference:file:" + fullPath);
bundle.start();
it worked for another simple bundle, but another more complex bundle has
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
in its manifest
this causes the following exception
(org.osgi.framework.BundleException) org.osgi.framework.BundleException: Unresolved constraint in bundle
Unable to resolve 42.0: missing requirement [42.0] osgi.ee; (&(osgi.ee=JavaSE)(version=1.8))
how do I add this capability to my project?
also how would I remove this require from the other project?
all similiar questions I found didn't answer my question
thanks in advance for any answers and for helping me not pull out my hair :)
Edit:
as christian suggested I tried finding the configuration to felix in netbeans, as the felix framework is loaded by netbeans. I found some configurations inside the maven POM file, but could not use the "org.osgi.framework.system.capabilities" framework property which was mentioned by christian, which I couldn't find in the documentation.
I am putting a bounty as this is really important for me to resolve and is the only thing preventing me from using OSGi as far as I can see
The capability you identified:
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
is a requirement for the osgi.ee namespace. This is the namespace which defines the execution environment for your framework. The filter then says that you need the execution environment to be JavaSE, and that you need the version attribute to be 1.8. This (unsurprisingly) corresponds to Java SE 8.
As others have indicated, this capability should be provided by the OSGi framework. You should not need to do anything to get this to happen. There are two main reasons that this capability would not be present.
You are using an older, or non SE, version of Java. This could easily happen if your NetBeans launch configuration is not using a Java 8 installation.
You are using a Felix framework which does not understand "new" versions of Java. This could be because your Felix framework is old (the latest version is 5.6.4) or because your Java version is very new (are you using a pre-release Java 9 build?).
This really should just work if you can run a newish Felix framework on top of Java 8. Do you have any more details about your environment?
Edit:
You can see the osgi.ee capability provided by the system bundle as follows:
// Get the wiring for the system bundle
BundleWiring wiring = context.getBundle(0).adapt(BundleWiring.class);
// Get the osgi.ee capability for the system bundle
List<Capability> eecaps = wiring.getCapabilities("osgi.ee");
// There must be exactly one capability to show
System.out.println(eecaps.get(0).getAttributes());
This is a capability that needs to be provided by your framework. It means that your project needs to run on Java 8.
It is configured in the framework property:
org.osgi.framework.system.capabilities=osgi.ee; osgi.ee="JavaSE"; version:List<Version>="1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8"
That said normally this is already configured when you for example start the felix distro.
This is a known felix bug which has been fixed in 2.0.4. From http://svn.apache.org/repos/asf/felix/releases/org.apache.felix.bundlerepository-2.0.10/doc/changelog.txt ,
Changes from 2.0.2 to 2.0.4
---------------------------
** Bug
* [FELIX-3097] - LocalRepository is not updated when bundles are
* [FELIX-4571] - NullPointerException when using Repository impl with Aries subsystem impl
* [FELIX-4616] - BundleRepository ResourceComparator violates comparison contract
* [FELIX-4640] - missing (&(osgi.ee=JavaSE)(version=1.8)) when embedding in org.apache.felix.framework
** Improvement
* [FELIX-4812] - BundleRepository can be quite CPU intensive when starting a lot of bundles

Getting a ClassNotFoundException when trying to configure a custom session manager in virgo tomcat

I am using the eclipse virgo server with embedded tomcat. I want to use a custom session manager which I have created and it is present in an osgi bundle. I have configured the osgi bundle as a fragment with the catalina bundle being the fragment host. Also in my context.xml I have configured the session manager by specifying the fully qualified class name.
The problem is that on startup I get a ClassNotFoundException for my session manager.
I have tried adding my jar to the lib folder and modifying the config.ini to make my jar load up on startup but that did not help
In this scenario what should I do to ensure that my class is found on startup.
You can use the Virgo Shell Commands as described in this blog to analyze class loading issues. You can lists all bundles that can load a class for example. Have a look at the Virgo FAQ How to add imports to 3rd party bundles if need be.
Enabling class loader debugging helped,
In configuration/config.ini add the following property
osgi.debug=configuration/equinox-debug.properties
In configuration/equinox-debug.properties add the following properties,
org.eclipse.osgi/debug=true
org.eclipse.osgi/debug/loader=true
Now when you restart the container it prints out the BundleClassLoader which is attempting to load your class. I wanted my bundle to a be added as a fragment to the bundle which was loading this class, so once I figured out which bundle was loading the class I simply used that as the fragment host.

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