David M. Karr
David M. Karr

Reputation: 15245

Maven Tycho can't find the bundle I created with maven-bundle-plugin

I inherited a largish Eclipse plugin codebase being built with Maven Tycho. It has several plugin modules, two features, a target platform, and an update site. I've been working with Java for many years, but I'm very new to Eclipse plugin development and OSGi.

I discovered that one of the plugin modules (we'll call it "core") had a "lib" folder with a handful of third-party jars. I initially assumed that the original authors were just lazy, as I would have expected to see those specified with Maven dependencies. I later discovered that getting Maven dependencies into an Eclipse plugin is very non-trivial, and I'm still unable to get it working, after more than two weeks of struggling with the problem and posting questions on various forums. I realized today I hadn't tried a SO posting, so here we go.

After reading more about the problem, I concluded that I needed to define a new module, which we'll call "maventhirdparty", which declares those third-party dependencies in the pom, and then uses the "maven-bundle-plugin" to produce a valid OSGi bundle, and then I'll need to declare the new bundle as a dependency from the original "core" bundle.

I've done all this. Unfortunately, although the produced bundle and manifest looks correct to me, when Tycho attempts to resolve dependencies for the "core" module, it simply says that it can't find the new bundle that I've declared. I can't figure out how to generate any additional diagnostics, it just says it can't find it.

So, here's some output and file excerpts.

This is from the build:

[INFO] Resolving dependencies of MavenProject: com.cisco.yangide:com.cisco.yangide.core:1.1.1-SNAPSHOT @ /home/opnfv/git/yangide/plugins/com.cisco.yangide.core/pom.xml
[INFO] {osgi.os=linux, osgi.ws=gtk, org.eclipse.update.install.features=true, osgi.arch=x86}
[ERROR] Cannot resolve project dependencies:
[ERROR]   Software being installed: com.cisco.yangide.core 1.1.1.qualifier
[ERROR]   Missing requirement: com.cisco.yangide.core 1.1.1.qualifier requires 'bundle com.cisco.yangide.maventhirdparty 1.1.1' but it could not be found
[ERROR] 
[ERROR] See http://wiki.eclipse.org/Tycho/Dependency_Resolution_Troubleshooting for help.
[ERROR] Cannot resolve dependencies of MavenProject: com.cisco.yangide:com.cisco.yangide.core:1.1.1-SNAPSHOT @ /home/opnfv/git/yangide/plugins/com.cisco.yangide.core/pom.xml: See log for details -> [Help 1]

Here's an excerpt of the POM for the new "maventhirdparty" module:

  <artifactId>com.cisco.yangide.maventhirdparty</artifactId>
  <packaging>bundle</packaging>
  <version>1.1.1-SNAPSHOT</version>

  <dependencies>
  <dependency>
    <groupId>org.antlr</groupId>
    <artifactId>antlr4-runtime</artifactId>
    <version>4.0</version>
  </dependency>
  <dependency>
    <groupId>org.mapdb</groupId>
    <artifactId>mapdb</artifactId>
    <version>1.0.4</version>
  </dependency>
  <dependency>
    <groupId>org.opendaylight.yangtools</groupId>
    <artifactId>yang-model-api</artifactId>
    <version>0.6.1</version>
  </dependency>
  <dependency>
    <groupId>org.opendaylight.yangtools</groupId>
    <artifactId>yang-parser-impl</artifactId>
    <version>0.6.1</version>
  </dependency>
  </dependencies>

  <build>
<plugins>
  <plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
    <configuration>
      <instructions>
    <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
    <Bundle-Version>1.1.1</Bundle-Version>
    <Embed-Dependency>
      antlr4-runtime, mapdb, yang-model-api, yang-parser-impl
    </Embed-Dependency>
    <Export-Package>org.opendaylight.yangtools.*, org.antlr.*, org.mapdb.*</Export-Package>
    <Embed-Transitive>true</Embed-Transitive>
    <Embed-Directory>jars</Embed-Directory>
    <_failok>true</_failok>
    <_nouses>true</_nouses>
      </instructions>
    </configuration>
  </plugin>
</plugins>

Here's an excerpt of the generated manifest in the resulting bundle:

Manifest-Version: 1.0
Bnd-LastModified: 1454085545792
Build-Jdk: 1.8.0_60
Built-By: opnfv
Bundle-ClassPath: .,jars/antlr4-runtime-4.0.jar,jars/mapdb-1.0.4.jar,jar
 s/yang-model-api-0.6.1.jar,jars/yang-parser-impl-0.6.1.jar
Bundle-DocURL: https://www.opendaylight.org
Bundle-License: https://www.eclipse.org/legal/epl-v10.html
Bundle-ManifestVersion: 2
Bundle-Name: com.cisco.yangide.maventhirdparty
Bundle-SymbolicName: com.cisco.yangide.maventhirdparty
Bundle-Vendor: OpenDaylight
Bundle-Version: 1.1.1
Created-By: Apache Maven Bundle Plugin
Embed-Dependency: antlr4-runtime, mapdb, yang-model-api, yang-parser-imp
 l
Embed-Directory: jars
Embed-Transitive: true
Embedded-Artifacts: ...
Export-Package: ...
Import-Package: ...
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.7))"
Tool: Bnd-3.0.0.201509101326

