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

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.

Related

Eclipse: Add class to startup classpath

I have a plugin that uses a JRE class that was removed in Java 8. I want to add that class to the Eclipse startup classpath so that it is available to the plugin. The Java 8 endorsement mechanism, which appears to be deprecated, doesn't seem to allow adding the class to the JRE.
Every Eclipse plugin has its own separate classpath. Plugins can only reference classes in the plugin or in other plugins on their classpath. The classpath is defined by the 'Require-Bundle', 'Import-Package' and 'Bundle-ClassPath' entries in the plugin's MANIFEST.MF.
So if you have additional classes add them to the plugin.
You can also add extra jars to the plugin by adding them to the 'Bundle-ClassPath' entry in the MANIFEST.MF and updating the 'build.properties' to include the jar.

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.

Maven add custom multiple jars from folder

I have a custom list of jars around 40 jars in a libs folder. I want to add all as a maven dependenices.
+ project
pom.xml
+ src
+ libs
Is there any way by that add all jar at a time.
Maven manages dependencies rather different than just including jars.
Essentially if you have a dependency on A and A uses B, you will need to have both A+B in your lib folder, but only A in your maven project, because maven transitively will include the subdependencies.
You should probably look through the maven repository, and see if you can find the jar files there in a similar version, and include that instead.
i.e. if you have commons-collections4-4.0.jar, use http://search.maven.org and write commons-collections4, and you will see a list of candidates. probably some with multiple version. Note, maven uses a groupId to scope jar files, so pick one with a suitable groupId, in this case org.apache.commons (Since commons-collections is an apache.org project).
When you have identified your dependency, it will show you ways to include it in your build, e.g. for maven, it would be
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
Looking at the pom file, you will be able to spot potential subdependencies, but otherwise, once you have added the dependency to your <dependencies/> section of your pom, run a mvn dependency:tree or mvn dependency:list to see how dependencies are transitively included.
Should you end up with libraries you cannot find in maven central, read this guide for the rest http://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html
Found one wonderfull plugin to achieve this task. addjars-maven-plugin

How to find the parent of a Maven transitive dependency

I am building a Java (web) application with Maven and Eclipse.
When I look inside my .war file I can see the following logging libraries there:
log4j-1.2.14.jar
log4j-1.2.17.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
I did not declared these libraries in my pom.xml, so they probably are transitive dependencies (i.e. dependencies of my dependencies).
How can I find out which of my dependencies depend on these libraries?
I tried to use the mvn dependency:tree plugin, but it does not show any of these .jars.
In Eclipse, the Java Resources > Libraries > Maven Dependencies node does not show them either. Though, curiously, it shows other transitive dependencies of my project.
If you want to rely on maven only you may want to take a closer look on the dependency plugin, here are two examples:
mvn dependency:tree -Dverbose will display more detailed information - especially for example if a artifact will be omitted for conflicting with another artifacts version (e.g. convergence issue). It will also display you the hirachy with all the transitive dependencies.
To have a specific artefact analyzed (to for example find who delivers a specific transitive dependency) you can specify like so:
mvn dependency:tree -Dincludes=com.my.group.id:my-artefact-id:jar:1.0.1 -Dverbose
(Where you obviously need to adjust the artefact, packaging type and version according to your needs)
Open pom.xml in Eclipse and go to Dependency Hierarchy tab
![enter image description here][1]
It should show you the dependency tree in the Dependency Hierarchy tab. Evgeniy Dorofeev is right.
Something similar to the screenshot attached
you would probably have to expand all.
EDIT: Refined the answer.
Thats a little weird. But here is what i found.
If you go to http://mvnrepository.com/artifact/log4j/log4j/1.2.17
it will show you which dependencies are used and which does the jar file depend on.
The springframework dependency for web-mvc 3.2.4 would download the spring-core and the spring-core dependency uses log4j.

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

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.