0

I am trying to import OWL-Api into a jar-packaged project. This library has many dependencies, which it provides in one OSGi bundle.

As I do not wish to maintain a list of dependencies of dependencies manually, I would like to use that bundle; as each dependency is packed as a jar inside the jar, just specifying it in the manifest does not work.

According to the OWL-Api mailing list, the easiest way is therefore to use this jar as an OSGi bundle and to turn the project into one as well.

Sadly, the latter is not an option. The existence of an independent OSGi loader may not be assumed as a requirement.

I have therefore (successfully?) attempted to embed the Equinox loader into my program and install the bundle on runtime. (Note: I picked Equinox at random. If another loader would be better suited for the task, say the word.)

... And now I have no idea how to proceed. The dependencies are not automatically loaded. How would I load them in a way that needs not listing them one by one?

To elaborate: If at any time in the future, the dependencies of OWL-Api change, be it through addition or removal, this shall not result in a need to adjust the code of the project. Only changes to the direct, first generation dependency on OWL-Api itself may.

Furthermore, if a different technique would be easier to attain the same goal (still using the provided bundle), I am interested to read of it.

Error message (same as without Equinox):

Exception in thread "main" java.lang.NoClassDefFoundError: com/google/inject/Provider
  [...]
Caused by: java.lang.ClassNotFoundException: com.google.inject.Provider
  [...]

The corresponding class file is present at lib/owlapi-osgidistribution-4.1.0.jar/lib/guice-4.0.jar/com/google/inject/Provider.class .

Test project file:

import org.eclipse.core.runtime.adaptor.EclipseStarter;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.OWLOntologyManager;

class Main
{
  public static void printThrowable(Throwable e)
  {
    do
    {
      System.err.println("Equinox initialisation failed:");
      System.err.println(e.getMessage());
      System.err.println("");
      e = e.getCause();
    }
    while(e != null);
  }

  public static void main(String[] args)
  {
    String[] equinoxArgs = { "-configuration ./config.ini" };
    try{ EclipseStarter.startup(equinoxArgs, null); }
    catch(Throwable e)
    {
      printThrowable(e);
      System.exit(1);
    }

    OWLOntologyManager m = OWLManager.createOWLOntologyManager();

    try{ EclipseStarter.shutdown(); }
    catch(Throwable e){ printThrowable(e); }

    System.out.println("Hallo Welt.");
  }
}

The output is displayed when the call to OWLManager is commented out, so Equinox seems to start up and shut down just fine.

Folder structure:

./
  lib/
    org.eclipse.osgi_3.10.2.v20150203-1939.jar
    owlapi-distribution-4.1.0.jar
    owlapi-osgidistribution-4.1.0.jar <- OSGi bundle
      lib/
        <...>.jar <- OWL-Api dependencies
  config.ini <- Equinox configuration file
  Main.jar <- project executable

Manifest:

Class-Path: ./lib/owlapi-distribution-4.1.0.jar ./lib/org.eclipse.osgi_3.10.2.v20150203-1939.jar
Main-Class: Main

Configuration file:

eclipse.ignoreApp=true
osgi.bundles=owlapi-osgidistribution-4.1.0.jar@start
osgi.noShutdown=true
Zsar
  • 443
  • 3
  • 14
  • Your application seems to be non OSGi. So why don´t you just use the non OSGi Owl jar? – Christian Schneider Nov 05 '15 at 19:53
  • I agree. If you don't want to use OSGi, then don't. Just expand the JARs inside this Owl JAR thingy and put them on your classpath. – Neil Bartlett Nov 05 '15 at 22:57
  • @Neil-Bartlett : Classpath parameter is ignored when loading a jar. Classpath inside the jar's manifest does not support wildcards according to the documentation (Though I have not tried just doing it... mayhap I should?). Jars inside jars are not supported by Classpath anywhere. - I would not mind at all a non-OSGi solution, but I am not aware of an elegant one. Links/suggestions/anything? – Zsar Nov 06 '15 at 13:49
  • The owlapi-distribution artifact has a pom, so adding the dependency to your project - if you build with maven - would not require you to manage the dependencies manually. But I might make assumptions here: is maven an option? – Ignazio Nov 06 '15 at 16:54
  • I'm aware that JARs inside JARs are not supported by the standard Java classpath. That's why I suggested expanding the JAR. You know... try some initiative? The page you linked to clearly states that there is a "regular" (non-OSGi") distribution with Maven dependency management. – Neil Bartlett Nov 06 '15 at 19:05
  • @Ignazio : As the final project is not supposed to depend on Maven (unless I would ship it _as part_ of the project, as tried with the OSGi loader in the OP), this looks possible but I wonder whether it is a smart idea. Cursory examination of the matter yields various kinds of complications: http://stackoverflow.com/a/32316071/3434465 http://stackoverflow.com/a/31845838/3434465 http://stackoverflow.com/a/1729202/3434465 As apparently no one is interested or knowledgeable in using the OSGi API, I guess it's still my best bet. – Zsar Nov 11 '15 at 12:29
  • The question you linked is referring to a function available through the shade plugin for maven. Main complication is that dependencies cannot easily be updated after the build. If you do not need to support that in your final project, then the shade plugin might help you. A similar result is available with the OSGi plugin for maven - with all dependencies set to be inlined. You don't need maven to run the resulting jar, only to build it. – Ignazio Nov 11 '15 at 12:36
  • @Ignazio : Actually, it does seem that I need to run the program via mvn exec:java _or_ use the 1. (unshaded) or 2. (shaded) method mentioned in the first link, both of which apparently are inherently unsafe to use. ... Examining the created jar shows that there is no mention of any dependencies, except in the included pom.xml - which of course needs Maven to be interpreted. Strange enough, that the "Maven in five minutes" tutorial claims that the jar can be run via `java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App` - this _does not_ seem to work once dependencies are needed. – Zsar Nov 11 '15 at 14:17
  • @Ignazio : More specifically, I refer to this paragraph, listed for both methods: `Files present in multiple JAR files with the same path (e.g., META-INF/services/javax.script.ScriptEngineFactory) will overwrite one another, resulting in faulty behavior.` This sure looks like a serious flaw. – Zsar Nov 11 '15 at 14:22
  • That particular issue is solved with a config option. Check out the pom for owlapi-distribution from github, it does exactly that for service list files. – Ignazio Nov 11 '15 at 16:02
  • @Ignazio : So, just adding `` to the shade plugin somehow prevents this issue? ... I am doubtful. The resulting jar does not seem to include anything from the sources. Will later test whether it really works on a different computer, where they are not present for sure... would be pretty sorcerous (sorceral?), I think. – Zsar Nov 12 '15 at 12:51
  • I was referring to overwriting files with the same names. For the rest of the merging, you need more configuration. – Ignazio Nov 12 '15 at 21:09
  • Well, it does seem to work. Shame about how much time I had to invest into just setting this up, but at least it's done. ... Cannot even update anything without editing the "pom.xml"-file, comfortable is definitely different; I so hope it will not cause issues further down the line. In any case, thank you, @Ignazio for that solution. Even if it is not an answer to the question at hand, it solved the problem motivating the question in the first place. – Zsar Nov 26 '15 at 13:42

0 Answers0