Provisioning your target platform from a p2/update site is a gem of a feature that was released with Eclipse 3.5. Chris called it “fantasy come true!” and so did many others. You could read the details on how this works from this article by Chris. (On the other hand, if you haven’t used target platforms at all, stop doing any further eclipse plugin development and read about it here first, right from the target platform expert Ekke).
Provisioning your target platform from a p2 site allows you to basically download any eclipse flavor you like, and with the click of a button set up your target platform. PDE downloads all the plugins required for your target platform automatically from different software sites based on your target definition and builds your workspace. Although this is a great feature, using this in your workflow has some shortcomings.
- If your target platform is large (which is mostly the case), this would end up in a lot of bandwidth usage every time the bundles are downloaded from different software sites. Also, if you do not have high speed internet or you have restricted internet access, the time to initialize the target platform could be very long.
- Not all bundles are available from p2/update sites. Although p2 marketing has been quite successful recently, many plugin providers still doesn’t host their products as p2/update sites. Although, you could have such plugins as local folders or in a shared network folder, this takes away the power of provisioning.
- Many p2/update sites don’t believe in archiving older versions and continue providing them as p2/update sites. Hence you have no guarantee that your platforms based on some older bundles will work forever.
- Many development projects version their target platforms and maintains them in versioning systems like SVN. This is a prerequisite to reconstruct older target platforms. This, however, is not possible with the approach above.
If you have a closer look, you could see that many of the limitations above stems from the fact that the software sites referenced are not local, nor within your control. All of them could be avoided if you provision your target platform as a local p2/update site. This means, instead of you downloading bundles from a public software site, you (and your team) downloads them from a local p2/update site that you have set up with all your required target platform plugins/features. In this article, I describe a workflow in setting up such a local p2/update site for your target platform.
1. The aggregation task
The first step would be to aggregate all the plugins and features required by your target platform. You could easily do this by creating a target definition file which references the software site of your bundle providers using “New -> Target Definition“. If your bundle provider doesn’t have an p2/update site, reference them from a local download folder.
You will never share/distribute this “setup” target file
A sample target definition file could look like this.
If you want your target to support multiple platforms, make sure to check this checkbox while you add a software site.
2. Testing the target
Using the target definition editor, set the target by clicking “Set as Target Platform“.
Additionally, you could set the target platform in “Preferences -> Plug-in Development -> Target Platform” and selecting the newly created target. If all the projects in your workspace builds fine, then you have setup the target platform correctly. Else repeat Step 1 to add the missing plugins and the workspace errors vanish.
3. Creating a new target platform feature
Using the feature project wizard, create a new feature for the target platform.
Make sure to properly name and version the feature.
In the plugin selection page, the plugins listed are the ones in your target platform together with your workspace plugin projects. Select all plugins except the ones in your workspace.
4. Creating a p2 site for target platform
You could do this either using PDE or using Buckminster.
If you want your target platform to support multiple development platforms (OSX, Linux, Windows etc.) use Buckminster (unfortunately, PDE had some export issues doing this)
4.1. Creating p2 update site using PDE
Create a new update site project using the update site project wizard.
Create a proper category and add the target platform feature you created earlier as child, using “Add Feature…“.
Build the update site using “Build/Build All“.
If the build is successful, the update site project could look like this.
4.2 Creating p2 site using Buckminster
Install Buckminster from update site http://download.eclipse.org/tools/buckminster/updates-3.6 (for Helios).
Create a buckminster.properties file in your target platform feature project.
## buckminster.properties ##
#Where all the output should go
# Where the temp files should go
# How .qualifier in versions should be replaced
Right click the target platform feature project and select “Buckminster -> Invoke Action…”
Select buckminster.properties file created using “Workspace” button followed by “site.p2” from “Matching items” list
Select “OK” to close the dialog.
The p2 site would be created in feature folder pointed by buckminster.output.root in your buckminster.properties file.
You do not have to create a update site project (as you did in the PDE approach) while using Buckminster
5. Deploying the target platform
Identify a server space in your local network where the p2 site could be deployed (preferably a webserver). Copy the p2 site contents to this location.
6. Creating the final target definition
Create a new target file and point it to the newly hosted p2 site (similar to Step 1)
7. Testing the final target platform from local p2 site
Open the target file and set the target using “Set as Target Platform” as before. The bundles from the local p2 site will now be downloaded and your workspace built again. If you have zero errors, you have succeeded in setting up a p2 update site for your target platform. Distribute the final target file to your development team and they could now set their target platform in the same way.
8. Managing different versions of target platforms
You could provision multiple versions of target platforms at the same local p2 site. All you need to do is to create a new feature for the new target platform, add it to the update site site.xml, build and deploy the target platform as before and distribute the updated target file.
A “split package” is a pretty old Java term where you have packages in different libraries with the same name providing related (or sometimes unrelated functionality). The classes in one package can access classes in the other package (with the same name) across library boundaries without any problem at both compile and runtime. This is true even for package-private classes. This works fine in the Java world as you deal with only a single hierarchical class loader. If you bring this concept to the OSGi (or Eclipse) world, you are in for trouble, where each bundle has its own class loader. This is what happened to me while I was doing some heavy refactoring recently.
I had the task of making a “monolithic” Eclipse system modular. Refactoring in JDT did a great job and in the end I had a modular system with no compile time errors. The pain started when I ran the application and started getting exceptions, I have never seen until now working with Eclipse framework.
Here’s what I did in short. I split a plug-in into two plugins, “Plugin A” and “Plugin B”, where “Plugin A” contained the main functionality and “Plugin B” was providing some library functions. So naturally “Plugin A” depended on “Plugin B” (or in OSGi terms, “Plugin A” had a “Require-Bundle: Plugin B” declared). Though not intentional, both plugins ended up having a package with the same name “SplitPackage”. A “Class A” in “SplitPackage” in “Plugin A” had a method call on “Class B” in “SplitPackage” in “Plugin B”.
PDE did not complain nor did I get any compile time errors. Now when I ran it, I got a “java.lang.IllegalAccessError: tried to access Class B from Class A”. I kept wondering why I would get this linkage error which I should normally get at compile time from PDE. After spending half a day on it, I found the cause. “Class B” was declared as package-private . The moment I changed this into a public class, all was well again (although this wasn’t my final solution).
The root cause here was that OSGi loaded “Plugin A” and “Plugin B” using different class loaders and the packages “SplitPackage” in both bundles are not the same and they live in two different worlds with a clear boundary between them. “Class A” in “Plugin A” cannot see package-private “Class B” after the bundles are resolved. This resulted in the java.lang.IllegalAccessError exception at runtime. The exception doesn’t pop up at compile time as a Java compiler doesn’t know these boundaries and sees them as split packages. May seem strange but true!
Moral of the story is that never have split packages in the Eclipse environment. For OSGi, a package is the atomic unit and it should be as cohesive as possible. If you have functionality split into two packages with the same name, then they are not cohesive and ideally the packages should have different names or the classes should live within one package. If you really need split packages, make one of them an Eclipse fragment plugin. A fragment plugin always lives within a host plugin and both of them are loaded by the same class loader.