How to define an OSGI/Eclipse plugin with binary components for multiple platforms - eclipse

I created an Eclipse plugin and there is a native binary needed to support its functionality. I have the native code ready for Win and Mac. The invocation of the native code is different for each platform, so there is also some plugin code related to the native code. (In fact the native code is JNA code, so very different indeed.) Currently I have an extension point and each native support plugin contributes there. So, as soon as a native support is here, the main plugin works. Also I have a test fragment for each of the native support plugins to unit test functionality.
How should I set the plugin(s) up, so that everybody get's the right plugin when downloading from update site or p2 repo? (I noticed that for example SWT uses fragments for the native code, so is this the way to go?)
Edit: After converting the plugins to fragments as indicated by the answer, what should I do with the unit test fragments of these plugins? Fragments of fragments are not possible.
How can I set this up in Tycho, so that Tycho build runs the test suitable for the current platform and ignores the other platform.
Edit: I have Mac and Windows native code, two fragments and therefore two environments in the pom. But then Tycho complains "plugin x cannot be installed in this environment because its filter is not applicable", of course not, only one of Win/Mac can be active at any certain time. Can Tycho figure out this itself or do I need os dependant Maven profiles?

Yes, you will need to package the native bundles into plug-in fragments. Each fragment should specify the platform filter to ensure only one fragment is valid per platform. For example on Windows 64 bit you need to specify os=win32, ws=win32 arch=x86_64.
If your fragments are part of a feature, you should also specify the platform filter in the feature definition.
Under Tycho, you need to specify all your supported platform filter combinations under the environments section of target platform configuration in your pom file.
Tycho always runs tests under the current platform. Add your fragments to your test runtime - see here on adding dependencies to the tycho test runtime. Tycho often needs help in identifying fragments to add to the test runtime.

Related

What is the right way to create JUnit tests for Eclipse fragments?

