Am I misunderstanding the usage of Export-Package in OSGI Bundles? - eclipse

I'm developing a plug-in that needs access to the class org.eclipse.swt.widgets.Display. This class is contained in org.eclipse.swt.win32.win32.x86_3.5.2.v3557f-RCP20100710-0200.jar. However, the class is also exported by the manifest in com.ibm.rcp.jfaceex_6.2.2.20100729-1241 as follows:
Export-Package: com.ibm.rcp.jface.action,com.ibm.rcp.jface.launcher,co
m.ibm.rcp.jface.themes,com.ibm.rcp.jface.util,com.ibm.rcp.jface.viewe
rs,com.ibm.rcp.jface.window,com.ibm.rcp.jface.window.effects,com.ibm.
rcp.ui.widgets.api.jface,com.ibm.rcp.ui.widgets.api.swt
Require-Bundle: com.ibm.rcp.swtex,org.eclipse.swt,org.eclipse.core.run
time,org.eclipse.jface,org.eclipse.ui
Now, com.ibm.rcp.jfaceex is not included as part of my JRE System Library. It is, however, a bundle that includes classes of its own, as well as the exported packages above.
I was led to beleve that all I needed to do in my own project was to include a reference to it in my own project's build path, but this does not appear to work. The compiler is unable to resolve import statements against the classes in the org.eclipse.swt.widgets package.
If I need those classes, what, exactly do I need to do to import them correctly, and with the least amount of work?
Note We are not using Maven or any third party build tools. This is mandated by management, and I cannot change it.
UPDATE
Per the suggestion of E-Riz, below, I added org.eclipse.swt to the Required Bundles section of the Dependencies tab of my plug-in. Then, I attempt to export the project as follows:
Right click project, select Export.
Select Plug-in Development -> Deployable plug-ins and fragments
Select All, then click Finish
Eclipse builds the project, then tells me there were errors. Examination of the log reveals the following error:
1. ERROR in E:\NotesDev\Plug-in\com.ibm.lotuslabs.ui\src\com\ibm\lotuslabs\ui\UI.java (at line 1)
/**
^
The type org.eclipse.swt.widgets.Shell cannot be resolved. It is indirectly referenced from required .class files
There are dozens of these throughtout my code; one for every reference to a class or method in the org.eclipse.swt namespace bundle. This, despite the fact that the bundle debugs just fine!
UPDATE 2
I've discovered that you can, in fact, put absolute paths into the Bundle-Classpath in MANIFEST.MF. Oddly, this made the compile-time errors vanish. I am not convinced at this point that this is the correct thing to do, since absolute paths are certainly not guaranteed to correspond to the end-user's configuration.
However, installing the plug-in into Notes (the target platform), is not working as intended.
Notes reports that the plug-in installed successfully, but the plugin (an addition to the toolbar) does not appear. I am assuming, at this point, that something with the classpaths still isn't right.
UPDATE 3
Per request, the MANIFEST.MF and build.properties files. Please note that absolute paths were added by Eclipse, through the Dependencies and Runtime tabs.
MANIFEST.MF:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Context Plug-in
Bundle-SymbolicName: com.ibm.lotuslabs.context.service;singleton:=true
Bundle-Version: 1.0.2
Bundle-Vendor: IBM
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-Activator: com.ibm.lotuslabs.context.service.internal.ContextPlugin
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: context.jar,
lib/activation-1.1.1.jar,
lib/mail.jar,
lib/SatuitCRM_XML_API2.jar,
lib/commons-lang3-3.1/commons-lang3-3.1.jar,
E:/NotesDev/Notes/framework/rcp/eclipse/plugins/org.eclipse.swt.win32.win32.x86_3.5.2.v3557f-RCP20100710-0200.jar
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.ui,
org.eclipse.ui.views,
org.eclipse.swt,
com.ibm.rcp.swtex,
com.ibm.rcp.jfaceex,
com.satuit.core
Export-Package: com.ibm.lotuslabs.context.service.document,
com.ibm.lotuslabs.context.service.internal
Import-Package: org.eclipse.core.resources
build.properties:
output.. = bin/
bin.includes = META-INF/,\
context.jar,\
lib/activation-1.1.1.jar,\
lib/mail.jar,\
lib/commons-lang3-3.1.jar,\
lib/SatuitCRM_XML_API2.jar,\
plugin.xml,\
E:/NotesDev/Notes/framework/rcp/eclipse/plugins/org.eclipse.swt.win32.win32.x86_3.5.2.v3557f-RCP20100710-0200.jar
jars.compile.order = context.jar
source.context.jar = src/

Just because a bundle names a package in its Export-Package declaration does not necessarily mean that it contains the code for that package. A bundle can export packages from bundles that it depends on (although I think that's generally a bad idea in most cases).
For you, the solution is simple: in your MANIFEST.MF go to the Dependendencies tab and add org.eclipse.swt to the list of Required Plug-ins

Not quite sure, but two things come to mind.
Either remove the jar from your project classpath and add the com.ibm.rcp.jfaceex jar to your target platform (Preferences->PDE->Target platform and point to a directory containing the com.ibm.rcp.jfaceex jar)
Or leave the reference and also add the jar to your bundle classpath (on the runtime tab of the MANIFEST)
It don't quite see how this would result in this error, but classpath problems can manifest themselves in weird ways in PDE.

I have taken a look at the swt related bundles in eclipse juno:
org.eclipse.swt_3.100.0.v4233d.jar
org.eclipse.swt.win32.win32.x86_3.100.0.v4233d.jar
The widgets are in the second bundle which is a fragment to the first.
So you have to make sure both bundles are in the target platform. I am not sure if require bundle works in that case (it may work). You may try to instead import all packages you need.
Especially you need Import-Package on the package org.eclipse.swt.widgets.

Related

Eclipse RCP - Use Classes from a library that are imported from another plugin?

follow situation.
-pluiginCore <- includes many Libraries (libA,liB) via pom.xml, do nothing else
-pluginA..F <- want use classes from libA.
-pluginF..Z <- want use classes from libB.
Is this possible with RCP?
Is this a good way?
Do I need to import via pom.xml libA and LibB in each plugin where I wanna use it?
I added pluginCore as a dependency of pluginA but still cant use libA.
You have to do this using the directives in the MANIFEST.MF of the plugins.
For the plugin which contains the libraries you use the Bundle-ClassPath to specifies the jars in the plugin. For example:
Bundle-ClassPath: .,
lib/jogg-0.0.7.jar,
lib/jorbis-0.0.15.jar,
lib/vorbisspi1.0.2.jar
The . entry is for the normal code in the plugin, the other entries are jars in a lib directory.
You must also specify the additional jars in the build.properties for the plugin.
You use the Export-Package directive to say which packages from these jars are available to other plugins:
Export-Package: com.jcraft.jogg,
com.jcraft.jorbis
Plugins which wish to refer to these packages can either use Require-Bundle to add a dependency to the plugin exporting the packages, or they can use Import-Package to let Eclipse find the imported package.

How to make JUnit4 + Hamcrest 1.3 + Mockito work from Eclipse AND Tycho

I've managed to get JUnit 4.12 + Hamcrest 1.3 + Mockito 2.8.47 to work in Eclipse so that when I add them as dependencies, my tests will run.
(The way I've done this is using the p2-maven-plugin to bundle the following
artifacts from Maven Central into plugins/a feature and provide them via P2:
junit 4.12
org.mockito.mockito-core 2.8.47
org.hamcrest.all 1.3.0
Adding the plugins to my test fragment as dependencies makes the tests
run in Eclipse.
However, the Tycho build of the same fragment will fail with the
following messages:
java.lang.LinkageError: loader constraint violation: loader (instance of org/eclipse/osgi/internal/loader/EquinoxClassLoader) previously initiated loading for a different type with name "org/hamcrest/Matcher"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.defineClass(ModuleClassLoader.java:273)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.defineClass(ClasspathManager.java:632)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findClassImpl(ClasspathManager.java:586)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClassImpl(ClasspathManager.java:538)
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClass(ClasspathManager.java:525)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.findLocalClass(ModuleClassLoader.java:325)
at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:345)
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:423)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:372)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:364)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:161)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:12)
at org.junit.Assert.assertThat(Assert.java:956)
at org.junit.Assert.assertThat(Assert.java:923)
So it seems that some other plugin is loading the package
org.hamcrest.Matcher before my fragment does. This is probably due
to the import/export/partial import/partial export chaos surrounding the
JUnit/Hamcrest/Mockito setup.
Does anyone have an idea -- or even better: a working example -- of how to
get the three components work together both within the IDE (for quick
checks on whether tests run) and Tycho (for checks during the build)?
Seems like that the loader want the dependencies in a bundle.
But I guess you haven't put your test lib in a bundle.
You could try to add them in the dependencies of your product to see how it reacts.
Background
The root of the problem is, that org.junit already has a dependency to org.hamcrest.core. So when your test-plugins has a dependency to org.hamcrest.all (which contains everything of hamcrest-core and all other hamcrest artifacts), all classes specified in hamcrest-core exist twice. Once in the bundle of hamcrest-core and once in hamcrest-all, which is why you get the linkage error.
If you open the Manifest of org.junit in the Manifest-Editor of Eclipse and go to the 'Dependencies' tab it should show you org.hamcreast.core in the "Required Plug-ins" section and org.hamcreast.core should be re-exported. Or in the raw-manifest it should look like this:
Require-Bundle: org.hamcrest.core;bundle-version="1.3.0";visibility:=reexport
Solution 1 - add hamcrest sub-modules
Instead of adding the all hamcrest-modul containing hamcrest.all as dependency to my Eclipse test-bundle/project (via 'Require-Bundle'), I add the hamcrest sub-modules that I require, except for hamcrest-core (because it is already re-exported in my case). For me hamcrest-library was sufficient.
The available hamcrest sub-modules are (according to the org.hamcrest:hamcrest-parent pom, which can be found here: https://repo1.maven.org/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom):
hamcrest-core
hamcrest-library
hamcrest-generator
hamcrest-integration
Creating the p2-Repo containing the required bundles
When using Maven and the 'org.reficio:p2-maven-plugin' to build the p2-repo that contains the mentioned test-bundles, the conversion of the maven-artifacts to OSGi-bundles does not produce fully working results by default.
Converting a maven-module to a full OSGi-bundle consists mainly of configuring the MANIFEST.MF to contain proper entries. For this the p2-maven-plugin utilizes "bnd tool".
By default the Java packages provided by all maven dependencies of a maven module are added as optional Imported-package when that module is converted into a OSGi-bundle.
In my case this had the consequence that the org.hamcrest.library bundle refereed to the packages from hamcrest-core only via Import-Package in its MANIFEST.MF.
But unfortunately with only this specified, the Equinox-ClassLoader did not find the classes from hamcrest-core in the test-runtime and threw a corresponding exception. Maybe this is also caused by the fact that hamcrest-core and hamcrest-library have a package "org.hamcrest" and bnd-tools adds the exported packages of a bundle to the imported packages again.
The solution in my case was to instruct the org.reficio:p2-maven-plugin respectively bnd-tools to add org.hamcrest.core as "Require-Bundle" to the Manifest of hamcrest-library. For this, the instructions-element shown below needs to be add to the artifact-element of org.hamcrest:hamcrest-library in the execution-configuration of the 'p2-maven-plugin' in the pom.xml used to build the p2-repo:
<artifact>
<id>org.hamcrest:hamcrest-library:1.3</id>
<instructions>
<Require-Bundle>org.hamcrest.core</Require-Bundle>
</instructions>
</artifact>
If hamcrest sub-modules other than hamcrest-library are are used, the instructions need to be analogous, corresponding to the dependencies listed in their pom.
Edit
Eclipse Orbit provides org.hamcrest.library, org.hamcrest.integrator and org.hamcrest.generator bundles that have have org.hamcrest.core as required bundle (if necessary):
https://download.eclipse.org/tools/orbit/downloads/
Appendix
In the end first solution caused a SecurityException:
java.lang.SecurityException: class "org.hamcrest.Matchers"'s signer information does not match signer information of other classes in the same package
Which is a known issue. The following two solutions avoid this issue and work properly during Tycho builds and from within Eclipse.
Solution 2 - bundle hamcrest sub-module jars with a plug-in
Another approach is to download the jar of the required hamcrest sub-module and bundle it with a Eclipse plugin directly, like it is described here:
https://www.vogella.com/tutorials/Hamcrest/article.html#hamcrest_eclipse
To bundle the jar with a plug-in, include it in the project and add it to the plug-ins classpath. Go to the Runtime-Tab of the Manifest-Editor and klick Add... in the Classpath section and select the jar. This should add the jar to the .classpath, MANIFEST.MF and build.properties file properly.
Make sure the jar is included before the other plug-in dependencies (which include hamcrest-core), as stated in the mentioned tutorial.
If hamcrest should be used in multiple test-projects/fragments, add the jar to a test plug-in all other test-projects depend on.
Solution 3 - use org.hamcrest 2.x
Since hamcrest-2 there is only one org.hamcrest jar/artifact that includes everything from hamcrest. Using hamcrest 2 avoids all the issues and is my preferred solution. Except for the changed packaing of hamcrest the API did not break, so it should be sufficient to just include org.hamcrest:
https://github.com/hamcrest/JavaHamcrest/releases/tag/v2.1
In order to create a p2-repo that includes org.hamcrest-2.2 the following sippet has to be included into the configuration-artifacts element of the p2-maven-plugin execution in the pom.xml:
<artifact>
<id>org.hamcrest:hamcrest-core:2.2</id>
<instructions>
<Require-Bundle>org.hamcrest;bundle-version="2.2.0";visibility:=reexport</Require-Bundle>
</instructions>
</artifact>
<artifact>
<id>org.hamcrest:hamcrest:2.2</id>
</artifact>
The IUs org.hamcrest.core 2.2 and org.hamcrest have to be included in the target-platform to make them available for plug-ins in Eclipse and during. All plug-ins which depend on org.junit now have org.hamcrest also available.
This aproach works because org.hamcrest.core still exists in version 2 stream, even tough it is deprected and empty. Its only purpose is to redirect build-systems to the new org.hamcrest-2.x jar/artifact. Therefore org.hamcrest.core-2.2 specifies a compile dependency to
org.hamcrest-2.2 in its pom.xml. Unfortunately the p2-maven-plugin dosn't translate it directly into a bundle-requirement for org.hamcrest in the manifest, but with the sippet above enforces that.
Because org.junit requires the bundle org.hamcrest.core with a minimal version of 1.3 (but without upper-bound) it uses the present org.hamcrest.core-2.2 . org.hamcrest.core-2.2 again requires org.hamcrest-2.2 and re-exports it. This makes org.junit use org.hamcrest-2.2 in the end and because org.junit re-exports hamcrest-core it also provides org.hamcrest-2.2 immediately to all depended plug-ins.
Note
If you want to play around with different variants of a jar, don't forget to clear (means delete on the drive) the bundle pools of Maven (in <your-home>/.m2/repository/p2/osgi/bundle/ and Eclipse PDE (in <your-workspace>/.metadata/.plugins/org.eclipse.pde.core/.bundle_pool/) in between. Otherwise you will always use the first one, because jar's with the same version are not updated.

Resource META-INF does not exist

I have tried to convert a regular Java project to an Eclipse plug-in with Tycho, but something went wrong, and I can't figure out what.
These are the problems (I'm just guessing they're related):
first of all: imports of other projects won't work, even if the other project is in the same workspace
when I open up the plug-in editor on the "Build" tab, I get the following exception: "Resource '/Project/target/classes/META-INF' does not exist."
after the multiple error dialogs with above message are gone, the trees of the "Build" tab are completely empty
I have no idea what could help figuring out that problem, so just ask if you have a hunch.
build.properties
source.. = src/
output.. = target/classes/
bin.includes = META-INF/,\
.
MANIFEST.MF
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.acme.project;singleton:=true
Bundle-Version: 1.2.3.qualifier
Bundle-Vendor: ACME
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Require-Bundle: [snip]
Import-Package: [snip]
How do I fix my plug-ins?
For reasons that are completely beyond me, there was the following line in the file .settings/org.eclipse.pde.core.prefs of the project:
BUNDLE_ROOT_PATH=target/classes/META-INF
I removed it and now everything works.
(To see the file, you need to either use the native file system or disable the ".* resources" filter of the Package Explorer.)

Cannot add an eclipse plugin, the plugin won't show up inEclipse

I am trying to add an eclipse Elugin (http://www.cs.wm.edu/semeru/TopicXP/) to my eclipse. I followed the instructions (copied the jar file into the plugins folder), but the plugin won't appear at all.
I do not have the LDA option in the right click menu
I do not have anything under Window > Show View > ...
I don't even see the plugin under Installation Details > plug-ins
I am in the Project Explorer, and using Eclipse Kepler Service Release 2. I did also try Eclipse Luna, as well as Eclipse 3.5 (the version of Eclipse that is mentioned in the plugin page) but none of these worked.
I did check the manifest and I have all required bundles. I also added Java 1.7 to it, since my environment is 1.7.
I cannot think of any reason, the plugin won't show up at all. I assumed that if there are some comparability issues, I will at least see the plugin or some errors related to loading it, but I see nothing.
Ideas?
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: TopicXP
Bundle-SymbolicName: edu.wm.topicxp;singleton:=true
Bundle-Version: 0.2.4
Bundle-Activator: edu.wm.LDATopics.LDATopics
Require-Bundle: org.eclipse.ui,org.eclipse.core.runtime,org.apache.luc
ene,org.eclipse.jface,org.eclipse.ui.ide,org.eclipse.ui.workbench
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7, J2SE-1.5
Bundle-ClassPath: .,lib/args4j-2.0.6.jar,lib/JGibbLDA.jar
Import-Package: org.eclipse.core.resources,org.eclipse.draw2d,org.ecli
pse.draw2d.geometry,org.eclipse.jdt.core,org.eclipse.jdt.core.dom,org
.eclipse.jdt.ui,org.eclipse.jface.text,org.eclipse.ui,org.eclipse.ui.
ide,org.eclipse.ui.texteditor
Old question, but this may help someone still. This sounds very similar to a problem I struggled with. It's likely that the plugin you are trying to load has unresolved dependencies, and Eclipse doesn't show you anything in that case. But you can find out if that's the problem, and what dependencies may be missing by using the OSGI console.
First, invoke Eclipse from command line and add '-console' option.
Then in the OSGI console, use 'install' command to try to load your plugin. For instance, if you have placed com.my.plugin in the plugins folder of your Eclipse installation:
osgi> install reference:file:plugins/com.my.plugin.jar
That will give you a bundle ID in the output. Use that with the 'diag' command to see any missing dependencies.

Tycho cannot resolve Require-Bundle: org.sample.ide.common;bundle-version="1.0.0.qualifier"

I build an Eclipse plug-in project with Tycho.
I got this error message.
[ERROR] Cannot resolve project dependencies:
[ERROR] Software being installed: org.sample.ide.core 1.0.0.qualifier
[ERROR] Missing requirement: org.sample.ide.core 1.0.0.qualifier requires 'bundle org.sample.ide.common 1.0.0' but it could not be found
org.sample.ide.core-1.0.0.qualifier has org.sample.ide.common-1.0.0.qualifier as required bundle.
When I export the plug-in project with the Eclipse PDE export function, the dependent projects are recognized inside the same workspace.
And my manifest.mf has version like 1.0.0.qualifier, and my pom.xml has 1.0.0-SNAPSHOT. Is that problem?
Having artifacts with .qualifier versions is supported, so this is not the cause of your problem.
However I am not sure to what extend Tycho also supports .qualifier replacement in dependencies, e.g. Require-Bundle headers. (At least, this is buggy.) So you should try to build your project with a dependency to version 1.0.0 instead of 1.0.0.qualifier.
Tycho replaces the .qualifier with a timestamp or fixed string in the reactor build within all manifest files. It resolves the files from the repositories defined from the target files attached, and from the local repository. If none of these contain an exactly matching dependency, tycho will not succeed with the build.
Note that the resolution of PDE export is based on the current target set in Eclipse, and that PDE will replace the qualifier for all bundles open in the workspace. Tycho does not know of these, its scope is what is included in the reactor during the build.