And here's the manifest from the "core" module:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: com.cisco.yangide.core
Bundle-SymbolicName: com.cisco.yangide.core;singleton:=true
Bundle-Version: 1.1.1.qualifier
Bundle-Activator: com.cisco.yangide.core.YangCorePlugin
Bundle-Vendor: Cisco Systems, Inc.
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.jdt.core;visibility:=reexport,
org.eclipse.text,
org.eclipse.core.resources,
org.eclipse.core.filesystem,
com.cisco.yangide.maventhirdparty;bundle-version="1.1.1"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy
Export-Package: com.cisco.yangide.core,
com.cisco.yangide.core.buffer,
com.cisco.yangide.core.dom,
com.cisco.yangide.core.indexing,
com.cisco.yangide.core.parser,
com.cisco.yangide.core.model,
org.antlr.v4.runtime

What can I do here?

Update:

Here is my current target platform definition:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?><target includeMode="feature" name="YANG IDE Target Platform" sequenceNumber="26">
<locations>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="com.google.guava" version="15.0.0.v201403281430"/>
<unit id="com.google.guava.source" version="15.0.0.v201403281430"/>
<repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20140525021250/repository/"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.rcp.sdk.id" version="4.5.1.M20150904-0015"/>
<unit id="org.eclipse.graphiti.feature.feature.group" version="0.12.1.v20150916-0905"/>
<unit id="org.sonatype.m2e.mavenarchiver.feature.feature.group" version="0.17.0.201502101659-signed-20150525172209"/>
<unit id="org.eclipse.emf.sdk.feature.group" version="2.11.1.v20150806-0404"/>
<unit id="org.eclipse.emf.compare.source.feature.group" version="3.1.1.201509120604"/>
<unit id="org.eclipse.graphiti.feature.tools.feature.group" version="0.12.1.v20150916-0905"/>
<unit id="org.eclipse.graphiti.sdk.feature.feature.group" version="0.12.1.v20150916-0905"/>
<unit id="org.eclipse.emf.compare.feature.group" version="3.1.1.201509120604"/>
<unit id="org.eclipse.sdk.ide" version="4.5.1.M20150904-0015"/>
<unit id="org.eclipse.graphiti.sdk.plus.feature.feature.group" version="0.12.1.v20150916-0905"/>
<unit id="org.eclipse.m2e.sdk.feature.feature.group" version="1.6.2.20150902-0002"/>
<unit id="org.eclipse.emf.compare.ide.ui.feature.group" version="3.1.1.201509120604"/>
<unit id="org.eclipse.gef.feature.group" version="3.10.1.201508170204"/>
<unit id="org.eclipse.m2e.feature.feature.group" version="1.6.2.20150902-0002"/>
<unit id="org.eclipse.gef.sdk.feature.group" version="3.10.1.201508170204"/>
<unit id="org.eclipse.jdt.feature.group" version="3.11.1.v20150904-0015"/>
<repository location="http://download.eclipse.org/releases/mars/"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
<unit id="org.sonatype.m2e.buildhelper.feature.feature.group" version="0.15.0.201206251206"/>
<repository location="https://repository.sonatype.org/content/repositories/forge-sites/m2e-extras/0.15.0/N/0.15.0.201206251206/"/>
</location>
</locations>
</target>