One of the most common uses of eclipse fragments is as a container for JUnit test classes. But how to write JUnit tests for Eclipse fragment when it plays another, more important role? For example, when it has platform specific code.
The problem is that it is impossible to create a fragment for a fragment. And you can't write tests for host plug-in to test the fragment because it doesn't even compile as a fragment is "merged" into a host only at runtime.
I don't know of a satisfactory solution, however, you may want to consider these workarounds.
Eclipse-ExtensibleAPI
You can use the Eclipse-ExtensibleAPI manifest header like this
Eclipse-ExtensibleAPI: true
It causes the packages exported by the fragment to be re-exported by the host bundle. Now you can create a test bundle that imports the desired packages and therefore has access to the public types in the fragment.
This isn't as close as test-fragments where you benefit from tests and production code using the same class loader that gives access to package-private types and methods. But you can at least test through the publicly accessible means.
Note, however, that this header is specific to Eclipse PDE and not part of the OSGi specification. Hence you are tied to this development environment. Furthermore, the packages of the fragment will be exported through its host bundle and will be visible not only for the test bundle but for all bundles.
Java Library
If your fragment has few dependencies and doesn't require the OSGi/Eclipse runtime you could consider treating it as a plain Java library w.r.t tests. Another sibling Java project could contain tests and have a project-dependency (Properties > Java Build Path > Projects) on the fragment project. Again, access to package-private members would not work.
And if you use a build tool like Maven/Tycho, some extra work would be required to declare dependencies and execute these tests during the build.
Bndtools
You could also look into Bndtools to see if this development tool fits your needs better than the Eclipse Plug-in Development Environment (PDE).
Plain JUnit tests are held in a separate source folder in the same project as the production code. This would give your test code access to the production code in the same way as if test-fragments were used.
Bndtools also supports executing integration tests, though I doubt that you would have access to the fragment code other than through services or other API provided by the fragment.
For CI-builds, Bndtools projects usually use Maven or Gradle with the help of the respective bnd(http://bnd.bndtools.org/) plug-in. Just as Maven/Tycho is used to build and package PDE projects.
Since Bndtools is an IDE extension to develop OSGi bundles, it doesn't know about Eclipse plug-in specificities such as extensions declared in the plugin.xml. Hence there is no builder and editor for these artifacts. But if you are lucky, you may even be able to use the PDE builder to show error markers for invalid extensions and extension points.
Another downside that comes with having production- and test-code in the same project, is that pure test dependencies like JUnit, mock libraries, etc. are also visible for the production code at development time.
Of course, the produced (fragment) bundles do neither contain test code nor test dependencies.
However, Bndtools itself is developed with Bndtools. So there is proof that Bndtools can be used to write Eclipse plug-ins.

Several versions of a plugin in a feature.xml

I've created an feature-based Eclipse product where all dependencies respectively external plugins are specified in a dependencies feature project. Some dependencies need different versions of the same plugin. How can I specify several versions of a plugin in a feature.xml? Eclipse seems to always use the current version of a plugin. I've tried to add a dependency with a strict version interval, e.g. [1.6.0.v201011041432,1.6.0.v201011041432], in the feature.xml but Eclipse doesn't accept this format.
I had a similar problem when running a feature based product within Eclipse (Kepler) where multiple versions of the same bundle were involved.
In the end I used a workaround - I changed the symbolic names of the bundles, so they all have different names. If you consequently use Import-Package instead of Require-Bundle this will make no difference in the dependencies you define for bundles or in the OSGi runtime, only in your Feature definition.
This solution is not pretty, but at least it's rather easy to do.
Thinking about that OSGi is intended to target exactly this kind of use case where you have multiple versions of the same dependency/bundle it's rather strange how bad the support in Eclipse is, if you actually have this kind of use case.

Eclipse 4 RCP, is it possible to exclude/include extensions conditionally

I'm working on an Eclipse rcp application which is using a middle layer to request data. I want to run my application in offline mode i.e. if data service is not available I should be able to work on some dummy data. For this purpose I want to exclude/ include extensions (not extension points but extension point providers). Is that possible?
Thanks
If you put the live and test versions of the extension point implementation in different plugins you can then choose which plugins to include in the product build - so you would have two product configurations, one for testing and one for production. When you are testing in Eclipse you can configure the plugins to include in the Run Configuration, so again you would have a test and production configuration.
It might also be possible to use a plugin fragment to contain just the part which varies. Use New / Project / Plug-in Development / Fragment Project to create.

Mixed Target Platform leads to resolution errors

I am developing plug-ins within an Equinox context. I have set up a target platform which contains the Equinox plug-ins my plug-in will depend on.
Now since I need some new components, I have created a mixed target platform, consisting of the existing platform plus some additional plug-ins from my developing Eclipse.
As soon as I mix these platforms (both 3.8) all my plug-ins are showing errors, and almost everything can not be resolved, e.g. "org.eclipse.*", although they are definitely present in the target platform.
When I remove the additional components, all the old components can be resolved again. Any ideas?
It seems that you are trying to include multiple versions of certain bundles in you target platform, while using the so-called "planner mode" for a Software Site location. (In the target editor UI, the planner mode corresponds to selecting the option "Include required software".)
In this mode, p2 takes the features that you have selected plus all transitive dependencies. This resolution is done in a way as if you were trying to install the selected features into Eclipse. This resolution fails if you include multiple versions of singleton bundles, which most Eclipse platform bundles are.
So if you need to have multiple versions in the target platform, you need to use the "slicer mode" (equivalent to de-selecting the "Include required software"). Note that in this mode, only the features and their included bundles are added to the target platform. You may need to add more features in case there are missing dependencies after activating the target platform with slicer mode.

General questions about PDE programming

Here are two short, but hopefully good questions:
When to use plugins and when fragments?
What is a headless PDE build and when to use it (and when not)?
Fragments are for when you want to expand or alter the functionality of a plugin. A fragment cannot exist on it's own, it requires a parent plugin. The typical example of a fragment are for localizing a plugin, i.e to change strings to other languages. The fragment will then alter the functionality of the plugin to replace resources or code with the contents of the fragment.
More details here Tutorial here
The headless part means you do the build without a gui, i.e from commandline or from a tool such as jenkins/hudson. PDE stands for Plugin Development Environment. In short, it adds some tasks to Ant, and you can use the defined resources and dependencies in the plugin.xml to build. The alternative is to again define classpaths, sources, etc in an Ant build file.
I've used it in some projects and it has been difficult to setup properly, but its the best way to build Eclipse plugins or products. We wanted to use relative paths for the build and had major problems with that. The earlier in your project that you set up a continous headless PDE build, the easier it will be to configure.
More info here