How to include a 3rd party dependency in a node?

I know how to include a plug-in that appears in the Plug-Ins view. I can’t figure out how to add an arbitrary library so that it will be included in the node. It builds fine if the library is on the class path, but the runtime node fails, apparently because the library is not exported.

Tried Eclipse Help and Stack Overflow, no luck.

Hi @dandl
I’m guessing you put your library jars under a a specific folder of your project (e.g a “lib” folder).

Two silly questions: is this folder added to the binary build, and are the jar file paths listed in Bundle-ClassPath of MANIFEST.MF file?

Yes, they’re in “Referenced Libraries”. Not my choice of name, it seems to be something Eclipse creates by default.

Sorry to show my ignorance, but the term ‘binary build’ doesn’t mean a lot to me. They’re on the classpath in the project file under “Java Build Path”. Otherwise they would trigger Eclipse errors.

DItto re ‘bundles’. Whatever a bundle is, setting its classpath looked like a good idea but I couldn’t find any reference for the syntax and nothing I tried has worked. Where do I put the files and how do I write a reference to them?

It seems there is no Eclipse Help on this, it only refers to OSGi via a broken link. If that’s what I have to set I can experiment some more, but a bit of advice would certainly help.

[build.properties is equally a mystery, in case that’s part of the answer.]

Hi @dandl,
KNIME AP is an Eclipse RCP application and uses the same plugin mechanism. Therefore, you can find many solutions to the problems you are facing if you search for solutions related to eclipse plugin development.
For example the solution to your current problem is described here:

best,
Gabriel

3 Likes

Hi @dandl
as @gab1one mentioned , a node in Knime is an Eclipse RCP plugin, so some documentation can be get from Plug-in Manifest Editor of latest eclipse official documentation.

Basically, to add one or more library jars to your node, you can follow these steps (similar to those described in the link @gab1one gave in his post) :

  1. In your Eclipse project, create a lib folder (or another name of your preference)
  2. Import your library jar files under this lib folder by using Import>File System or by dragging them into the folder
  3. Open the manifest editor by double-clicking the plugin.xml file
  4. Go to Runtime tab and in Classpath section make sure the plugin jar of your node is in the list.
  5. In Classpath section, press Add and include the jar files of step 2 (note: with this action the editor adds for you the jar paths in Bundle-ClassPath of MANIFEST.MF file).
  6. Go to Build tab and in Binary Build section, make sure the lib folder is checked (the editor adds for you the bin folder to the list in bin.includes of build.properties file).

HTH
Fabrizio

2 Likes

Thank you (both). I hadn’t found those answers on SO.

So I went through each of them, and yes, I can follow all the steps and they all seem to behave as they should, but at the end, no change. The error is exactly the same:

ERROR RaExtension 0:17 Configure failed (NoClassDefFoundError): org/apache/commons/jexl3/JexlContext

I know that jexl3 has a dependency on apache-commons-logging, but I’ve included that. It all works in a standalone test program. The problem is unique to the plugin build, somehow related to exporting the JAR and then finding it when needed. The error is only triggered when the class is instantiated.

Is there any way to debug this? Find out what is actually being exported into the plugin, what and where the components are, maybe debug the class loader?

You could try asking OSGI what it thinks is wrong via diag and examine the headers via headers. I don’t know how you’re deploying your plugins to test, but what is starting up KAP, have it start up the console as well and then telnet into it.

Some of this was discussed here.

1 Like

Thanks all. I finally figured it out, and I think it’s worth documenting.

There were enough clues here to find the OSGi console, run some commands and figure out that all the bundle stuff is working just fine. The problem was the class loader.

I had assumed the binaries would be exported somewhere as JARs and something went missing. Wrong. The binaries stay right where they are in the dev workspace, as raw classes. There is no actual built plugin, doesn’t exist, no JAR. The class loader simply works through the list in Bundle-ClassPath as set by the runtime tab of the plugin.xml, using the dev workspace as the root path. All I had to do was write class paths that are relative to the dev workspace and magic happens! Like this:

lib/commons-logging-1.2/commons-logging-1.2.jar

Maybe I should have tried that earlier, it really was not what I expected, but works just fine, for now. It may be quite different in a deployed plug-in, but that’s for another day.

1 Like

Glad you’ve resolved your issues. Though I’m not sure why you had it,

The way I add a lib (same as others have commented above):

  1. Create a libs folder in the project
  2. In the MANIFEST.MF / plugin.xml go to ‘Runtime’
  3. On the right hand side under Classpath click add then select the lib which should give you this relative style linking anyway:

    image

These libs should load unless there are other issues and be added into your build automatically. I’m not sure what is happening for you when you say " The binaries stay right where they are in the dev workspace, as raw classes".

If you need them to be available to other plugins you will need to export the packages on the Runtime tab also. Though be careful not to export things from common libraries - which you should be using an OSGi bundle for to avoid potential conflict.

Project can be found here:

Cheers

Sam

3 Likes

There is obviously a problem in communicating (both ways). What do you mean by “add the lib”, “the libs should load” and “added into the build” mean? What actually happens, and if it doesn’t, where do I look to fix it? Thank you for your pictures, but it’s actually the words I’m having trouble with.