Here is the current use of the "target-platform-configuration" plugin from the parent pom:

  <plugin>
    <groupId>org.eclipse.tycho</groupId>
    <artifactId>target-platform-configuration</artifactId>
    <version>${tycho-version}</version>
    <configuration>
      <target>
    <artifact>
      <groupId>com.cisco.yangide</groupId>
      <artifactId>com.cisco.yangide.target-platform</artifactId>
      <version>1.1.1-SNAPSHOT</version>
    </artifact>
      </target>
      <environments>
    <environment>
      <os>linux</os>
      <ws>gtk</ws>
      <arch>x86</arch>
    </environment>
    <environment>
      <os>linux</os>
      <ws>gtk</ws>
      <arch>x86_64</arch>
    </environment>
    <environment>
      <os>win32</os>
      <ws>win32</ws>
      <arch>x86</arch>
    </environment>
    <environment>
      <os>win32</os>
      <ws>win32</ws>
      <arch>x86_64</arch>
    </environment>
    <environment>
      <os>macosx</os>
      <ws>cocoa</ws>
      <arch>x86_64</arch>
    </environment>
      </environments>
    </configuration>
  </plugin>

What's curious is that in the original codebase that I inherited, the "target" element above is commented out. I've run the build both with and without this, and I don't see a difference. I'm guessing it should be there, so I've left it in, but the original authors likely know more about this than me.

Concerning the given answer, I find this pretty mystifying. You appear to be saying that if I have two plugin modules, I can't reference the classes from one in another without deploying the referenced bundle to a p2 repo somewhere. The thing is, I already have references to other bundles in the app in the "Require-Bundle" properties of one or more bundles, and these modules are building fine, without error.

Update:

Note that I'm looking at two other workarounds for this problem.

The people who maintain the nexus repo I'm using for this project are working on setting up a p2 mirror for the MavenCentral artifacts. They were having some cert problems with this, but I have a feeling this will be the eventual solution.

The other possibility is replacing Maven with Gradle, using the "Wuff" plugin. From what I've read, Wuff will just take maven dependencies and transparently package them as OSGi bundles, and this will just work. Unfortunately, what I'm finding is that the docs for Wuff are somewhat "primitive", and seem to not cover my application structure, although it could be that it's just assuming I know how all of this should work. There doesn't appear to be any way to ask questions about this, as the author hasn't replied to my issue or my email.

Update:

The files here are just excerpts, but you can see (and clone) the entire project, minus the "maventhirdparty" module and the reference to it, at github. My latest work is on the "forkmaster" branch, but that has no changes in this area.

Upvotes: 2

Views: 2872

Answers (1)

execc
execc

Reputation: 1123

I have worked with Eclipse for years, and I have encountered the exact same problem you're describing.

The thing is, tycho does not 'just' resolve dependencies from maven reactor, it actually resolves them from target platform. You may need to look into you parent pom file to discover it, but most likely tycho is configured to use the exact target platform you inherited.

It will look like

<plugin>
  <groupId>org.eclipse.tycho</groupId>
  <artifactId>target-platform-configuration</artifactId>
  <version>${tycho-version}</version>
  <configuration>
    <target>
      <artifact>
        <groupId>org.example</groupId>
        <artifactId>target-definition</artifactId>
        <version>1.0.0-SNAPSHOT</version>
      </artifact>
    </target>
  </configuration>
</plugin>

See docs (https://wiki.eclipse.org/Tycho/Target_Platform) for reference. Tycho compatible target platform should use uri-based location of p2 repositories. Also, alternatively, p2 uris could be specified in you pom.xml. In any case, you need to place you artifacts into p2 repository. I found that the best way to do it, is to use p2-maven-plugin (see the like for detailed examples: https://github.com/reficio/p2-maven-plugin). What you will need to do, is to build you repository using p2 maven plugin (with p2:site goal), make it http accessible (jetty or nginx serving the directory will work just fine), add it into you target platform, and you're done.

This part from p2-maven-plugin reference addresses you problem:

If some of your dependencies are not OSGi bundles or are not available in P2 update sites, SIMPLY define them in the p2-maven-plugin config, generate the site and make it available using jetty (or any other mechanism). Then add the URL of the exposed site to the target platform definition. In such a way you will have a consistent, manifest-first dependency management in Eclipse RCP project!

Hope this helps, and have (more) fun with Eclipse development!

Upvotes: 3

Related Questions