I’ve been working for quite a while on finding solutions to the problems we are having in PDE as soon as we need to add support for new OSGi headers, to create new editors for cheatsheet files, p2 categories, etc.
Declarative Services tooling is a good illustration of all these problems. As part of the Google Summer of Code 2008, Rafael Oliveira worked on the creation of some cool tooling to help people wanting to use OSGi Declarative Services. This tooling is great, and available in Eclipse Galileo as many of you may know but, unfortunately, it introduces a lot of boilerplate code (Java model of what a DS component is, Java model of what the textual representation of a DS component is, JFace label and content providers, etc.)
Indeed, since day 1 of PDE, despite the fact there is a sort of generic framework behind PDE (undo/redo support for operations done both programmatically or through the UI/text editors, compiler to check models consistency and create markers, outline, etc.), it is, and always has been kind of a pain to “instantiate” this framework for each new usecase.
People familiar with EMF, and modeling technologies in general, are probably thinking right now that the framework behind PDE should probably model-based, and of course they are right! That’s exactly the purpose of the ongoing “model my PDE” work being done in the PDE incubator. In this post, I will quickly explain what is currently available in HEAD of the project, further explanations may come in later posts (by the way, feel free to ask precisions on specific topics!).
Generic Forms editor
The org.eclipse.pde.emfforms bundle proposes some abstractions of what is generally needed to create a Forms editor for any kind of EObject. Thanks to EMF.Edit and Databinding framework, it makes it really simple –sometimes you won’t even need to write a single line of code– to create your UI and bind it to the model, display the errors on your model, show an outline, and stuff.
Since the project is still incubating, there is of course no clear API of this bundle at the moment, but if you need to quickly hack a model editor, you should probably have a look at it, and at the “exemplary” implementation which has been done for the “next-gen” DS Component editor.
A non-exhaustive list of the feature provided by this framework (coupled to the features of EMF/EMF.Edit/Databinding and Forms) would be:
- full undo/redo support
- full copy/paste support (both locally to the editor, and from an editor instance to another),
- automatic refresh of the editor if the model is changed on disk,
- model live-validation; displaying error(s) in front of the “guilty” controls, in the forms header, and on the nodes of the elements displayed in Master/Details blocks,
- full drag&drop support in Master/Details blocks’ viewers,
- generic Outline view,
- generic Properties view,
- … 😎
Extensibility
There are many OSGi vendors who work on their own implementation of the standard, and they obviously need tooling for these specificities. In an ideal world, they should be able to extend vanilla PDE instead of reinventing the wheel. We, at PDE, expose some APIs for people to do that (SpringSource Tool Suite proposes tooling for SpringDM, and it is built on top of PDE), but there are many things that are still internal. Our models, our editors, our compilers, are not really designed to be extensible. A model-based approach is the right solution to this lack of extensibility:
- An EMF model is very easily extensible. In order to extend the “Declarative Services” model, create you own, let’s say scr-equinox.ecore, referencing just take the scr.core model. You can now have an EquinoxComponent, extending the standard Component, and bringing some nice Equinox-specific additions. When you will generate the corresponding Java code, you’ll end up with a model which will be 100% editable in the “legacy” Component editor.
- It is very easy to add new validation rules, either enhancing the EValidator generated by EMF, or, way better, using the EMF Validation framework which allows to contribute new rules in a declarative fashion. Not only it allows anybody to “plug” additional rules on top of an existing model, but it also avoids to clutter the model API with dependencies needed only for validation purposes. Indeed, to perform a meaningful validation of a Declarative Services component, you have to query JDT and PDE to check method signatures, visibility of referenced services, etc. For people interested in how an EMF Validation constraint extension, here is an example taken from the incubator code:
<extension point="org.eclipse.emf.validation.constraintProviders"> <category id="org.eclipse.pde.ds.builder.validation" mandatory="true" name="Declarative Services Validation"> </category> <constraintProvider cache="true"> <package namespaceUri="http://www.osgi.org/xmlns/scr/v1.1.0"> </package> <constraints categories="org.eclipse.pde.ds.builder.validation"> <constraint class="o.[...].ComponentMethodsAreValidAndAccessible" id="o.[...].constraintComponentMethodsAreValidAndAccessible" lang="Java" mode="Live" name="Components methods validation" severity="ERROR" statusCode="2"> <message> Method {0}: {1} </message> <target class="Component"> <event name="Set"> <feature name="activate"> </feature> </event> <!-- ... --> </target> </constraint> </constraints> </constraintProvider> </extension>
- EMF allows to version models, and has solutions to ensure compatibility between an N-1 and an N model instance. This way, we could probably be a bit less shy when it comes to updating old APIs. Tooling would be written to handle models in version N, but APIs for N-1, N-2, etc. would still be available, and mappers to convert from N-X to N would be too.
Model-aware builder
In order to report errors to the end-user, the editor performs live validation (thus the nice Forms decorators in the screencast below), but there is also a specific builder (once again, designed to be extensible) listening for model changes, and calling EMF Validation behind the scene to check the consistency and create resource markers for every encountered problem.
Screencast
A screencast being IMHO worth a thousand words, here is a live demo of the DS Editor:
If you want to play with this “experimental” tool, you can install in your SDK the experimental feature served by build.eclipse.org and corresponding to the result of continuous integration of the HEAD of the project, thanks to Hudson and Athena!
I guess the next important step is now to find an elegant way to propose a Source tab which, as you may have noticed, is almost the only feature being present in the Galileo editor and not in this prototype. Another important step will also be to write the Xtext grammar of an OSGi Manifest, and leverage this “EMF-Forms” framework to propose a cool and extensible editor on top of a Manifest 🙂
8 replies on “Model my PDE!”
I like the direction this experiment is going in 🙂
I can only applaud you for this work – PDE would become the first publicly know Eclipse-Project use EMF and EMF-Databinding! It’s nice to see that people use the code we produce.
great idea !
BTW: a Xtext grammar for OSGI Manifests would be helpful in other MDSD projects, too
ekke
Hi Benjamin — thanks for this! I’ve checked out your code from pde-incubator.
I am trying to also connect the EMF Validation framework to be used within the databinding framework. However, I’m working on making widgets that will support databinding for my EMF model objects.
While looking at your code I don’t see any custom ValidationStatusProviders. All of the calls to DataBindingService.bindValue calls either have null, null for their targetToModel / modelToTarget or they lightly extend the generic EMFUpdateValueStrategy (overriding the convert method)
I also don’t see where ValidatingService35 is called.
Can you please clarify exactly where you are linking the databinding validation with the EMF validation?
thanks much
Tamar
AHA! as soon as I posted I realized that you are binding it in the validatingEContentAdapter. I’ll keep poking around but if you feel like clarifying anything that would be lovely.
thanks!
Tamar
This is useful to me. Thanks.
I’m new to EMF, PDE and databinding. I’m learning much from this project’s source code.
There is one struggle I have finally overcome. I hope I’m not blowing etiquette by sharing here. Is there a better forum?
I’m probably using the wrong terms as in this description here. I’m describing in terms of the ds implementation as common reference for us to communicate. In reality, I’m working on a different model editor.
ProperiesDetailsPart.bind(DataBindingContext bindingContext) is using return from EMFDetailsPart.getCurrentSelection(). This led me to believe that bind was called after every selection change. In fact, this is not the case. DetailsPart.showPage calls the pages’ createContents method only once (maybe?) per editor instance, and always before it calls the page’s selectionChanged method. So, getCurrentSelection is returns null (or the old selection) when the part’s bind method is called.
This became important to me because some of the features my user would select are not fully built. Some nested features do not exist when the ‘master’ feature is selected. The behavior when this occurs is simple: the user can enter text into a text box in the details side of the page, but the databinding is not effective. The databinding finds the nested feature non-existing and doesn’t add the nested feature or otherwise change the model.
I don’t know if my workaround is the best solution, but I overrode selectionChanged to disable the text fields corresponding to features that do not exist. I think my users will prefer to create those fields explicitly, instead of the editor creating them.
Thanks for your effort.
John
[…] improving on releng base builder (Athena), some wrote their own scripts, other started modeling PDE like this project in PDE incubator, and some wrote better/easier to use script generators like […]
Hi,
Very useful article. Still, I’ve tried to access the sources you’ve mentioned in the “experimental feature” (https://build.eclipse.org/hudson/job/cbi-pde.ds.modeling.incubator-0.1.0/lastSuccessfulBuild/artifact/build/repository/) but it doesn’t work.
Could you make this available again?
Thanks
Mike