I’ve used Eclipse/Java a lot for Android dev, never plugins. I read words like “load” and “build” to mean that all the files constituting my plug-in would be copied from the dev environment into some special place, packaged up in some special way (a “bundle”), and read into the runtime environment by some special plug-in loader. None of that happens. I was mistaken.They don’t go anywhere.

What actually happens is that a thing called “Equinox launcher” runs, and finds all the nodes. If you pick one it accesses all the files (raw class files and lib JARs) by reaching into the dev environment. The class loader ignores the normal class path and instead uses the bundle headers directly to find stuff (and it tries about 6 different ways). That kind of makes sense for debugging, but it really wasn’t what I expected. It obviously can’t work that way for a deployed binary.

For now, it’s all working just fine. When we get to deployment, I think the fun starts again.

Mmm my Eclipse RCP / OSGi knowledge is based on problem solving but to try clear up some confusion I may have caused I’ll try explain what I meant. It’s been so long since I had to use the OSGi console to debug a plugin failing to load I can’t really provide any advice there.

add a lib

Including a built jar file (which constitutes a non OSGi dependency) to a plugin so the code can be called from within the plugin.

“the libs should load”

When debugging / running the application from eclipse. If the libs (jars) have been added in the steps discussed there shouldn’t have been an issue unless there are dependencies missing. When you OSGi bundle loads the classes should be available.

“added into the build”

The OSGi bundle / plugin needs to be built to run. What’s including is controlled by the build config / build path. You need to libs to be in this build config to be available when you debug and when you get to building a deployable jar.


The common cause for me getting a NoClassDefFoundError is that I’ve not added the dependencies of the jars I’ve added into the lib folder.

3 Likes

I don’t want to labour the point, but all I was really trying to do was point out that when people come from different backgrounds and use the same words with different nuances of meanings it can be difficult to communicate, both ways.

I still have problems with the build.properties file, which I don’t understand at all. Stuff appears and disappears for reasons I don’t get, and there are quite a few warnings I don’t understand. But we’re making progress.

When you build a plugin, you generate a directory of files or jar (a bundle) which includes the class files of your plugin, together with any library (jar or class files) it may need.
In addition, your plugin may require some other plugin or packages: these are the plugin dependencies, which are not part of your bundle, but are required for it to work. You declare them under the Dependencies section of Manifest editor. The actual plugin/packages will be provided by the target eclipse platform, where the plugin will be installed (in our case the KNIME AP).
For example, a Knime node plugin will require org.knime.base, org.knime.core plugins and so on.

The META-INF/MANIFEST.MF, build,properties, plugin.xml, are the files needed to configure an eclipse plugin. You can create/edit them manually or use the Manifest editor instead, which automatically updates them for you.

I woud say that Eclipse development learning curve is bit steep at the beginning (at least it was for me), but with the patience to read its documentation, you’ll start to get acquainted of its terms and infrastructure.
There are a lot of things I don’t know about Eclipse and what I know is just the minimum required to write knime nodes (eclipse plugins) and deploy them. When I happen to need a new aspect of the platform I’m not aware of, then I go back to documentation.

To start from terminology, I would suggest reading the plugin concepts, or better the entire Concepts section

Regarding the build.properties file, you can read the Feature and Plug-in Build Configuration Properties section.

Fabrizio

4 Likes

What I was trying to point out is that (at least in debug) there is no JAR containing the classes of my plugin. The classes are compiled into the bin directory, and the plugin loads them directly from there. I spent time looking for that JAR, which just isn’t there. But it’s not an important issue.

Thanks for the pointers. The first is to “Feature builds with p2”. I don’t know whether I’m using p2 or features, but I don’t think so. The concepts section is useful, but I can’t find anything about the syntax or semantics of build.properties. It’s editable, but that’s risky if I don’t know what I’m doing. If there is such a thing it would be very useful.

I’m sorry, but I pasted the wrong link URLs. These are correct ones:

You can also navigate in the help contents bookmarks to search for additional information.

Is it correct that classes are compiled into a bin directory, but these are just there to allow your plugin to work in your development environment.

In order to release your plugin in production environment, that is in a KNIME AP, in addition to the build step (i.e. the generation of compiled classes in bin directory), you need the deployment step.

You have two options for deployment.
In the simplest one you export your build into a JAR file: look at the Overview tab of Manifest editor, under Exporting secition, option 4 Export Wizard. Step by step instructions are available here or here .

The second option is the preferred one, but it is a little bit complex; it allows you to generate a specific update site for your plugin. For information, please read this documentation.

HTH
Fabrizio

1 Like

Thanks. I’ve read all the concepts stuff, which is helpful but still leaves some questions about exactly which parts are relevant to Knime. The section on build.properties is very useful.

I’m way off deployment, so my problems were purely in the dev environment. So the runtime page has a list of JAR files on the classpath, but none of those are actually created in the dev build. Instead, the class loader deconstructs the JAR path into a folder path and loads the CLASS files directly. Easy when you know what’s going on, pretty tough when you don’t.

[Right now my dev environment is broken and I can’t fix it, so not a lot is happening. See separate post.]

Just a quick update: the JAR export worked fine. I have a set of Relational Algebra nodes executing ‘in the wild’, on the production release AP.

Now working on cleaning up, samples and README for a first alpha release on GitHub. I’ll do that as a JAR dropin, and get back to the update site method later.

Thanks for the help.