Posted in Tutorials
Recently, while fixing a bug, there was a discussion in the emails going on whether adding a new field to an interface in the API would break the binary compatibility to the existing clients. I strongly believed that only adding a method would break, not by adding a field. But API tooling was complaining that it is a breaking change. Luckily Olivier Thomann came to rescue and explained why it is a breaking change.
API is what it stands for A Pain In <you know where>. Maintaining an API is not an easy task and its pretty easy to make mistakes (as in the above case). In this tutorial, I'm going to explain the concepts of API tooling, setting up and using it effectively.
What is API Tooling
API tooling helps a developer in creating and maintaing the API in the OSGi bundles. It mainly does these three things:
(1) Report Binary incompatibility
(2) Helps in versioning the bundles correctly
(3) Identifies the non-API leaks and usages
Setting up API tooling in your project
Since 98.4% of us already have a product already, I'm going to explain how to setup for an existing product. Lets take the RCP Mail template created by the PDE wizard. The wizard creates all the classes in a single package. Lets refactor it to two different packages like this:
Now, we would like our clients to use the rcp.mail.api package, so we export it in the Runtime tab of the Manifest Editor. Use the PDE's Product configuration Wizard and create a new Product out of this RCP Mail.. You can run the product to check everything is alright and then, export it using File->Export->Export Product.
That will be our version 1.0 product that we have shipped to our customers. Customers are using it and are happy. That will be our baseline now. BTW, baseline means the set of bundles and its state, against which we will be validating the binary compatibility and versioning.
There are two steps in setting up API Tooling. The first one is to tell API Tooling that this exported product is the baseline. Open the Preferences dialog and go to Plug-in Development->API Baselines. Now click Add Baseline and select the directory where we have exported the product. Click OK and go back to the Preferences. Select Error for the Missing API baseline option (good to have).
The second step is to add the API Tooling nature and builder to our project. API Tooling gives a wizard for this. Right click our project-> PDE Tools->API Tooling Set up. Select the project and click Finish.
We are all set.
Manage versioning with API tooling
Lets start working towards the version 2.0 of our product. The first requirement for 2.0 is an enhancement to add an action for the New Message. Lets start doing it by adding an Action in the api package.
Once we create the class, API tooling will give you an error like this:
Now use the Quick Fix and get the @since tag there. The error should have gone. But wait, isn't this wrong? The @since tag says that this class is available from version 1.0 of the bundle. But this was absent in 1.0 and added only in the next version, which we are working. Basically. API tooling's quick fix takes these @since tag from the bundle's version. Since we have added a new API (whether its a type/method/field), ideally we should have incremented the bundle version also. As you can see, an error (with a quickfix and the reason) is now created on the bundle's manifest. Lets use the quick fix to bump up the version.
Now the error is shown in the NewMessage that the @since tag is wrong.
Again, use the quickfix to fix the problem.
So this gives us a nice picture about how versioning is maintained. Any new additions in the API, the bundle's version is incremented and the API is tagged with the right @since tag. So that the clients would know which version introduced the API and adjust their depenecies. Thats version management by API tooling.
For this NewMessageAction, we need to add a command Id, so we add it in the ICommandIds. API Tooling would ask you to add the @since tag, use quickfix and add it. Now it still shows an error.
This was the error I was mentioning in the beginning of the tutorial. Try deleting an existing field in that interface or change a method signature in a class or introduce a non-default constructor to a class that didn't have any constrcutors - all these changes could be easily overlooked if done manually, and have create binary incompatibilities. But API tooling will catch you and notify you about these problems.
Other @ tags
In addition to the @since tag, API tooling provides you the few other tags:
This is specified on an interface in the API. If an interface is used only to store some constant, or the implementation is always private and you don't expect the client to provide an implementation, you should use this tag
When you have a class, that should be extended only within your framework (either with public API classes/internal classes), then mark it with @noextend
Use this on your utility classes, so that your clients cannot create instances of it
Sometimes, it might be required that a method/field should be in a public API class/interface, but the clients should not call it (something like IProgressMonitor.internalWorked() method). In those cases, mark them with @noreference.
Used on methods that can be referred, but should not be overridden.
Lets move on to the last part - the API leaks. What is an API leak? When your public API classes/interfaces expose a non-API type, it would be an API leak. For example our NewMessage class (which is an API) needs the Application class (which is a non-API class). Its fine as long as it doesn't expose the Application class to the client:
But once it exposes it in the public methods, then the Application class is seen by the clients. Now this restricts our ability to modify the Application class in the next version (or even delete it). So API tooling would give you an error on this API leak:
In case you want to overrule the API tooling errors and go ahead with shipping your product (and potentially breaking your clients), API tooling allows you to filter out certain problems. In the previous example, lets add the CMD_NEW field to the ICommandIds and use the quick fix. These filters are stored in your <project>/.settings/.api_filters file. Thanks to the "API Problem Filters" page on the project's Property pages, you don't have to manually edit that file to modify the filters
Reviewing the changes
We are ready to ship our RCP Mail 1.1. Before that lets do a quick check on what are the API changes that we have made. To do that, select the rcp.mail project in the Package Explorer (won't work if you select in Project Explorer or any other view), right click ->Compare With->API Base line. This will open up a view called "API Tooling" which will show up all the changes in the API that has been made since the baseline is released:
If this tutorial isn't enough for you to get started, Ankur has created a CheatSheet for API Tooling. This is now available in Eclipse SDK itself. Click Help->Cheat Sheets and get started.
Post your comments in here.
|< Prev||Next >|