OSGI framework hangs when loading native library - java

Situation: Open source OSGI framework SMILA (http://www.eclipse.org/smila/) started as Windows Service with the aid of Apache commons-daemon (http://commons.apache.org/daemon/). Trying to load a DLL via System.loadLibrary() from OSGI bundle while Manifest.mf includes Bundle-NativeCode: path/to/dll.
Environment: Windows Server 2003, Java 1.6
Error: During the invocation of System.loadLibrary() the complete Java process hangs. When the service is stopped System.loadLibrary() finish and code execution goes on until the OSGI framework shut down.
The error doesn’t occur on Windows Server 2008 or if the OSGI framework isn’t started as service.
The DLL itself is stripped down to no functionality for testing. All imports are static and the only depended library is kernel32.ddl.
Could anyone imagine why this is happening and how to fix it?
Manifest containing DLL:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: NTFS Utils Acl Win32 Library
Bundle-SymbolicName: com.eccenca.utils.ntfs.acl.win32
Bundle-Version: 2.2.0
Bundle-Vendor: brox IT-Solutions GmbH
Fragment-Host: com.eccenca.utils.ntfs
Eclipse-PlatformFilter: (& (osgi.os=win32) (osgi.arch=x86))
Bundle-NativeCode: ntfsacl/Release/NtfsAcl.dll
Bundle-RequiredExecutionEnvironment: JavaSE-1.6+
Manifest containing code:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: NTFS Utils Acl
Bundle-SymbolicName: com.eccenca.utils.ntfs
Bundle-Version: 2.2.0
Bundle-Vendor: brox IT-Solutions GmbH
Export-Package: com.eccenca.processing.acl,
com.eccenca.utils.ntfs
Import-Package: org.apache.commons.io;version="1.4.0",
org.apache.commons.lang,
org.apache.commons.logging;version="1.1.1",
org.eclipse.smila.blackboard;version="0.8.0",
org.eclipse.smila.datamodel,
org.eclipse.smila.processing;version="0.8.0",
org.eclipse.smila.processing.pipelets;version="0.8.0",
org.eclipse.smila.utils.config;version="0.8.0",
org.eclipse.smila.utils.service;version="0.8.0",
org.osgi.framework;version="1.4.0"
SMILA-Pipelets: com.eccenca.processing.acl.AccessListConverterPipelet
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Code snipped with System.loadLibrary() invocation:
public class ACLList {
private static final org.apache.commons.logging.Log LOG =
org.apache.commons.logging.LogFactory.getLog(ACLList.class);
static {
try {
LOG.debug("Start loading library");
System.loadLibrary("NtfsAcl");
if (LOG.isInfoEnabled()) {
LOG.info("NTFS ACL library was succesfully loaded");
}
} catch (Throwable e) {
LOG.error(e);
}
}
private ACLList() {
}
public static native ArrayList<ACLEntry> getAccessFor(String path,
String serverName) throws IOException;
}

There are two possible issues with the situation you described; I don't know exactly how Equinox handles native code, so I'll just present them to you both.
Bundle-NativeCode requires at least one parameter
You use a Bundle-NativeCode header that just defines a library, and it seems you use Eclipse-PlatformFilter to specify what that library is intended for. Section 3.10 of the spec shows that you need at least one parameter for the library to be selected.
You can change your Bundle-NativeCode header to read
Bundle-NativeCode: ntfsacl/Release/NtfsAcl.dll;osname=win32
and your bundle will be able to find the right library.
Load only from your own bundle
Judging from your code, it could be possible that you define the library in one bundle, and try to load it in another; that doesn't work, a bundle can only load a library that it contains itself.

Related

Registering services inside OSGi extension bundles

I'm playing with OSGi framework extension bundles in order to fully understand them.
After looking at the OSGi R6 specification (3.15 and 4.2.4.1) I've sucessfully invoked the "start" method of the ExtensionBundleActivator. Now I'm trying to register a service inside such activator. However, when I trying to consume such service, the reference annotation fails to connect the service.
Here's my code ('ve changed the name of the bundle, but it shouldn't matter):
public class ExtensionBundleActivator implements BundleActivator {
#Override
public void start(BundleContext context) throws Exception {
System.out.println("start extension bundle activator!");
context.registerService(
BundleExample.class.getName(),
new BundleExampleImpl(),
new Hashtable<>(new HashMap<>()));
}
#Override
public void stop(BundleContext context) throws Exception {
//service automatically unregistered
}
}
And here's the manifest of such extension bundle:
Manifest-Version: 1.0
Bnd-LastModified: 1476436248622
Build-Jdk: 1.8.0_91
Built-By: massi
Bundle-ClassPath: .
Bundle-ManifestVersion: 2
Bundle-Name: extensionbundleexample
Bundle-SymbolicName: com.massimobono.microsi.extensionbundleexample
Bundle-Version: 0.0.1.SNAPSHOT
Conditional-Package: com.massimobono.microsi.common.*;
Created-By: Apache Maven Bundle Plugin
ExtensionBundle-Activator: com.massimobono.microsi.bundleexample.imp
l.ExtensionBundleActivator
Fragment-Host: system.bundle; extension:=framework
Provide-Capability: osgi.service;objectClass:List<String>="com.massimobo
no.microsi.bundleexample.BundleExample"
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Service-Component: OSGI-INF/com.massimobono.microsi.bundleexample.im
pl.ExtensionBundleExample.xml
Tool: Bnd-3.0.0.201509101326
The consuming bundle (part of the bundle):
#Reference(cardinality=ReferenceCardinality.OPTIONAL)
public BundleExample actualBundleExample;
#Activate
public void activate() {
System.out.println("activating " + this.getClass().getSimpleName() + "with actual bundle set to "+ this.actualBundleExample);
}
My question is: What am I doing wrong? Why the consumer can't detect the registered service of the extension bundle? Or maybe I'm just doing something the framework forbids... in this case is it impossible to provide a service from an extension bundle? How can I interact with the code within the extension bundle (aka accessing something inside the extension bundle itself)?
Here some notes:
I'm using felix as OSGi implementation;
Both "ExtensionBundleExample" and "BundleExample" are loaded inside the auto-process folder of felix (the default one is "bundle" but I tweaked the config.properties to use "corebundles" folder;
The output corretly show "start extension bundle activator!" but when it's time to display the reference of actualBundleExample, the output shows "null";
the optional cardinality of BundleExample is used for testing purposing: I just wanted to invoke the "acivator" method the consumer component has (in order to see the System.out.println console;
from my previous question I understand extension bundles are a niche inside the OSGi framework, but I want to understand them nonetheless: I find the lack of examples on the internet regarding this topic quite annoying;
Thanks for any reply!
The primary purpose of extension bundles is for framework extensions, absolutely not for regular usage. I.e. extension bundles are often tightly coupled to a framework. The reason is that many rules do not count for extension bundles because they are on the "wrong" side of the fence. There are few examples for very good reasons. You should not use them unless you really know what you're doing because most of the OSGi rules do not apply.
That said. My expectation is that the package you use for the BundleExample differs between the extension bundle (comes from the class path) and the DS example exported by some bundle. Since they come from different class loaders OSGi considers them different services because you would get a class loader exception when you tried to use it.
You can solve this by letting the framework export this package.
Just a guess.

OSGI bundle is unable to start

I have an OSGI bundle which gets to the RESOLVED state, but never reaches the ACTIVE state. When I run my application, this is the stacktrace I am obtaining: http://tny.cz/fa949f16
Afterwards, when I try to start the bundle explicitly through the OSGI console, I get this error:
start 53
gogo: BundleException: The activator rsy.home.mac.sm.schedule.service.win.WinServiceActivator for bundle rsy.home.mac.sm.schedule.service.win is invalid
Notice that in the end of the stacktrace ouput, there's the following message:
!ENTRY org.eclipse.osgi 4 0 2014-03-14 10:52:50.984 !MESSAGE Bundle
rsy.home.mac.sm.schedule.service.win_1.0.0 [53] is not active.
Here's the code from WinServiceActivator:
package rsy.home.mac.sm.schedule.service.win;
import java.util.HashMap;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
public class WinServiceActivator implements BundleActivator {
private static BundleContext context;
#Override
public void start(BundleContext context) throws Exception {
ServiceActivator.context = context;
ScheduleService schedServ = new ScheduleService();
schedServ.setTdMapping(new HashMap<String, String>());
schedServ.setHtMapping(new HashMap<String, String>());
schedServ.setDoMapping(new HashMap<String, String>());
context.registerService(ScheduleService.class.getName(),
schedServ, null);
}
#Override
public void stop(BundleContext context) throws Exception {
context.ungetService(context.getServiceReference(ScheduleService.class.getName()));
ServiceActivator.context = null;
}
}
And this is my MANIFEST file:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: SM Schedule Query Service
Bundle-SymbolicName: rsy.home.mac.sm.schedule.service.sm;singleton:=true
Bundle-Version: 1.0.0
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Service-Component: OSGI-INF/sm_schedule_service.xml
Require-Bundle: rsy.home.mac.sm.jaxrs.lib;bundle-version="1.0.0",
rsy.home.mac.sm.config;bundle-version="0.1.0",
rsy.home.mac.log,
rsy.home.mac.sm.model;bundle-version="1.0.0",
rsy.home.mac.sm.schedule.service;bundle-version="1.0.0",
rsy.home.mac.sm.sm.scheduletable;bundle-version="1.0.0",
resources;bundle-version="1.0.0",
rsy.home.mac.portal.utilities,
rsy.home.mac.portal.logging;bundle-version="1.0.0",
org.eclipse.xsd;bundle-version="2.7.0",
org.eclipse.osgi
Import-Package: org.osgi.service.http;version="1.2.1"
Bundle-ActivationPolicy: lazy
Bundle-Activator: rsy.home.mac.sm.schedule.service.sm.SmServiceActivator
Export-Package: rsy.home.mac.sm.schedule.service.sm
While googling the error "Activator start error, ClassCastException: xxxx cannot be cast to org.osgi.framework.BundleActivator", I found this:
That error is telling you that you have two copies of the BundleActivator class loaded into your VM somehow. The framework is using one and your bundle is using another.
Do you have any other bundles exporting org.osgi.framework? Where is your bundle getting this package from? If you issue the following command in the Felix shell you can see the wiring:
inspect package requirement <bundle-id>
or shortened to:
inspect p r <bundle-id>
Where <bundle-id> is the ID of your bundle, then you should see from where it is getting org.osgi.framework. If it is not the system bundle (org.apache.felix.framework), then you have an issue.
When I executed the given command, I obtained this output:
org.osgi.framework; version="1.7.0" -> org.eclipse.osgi_3.9.0.v20130410-1557 [0]
Do you think this is the reason why the bundle doesn't start? If so, how can I fix this? Following this comment I found on the internet and the comments and answers from people below, I tried to replace this line in the MANIFEST file:
Import-Package: org.osgi.service.http;version="1.2.1"
by this one:
Import-Package: org.osgi.framework
And I get a whole bunch of errors in the code, whose reason given by Eclipse is:
Multiple markers at this line
- Access restriction: The type BundleActivator is not accessible due to restriction on required library
rsy.home.mac.sm.jaxrs.lib/lib/org.osgi.core-4.2.0.jar
- Access restriction: The type BundleListener is not accessible due to restriction on required library
rsy.home.mac.sm.jaxrs.lib/lib/org.osgi.core-4.2.0.jar
I would really appreciate some help on this... Thanks!
I had a similar exception some time ago when I tried to get CXF working in an eclipse rcp application. The reason was that I did require bunddle on org.eclipse.osgi. You should avoid that.
Require bundle means that you import all packages of that bundle. The framework bundle (org.eclipse.osgi) exports the OSGi API. Probably another bundle listed in your require bundle list also exports the BundleActivator package. So you get the class from two sources and likely use a different one than the framework itself.
These problems are the reqson why you should avoid require bundle. Espcially try to avoid doing require bundle on org.eclipse.osgi. THis bundle also exports all packages defined in the system exports. So it exports lots of packages and chances are high you run into problems. In my case with cxf I had a similar problem with the jaxb api that is exported by org.eclipse.osgi and also by one of the bundles cxf brings with it.
This article may give you some more details as the problem you observe often surfaces as a uses constraint violation. http://njbartlett.name/2011/02/09/uses-constraints.html
In general if you have the chance use the maven bundle plugin or bndtools to generate the Manifest. Both have good defaults that avoid most of these problems.

Osgi java.lang.NoClassDefFoundError when trying to retrieve a service from another bundle

So, let's see, I have three bundles: Provider interface, Provider implementation and Client.
Everything is running smoothly on Eclipse, but when I export the bundles and run em, the following error appears when I try to retrieve the Provider Service:
java.lang.NoClassDefFoundError: provider/providerinterface/ProviderService
The interface is exporting his package, so there should be no errors with that. Alongside, Client is also importing the providerInterface package in its manifest.
The .jar of the Provider interface bundle does have the ProviderService class inside, so there are no error exporting either.
Provider Interface's manifest:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: IMA_Provider
Bundle-SymbolicName: IMA_Provider
Bundle-Version: 1.0.0
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Export-Package: provider.providerinterface
Client's manifest:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: MAClient
Bundle-SymbolicName: MA_Client
Bundle-Version: 1.0.0
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: provider.providerinterface,
org.osgi.framework;version="1.3.0",
org.osgi.util.tracker;version="1.4.2"
Provider and Client are just symbolic names, the "Client" bundle imports and uses a lot of other classes from many other bundles with no errors whatsoever. Anyway, I'm getting stuck with this one, and I can't find any reason.
Any help?
Usually there is something wrong with the build.properties file, causing the bundles to miss the actual class files. This does not matter when running directly from Eclipse, but it does matter when you export the bundles using PDE.
Things to check:
Are the classfiles really in the bundles? When checking the bundle, you should have at least at toplevel a provider/ folder and a META-INF/ folder
the build.properties file should look something like:
output.. = bin/
source.. = src/
bin.includes = META-INF/,.
Good luck, Frank
I was finally able to solve this.
There were no issues with the Manifest files or the build.properties, this was a constructor problem.
The MA_Provider implementation was lacking a void constructor; Once I added this
public ProviderImpl(){}
on the implementation class of the ProviderInterface, the OSGi bundles were able to retrieve the service.

Class Not Found Exception after using IWorkspaceRunnable

I get the Class Not Found Exception after Exporting the plugin I'm developing as a Deployable Feature.
Normally I place the generated Jar in the dropins folder and I can use it. But after adding what seemed the proper way of saving changes to a resource using IWorkspaceRunnable I started getting the not Class Def Exception when I try to run the deployed plugin. (Note the plugin runs fine when testing it without deploying, aka Run as Eclipse Application)
IWorkspaceRunnable saveTask = new IWorkspaceRunnable() {
#Override
public void run(IProgressMonitor monitor) throws CoreException {
if (fileName != null) try {
myEditor.save(new File(fileName));
firePropertyChange(PROP_DIRTY);
ResourcesPlugin.getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, null);
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Error while saving: \n"+e.toString());
}
}
};
try {
ResourcesPlugin.getWorkspace().run(saveTask, null);
} catch (CoreException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Error while saving: \n"+e.toString());
}
Any idea how to get this working?
org.eclipse.core.resources, which holds IWorkspaceRunnable, is already present in my "Plug-in dependencies" folder. I think it got there automatically at some point. Is there somewhere else I should put/reference that particular jar? I haven't done anything else for the other classes I'm using from org.eclipse.*.
EDIT: Here is the MANIFEST.MF
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: MyPlugin
Bundle-SymbolicName: MyPlugin;singleton:=true
Bundle-Version: 1.0.0.1
Require-Bundle: org.eclipse.ui,org.eclipse.core.runtime,org.eclipse.ui
,org.eclipse.core.runtime,org.eclipse.jface.text,org.eclipse.ui.edito
rs,org.eclipse.ui.ide,org.eclipse.core.resources;visibility:=reexport
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Vendor: myVendor
Bundle-ClassPath: /usr/share/eclipse/plugins/,.
How I'm deploying the plugin:
I'm placing the .jar in /home//.eclipse/org.eclipse.platform_/dropins/, with version being 4.2.0_1543616141. This may not be the proper way to deploy it, but it worked before adding references to org.eclipse.core.resources.
I'm interested in creating a standalone-ish plugin that can be dropped in the dropins folder and just run.
ClassNotFoundException indicates that something is missing on the classpath. Maybe you are missing a library in the classpath.
As the name suggests classNotFoundException in Java is a subclass of java.lang.Exception and Comes when Java Virtual Machine tries to load a particular class and doesn't found the requested class in classpath.

Eclipse Plugin Fragment

Does anyone have a "hello world" sample or tutorial for creating an Eclipse plugin fragment?
I have a working host plugin that, for the sake of simplicity, is just this...
public void start(BundleContext context) throws Exception {
System.out.println("Hello....");
super.start(context);
plugin = this;
}
public void stop(BundleContext context) throws Exception {
System.out.println("Goodbye...");
plugin = null;
super.stop(context);
}
Simple enough and works. Now I want to add a fragment to that host, which seems not as simple as creating a plugin host. I just don't see how to create a fragment project and add logic to it. Let's say I just want to do something simple and have the fragment to print a "Hello2" at start() and "Goodbye2" at stop(). Can someone give me a working example?
Eclipse -> File -> New... -> Fragment project -> set the host plugin (which is either in your workspace or in plugins in target platform).
Open Plugin manifest editor (you can do it by clicking on build.properties, manifest.mf or fragment.xml - if there is no such a file, create it by hand)
In tab Extentions click Add.. and add org.eclipse.ui.startup and browse class which implements org.eclipse.ui.IStartup class.
Create this class and implement it. You need to implement method earlyStartup() which is entry point to the fragment.
Note: The lines below are just example. I didn't test it so there might be errors...
All you need is this (this is project structure / directory structure):
Fragment-Project - root dir
/META-INF
MANIFEST.MF
/src (which is source directory)
FragmentStartClass.java (which implement org.eclipse.ui.IStartup interface and earlyStartup method)
build.properties
fragment.xml
META-INF/MANIFEST.MF content:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: FragmentProject
Bundle-SymbolicName: FragmentProject;singleton:=true
Bundle-Version: 1.0.0
Bundle-ClassPath: src/,.
Fragment-Host: *HostPluginProjectSymbolicName*;bundle-version="1.0.0"
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Require-Bundle:
build.properties content:
source.. = src,\
output.. = bin/
bin.includes = META-INF/,
.,
fragment.xml
fragment.xml content:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<fragment>
<extension
point="org.eclipse.ui.startup">
<startup
class="FragmentStartClass">
</startup>
</extension>
</fragment>
FragmentStartClass.java content:
import org.eclipse.ui.IStartup;
public class FragmentStartClass implements IStartup {
public void earlyStartup() {
System.out.println("Hello World From Fragment!");
}
}
Well, first off what are you trying to accomplish? Are you sure fragments are the solution?
Fragments are simply additions to an existing plugin. There is no Bundle-Activator to "startup" the fragment. You just gain the additional resources in the fragment. You could use an extension point to inform the host that some particular functionality was extended by a present fragment. Think of it as merging the two at runtime.
See this note from the Eclipse Wiki.
I'm not sure if you can do this without the host plugin knowing something about loading the fragment's extra implementation code.
For example:
MyInterface o = null;
try {
Class<?> c = getClass().getClassLoader().loadClass("my.fragment.Activator");
o = (MyInterface) c.newInstance();
} catch (ClassNotFoundException e) {
}
if (o != null) {
o.start();
}
where MyInterface is an interface defined in the host plugin, and implemented by your fragment.
Another way might be to have the fragment provide an extension point identifying the extended class, but that is probably more than is needed.
I think what you are trying to do is better served by using extension points and separate plugins, as you want to add functionality to the base plugin.
Fragments are only used to add resources or extra classes to the base plugin.
For the record, I just created an Eclipse Fragment that contains some PMD Java Rule classes.
Next to the class files, there is only one file required in that Jar: META-INF/MANIFEST.MF:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: com.acme.tools.pmd
Bundle-SymbolicName: com.acme.tools.pmd;singleton:=true
Bundle-Version: 1.0.0
Fragment-Host: net.sourceforge.pmd.eclipse.plugin;bundle-version="3.2.6"
Bundle-RequiredExecutionEnvironment: J2SE-1.5
I tried this with current Eclipse 3.7. Deployment is by placing the Jar file into <eclipse root>/dropins/plugins (create that folder if it's not yet there).

Categories