Using Eclipse's Link Source Feature
Join the DZone community and get the full member experience.
Join For Free
NOTE: Apparently a bundle with a linked source will not be exported or built in an update site built. also Tycho will complain that it can't find linked sources, which severely limits the possibilities. A workaround is to export the bundles as plain old jars (this works fine for some reason), but the problem is far from ideal. See bug reports: |
Introduction
I've been using Eclipse for more than ten years now, and so I like to think I know my way around it's offerings, but every now and then I get pleasantly surprised by discovering a feature – which usually had been there all along- but for which I finally have made the time to investigate. In this case, I am talking about the 'Link Source' feature in the Project Properties tab. Most experienced Eclipse users will at some point wander through the project properties, for instance when certain libraries are not found by the compiler, or when a plugin project starts to behave unexpectedly. The Project Properties tab comes into play when the Manifest.MF file no longer provides the answers for certain problems you face, and you need to delve deeper into the classpath and project settings. It also becomes topical when you need to make a custom project.
At Project Chaupal we are currently maintaining and updating the code from Project JXTA. JXTA has been around for quite a bit in the open source community, and the development has had its ups and downs, so the code could do with a makeover here and there. I've been involved with keeping the code available in OSGI since 2006 or so – also with its ups and downs- and one of my ideals would be to automatically generate the OSGI bundles straight from the JXTA sources, without any handwork. The JXTA jar ships with a large number of third party libraries (e.g. Jetty and Log4j), some of which are available as OSGI bundles, so I don't want to include them in the JXTA OSGI bundle I make. A list of dependencies in the Manifest should be enough! Some of the third party libraries also aim to provide the same functionality (e.g. the database functionality provided by Derby and H2), so I would prefer to divide this over two bundles, and then just select the bundle that is needed.
Ever since JXTA 2.6, the code has been mavenised, and so the code now conforms to the typical structure that Maven requires, with a specific location for JAVA code (src/main/java), resources (src/main/resources) and tests (src/main/test). I prefer to use Tycho for my OSGI bundles, so the regular Eclipse tooling is leading. As a result my goal is to:
-
Create separate bundles for the core and the test source code
-
Add the required resources, such as .properties files and the likes
-
Split the core source code over different bundles, so that every bundle depends on one third party library at the most.
It took me a day or two to get everything the way I wanted it, but in the end it was surprisingly easy, so I thought I'd share the experience.This tutorial assumes that you are well-versed in Eclipse and OSGI development. If not, a good tutorial on the subject can be found here.
Preparation
As was described earlier, the plan is to use a Maven project (available on GitHub) as a source for a number of OSGI bundles. For starters, we need to do the following;
-
Prepare an Eclipse IDE with Egit and, optionally, with support for GitHub. As always, Lars Vogel's tutorial provides an excellent guide to achieve this. With the GitHub support you can actually search for the required repository, and clone it in your workspace within minutes.
-
Add Maven Support for Eclipse. The tutorial can be found here.
We now have an Eclipse IDE with one project loaded in the workspace, which conforms to the Maven structure. Now we can start to do the magic!
Extracting Source Files in an OSGI Project
First create a new plugin project, using the wizard (File → new → Plugin Project). Fill in the required details as requested (target platform→OSGI framework) and press 'finish'. We now have a standard textbook OSGI bundle project. For the sake of argument, let's call this bundle org.mybundle.host.
Now we are going to add java source files and resources from the Maven project:
-
open the project properties tab (right mouse click → properties)
-
select the 'Java build path' option and choose the 'source' tab
-
press 'Link Source' and browse to the 'main/java' subfolder of the Maven project.
-
Close the project properties
-
Include the source folder in the build.properties file and clean the workspace
-
Update the Manifest to include the required dependencies, and export the packages as needed
As you can see, the java files have been included in the bundle project, and will compile in a normal fashion.
TIP: Currently the source file will by default have the same name as the folder. You can change this in the 'link source' wizard. For instance, you can delete the 'src' folder that is created by default, and replace it with the linked source if you want. This should only be considered if you are not going to make specific java files in the bundle. |
Next we are going to include the resources, such as .properties files that are included in the Maven project. As an exercise, we will exclude all html files that may be included.
-
Open the project properties and follow the steps described previously, but now select the main/resources folder. Then press the 'next' tab, instead of closing
-
You can now select which files to include or exclude in your bundle. Select the 'exclude' tab, and enter the following pattern:
**/*.htm*. -
Close the project properties, update the build path and clean the project
We have now included the desired resources, and in principle the bundle should now work as desired. With the include and exclude tabs, you can determine which files and folders you want to add to your bundle. The inclusion and exclusion patterns follow the conventions used by Apache ANT.
TIP: You can check if the bundle has the correct source and resource files by opening a file explorer (in Windows) and browsing to the 'bin' folder of your bundle project. If you first refresh your bundle project (F5 in the Eclipse IDE), the correct class and resource files should be present there. |
NOTE: Although I would not recommend it, it is possible to link the sources of multiple non-OSGI code sources this way. Even though the folders need different names, they will be built as if they are one source folder. |
Now we create a second plugin project for the test files. We will call this bundle org.mybundle.test
-
Open the project properties and follow the steps described previously, but now select the main/test folder.
-
If required, you can exclude certain tests in the 'exclude' tab
-
Close the project properties, update the build path and clean the project
-
In the manifest editor, include the dependencies to org.mybundle.host, and for instance JUnit and JMock.
When there are no more compiler errors, your two bundles should behave as regular OSGI bundles, with the only difference that the sources are extracted from the Maven project.
TIP: It is also possible to make fragment bundles this way, and you can include library resources in your bundle (such as third party jars). This way you can restructure a non-OSGI project at will |
Using Variables
When you store your projects in the cloud, such as on gitHub, you may often find multiple versions of your workspace scattered over different computers, and your repositories stored on different drives. This means that linking your sources with absolute paths, as we have done previously, is not a very versatile approach. Especially with linking this may become problematic, as the linked source project (e.g. the maven project) can be stored on a different location than the project that uses the source files. Luckily eclipse allows you to define variables in your project, which can help either to standardise the relative locations or, if this is not possible, to easily modify the links.In order to achive this, follow these steps:
- Select the project properties, and select the 'Java Build Path' option.
- Add or Edit a link source, and select the 'variables' button.
- Add one or more new variables by pressing the 'New' button and entering the locations. Then press 'OK'
- GITHUB_LOC: | C:/Users/MyName/MyGithubLocation |
- MYPROJECT_LOC: | ${GITHUB_LOC}/MyProject |
- MYSOURCEPROJECT_LOC: | ${MYPROJECT_LOC}/MySource |
Now all you have to do is change the 'Linked folder location' to:
MYSOURCEPROJECT_LOC/src/main/java
in order to include the Maven project in your bundle.You can then also add a resource folder:
MYSOURCEPROJECT_LOC/src/main/resources
TIP: In the above example with a Maven project, the linked folder name will default to 'java' (and the resources to 'resources'). It is recommended to leave it that way, because you can then use the 'src' folder for bundle specific code that yuo may want to add, like a decalarative service. Also remember to update the build path to include the folders your project needs. |
Conclusion
The 'link source' option provides a powerful way to make non-OSGI code accessible as OSGI bundles. The inclusion and exclusion patterns allow you to customise the bundles to your needs.
Opinions expressed by DZone contributors are their own.
Comments