3. POINTS OF INTEREST
Multiple Ecore Wipe out
Make EMF a
model versions in dependency from
better OSGi
the same OSGi Java interfaces to
citizen
container implementation
Work inspired from Alex Blewit and Neil Bartlett following posts [1, 2] and bugs [3, 4]
(1) http://njbartlett.name/2011/02/07/emf-in-osgi.html
(2) http://alblue.bandlem.com/2010/11/using-emf-for-osgi-service-creation.html
(3) https://bugs.eclipse.org/bugs/show_bug.cgi?id=329209
(4) https://bugs.eclipse.org/bugs/show_bug.cgi?id=328227
5. USE CASE 1
ECORE MODEL V1 ECORE MODEL V2
Tool Vendor 1 Tool Vendor 2
6. WAIT, I CAN’T USE
TOOLS FROM THESE
TWO VENDORS AT
THE SAME TIME?
I don’t care if they are based on
some data model whose
different versions can not live
together.
HTTP://WWW.FLICKR.COM/PHOTOS/KALEXANDERSON/6237846841/
8. FIRST GUILTY:
EXTENSIONS
OSGi is modular and dynamic by nature.
Extensions are reducing some of these
advantages by forcing plug-in to be singleton.
EMF uses extensions to contribute generated and
dynamic EPackages.
9. FIRST SOLUTION
Mimic GeneratedPackageRegistryReader and
DynamicPackageRegistryReader during activation
of model plug-ins.
Advantages: simple and mostly backward
compatible.
Drawbacks: plug-in must be activated to
contribute its model and some boilerplate code
needs to be written.
10. SECOND SOLUTION
Use OSGi (declarative) services.
Advantages: simple and mostly backward
compatible. Once defined as a service, any
requiring class can be made a component
requiring this service (DI).
Drawbacks: needs a ServiceTracker to track
services that can come and go anytime
EVEN BETTER OSGI R4.3: CREATE A CAPABILITY FOR EPACKAGES
12. SECOND GUILTY:
REGISTRY KEYS
EPackage instances are identified by namespace
URI in the Registry.
Best practice (workaround?) today is to include
version into namespace URI.
It should be a tuple (URI, Version)
13. SOLUTION
Need a specific EPackage.Registry
implementation that handle versions
public interface VersionedRegistry extends EPackage.Registry {
EPackage getEPackage(String nsURI, String version);
EFactory getEFactory(String nsURI, String version);
}
Contributed through
package_registry_implementation extension point.
Version can be valued from a property of service
or from version of contributing bundle (or from
capability?)
14. USE CASE 2
« If the interfaces can be kept "clean", i.e.
without any references to EMF-generated
implementation classes or to EMF itself, then the
APIs can be used standalone, for example in a
memory constrained environment. In this scenario,
normal hand-coded implementation classes could
be used. »
Neil Bartlett
https://bugs.eclipse.org/bugs/show_bug.cgi?id=329209
18. aces
Interf
EObject EPackage EFactory
EMF
YOUR MODEL
19. aces
Interf
EObject EPackage EFactory
EMF
Foo BarPackage BarFactory
YOUR MODEL
20. aces
Interf
EObject EPackage EFactory
EMF
Foo BarPackage BarFactory
YOUR MODEL
Impl
EMF
YOUR MODEL
21. aces
Interf
EObject EPackage EFactory
EMF
Foo BarPackage BarFactory
YOUR MODEL
Impl
EObjectImpl EPackageImpl EFactoryImpl
EMF
YOUR MODEL
22. aces
Interf
EObject EPackage EFactory
EMF
Foo BarPackage BarFactory
YOUR MODEL
Impl
EObjectImpl EPackageImpl EFactoryImpl
EMF
FooImpl BarPackageImpl BarFactoryImpl
YOUR MODEL
23. aces
Interf
EObject EPackage EFactory
EMF
Foo BarPackage BarFactory
YOUR MODEL
Impl
EObjectImpl EPackageImpl EFactoryImpl
EMF
FooImpl BarPackageImpl BarFactoryImpl
YOUR MODEL
24. aces
Interf
EObject EPackage EFactory
EMF
Foo BarPackage BarFactory
YOUR MODEL
Impl
EObjectImpl EPackageImpl EFactoryImpl
EMF
FooImpl BarPackageImpl BarFactoryImpl
YOUR MODEL
25. aces
Interf
EObject EPackage EFactory
EMF
Foo BarPackage BarFactory
YOUR MODEL
Impl
EObjectImpl EPackageImpl EFactoryImpl
EMF
FooImpl BarPackageImpl BarFactoryImpl
YOUR MODEL
26. aces
Interf
EObject EPackage EFactory
EMF
Foo BarPackage BarFactory
YOUR MODEL
Impl
EObjectImpl EPackageImpl EFactoryImpl
EMF
FooImpl BarPackageImpl BarFactoryImpl
YOUR MODEL
27. BENEFITS
Make generation gap pattern very natural and
easy.
Change from plain EMF objects to CDO native
objects.
28. SOLUTION
EObjectImpl
FooImpl BarPackageImpl
Add a method to (Internal)EObject
abstract EPackage ePackage();
Can be done in an extending interface
implemented by only newly generated models
29. SOLUTION
EObjectImpl
FooImpl BarPackageImpl
Field in Field in
EPropertiesHolder XXXObjectImpl
Access to
EPackage.Registry.INSTANCE
In all cases, it requires to give its defining EPackage to the
EObject’s constructor, and then to modify XXXFactoryImpl
30. SOLUTION
Some adapter factories need to be modified too
(AdapterFactory for models)
Need to introduce a new interface extending
AdapterFactory
public interface ModelAdapterFactory<P extends EPackage, F extends EFactory>
extends AdapterFactory {
P getEPackage();
F getEFactory();
}
31. SOLUTION
public interface ModelAdapterFactory<P extends EPackage, F extends EFactory>
extends AdapterFactory {
P getEPackage();
F getEFactory();
}
XXXItemProviderAdapterFactory is also
implementing it
XXXItemProviders are taking this interface as
argument to their constructor instead of simple
AdapterFactory.
32. BIND IT ALL
This solution perfectly fits
with registration of
EPackages as OSGi
(declarative) services
33. USE CASE 3
« I want to use EMF models on another OSGi
runtime than Equinox »
34. ECLIPSE RICH CLIENT ECLIPSE
WORKBENCH PLATFORM HEADLESS
IDE RCP EQUINOX
STANDALONE ECLIPSE RICH GOOGLE WEB
AJAX PLATFORM TOOLKIT
JAVA RUNTIME RAP GWT
SUPPORTED PLATFORMS
RAP AND GWT SINCE EMF 2.6
35. What about other OSGi
runtimes?
When running in an OSGi container,
EMF explicitly requires the following
8 bundles:
org.eclipse.core.runtime
org.eclipse.equinox.common
org.eclipse.core.jobs
org.eclipse.equinox.registry
org.eclipse.equinox.preferences
org.eclipse.core.contenttype
org.eclipse.equinox.app
org.eclipse.osgi
HTTP://NJBARTLETT.NAME/2011/02/07/EMF-IN-OSGI.HTML
36. SOLUTION 1 & 2
(Repackage EMF bundles)
Big refactoring to separate
Eclipse/Equinox related bits
from OSGi related bits
Use import-package instead
or require-bundle
37. SOLUTION 3
There are some less radical changes that can be
done in a backward compatible fashion, but
Introduces even more graceful handling of target
running platform into the runtime
Ex: rewriting EMFPlugin.IS_ECLIPSE_RUNNING
in a similar way to
IS_RESOURCE_BUNDLE_AVAILABLE in the
term of a new EMFPlugin.IS_OSGI_RUNNING.
38. CONCLUSION
EMF is a great piece of engineering
OSGi is a great piece of engineering too
3MF is an experimentation to make EMF mimic /
use some of the best qualities of OSGi (modularity,
dynamicity)
With these, EMF would reach the infinity... and
beyond!
39. CONCLUSION
EMF is a great piece of engineering
OSGi is a great piece of engineering too
3MF is an experimentation to make EMF mimic /
use some of the best qualities of OSGi (modularity,
dynamicity)
With these, EMF would reach the infinity... and
beyond!
(c) Raoni Nery (raoninery@gmail.com)\nhttp://raoninery.cgsociety.org/gallery/853975/\nexperiment, available on my github, anchors @ the end\n
EMF is cool, it&#x2019;s a great piece of software, and \nfrom a software engineering point of view, it&#x2019;s really smart.\nroom for improvments? DO NOT TALK ABOUT BACKWARD COMPATIBILITY\n
some patterns in EMF are keeping it from being more modular and dynamic\n
Backward compatibility is a day-to-day issue\nSometimes, to reach the next big step, we may break it\nmajor concern\nbenefits outweigh the costs\n
one ecore model, multiple version, say from a standard consortium\nTwo tools vendors implement tools on 2 different versions of this model\nOne end user wants to use those two tools at the same time, in the same Eclipse instance\n
oh crap! he does not care, from its point of view it&#x2019;s implementation details\nif you are one of these tool vendor, you may loose a customer because of your underlying technology. You may be ready to loose a customer because of anything else than the technology used two or more layers deeper than you \n\n
Who are the guilty? First Eclipse extensions mechanism, now built upon OSGi (since 3.0)\n
Extensions force singleton and reduce dynamicity for good technical reasons, but it introduces some very crappy thing (think of restart after installing plug-in, &#xAB;Do you want to restart? Yes, Apply change, Cancel&#xBB; \nEMF use extension because it started in pre-OSGi eclipse, this was the way to do it. It has been kept since then.\nRemove generated_packages and dynamic_packages extensions\n
RegistryReader are classes that are responsible to read plugins&#x2019; extensions from Eclipse extension registry @ startup time of the ecore plugin and then fill the EPackage registry with proper values (with gracefull handling of class loading (and then activation) of contributed plugins).\n\n
declare that MyPackageImpl provides an EPackage service, it can be listened by ServiceTracker\nwhat to do when several MyPackageImpl provides EPackage with same nsURI\n
crap, it&#x2019;s a single strign\n
nsURI MUST identify the EPackage artifact the same as the FQN of a Java package is identifying it.\nVersion has to be handled separatly from the identity.\nThen, if we want to have a single place to get EPckages, the map&#x2019;keys must be a tuple\n
EPackage.Registry.getEPackage(String) could return the highest version for instance\ncontribution through xtension point is valid only if the declaring plugins is installed into the OSGi before Ecore plugin is started, otherwise, it will use its default implementation (EPackageRegistryImpl)\n
\n
\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
FooImpl refers to BarPackage.Literals static final fields by protected method eStaticClass()\nBarPackage.Literals refers to BarPackage.eINSTANCE\nBarPackage.eINSTANCE refers to BarPackageImpl by static init()\n\n
you can make your own implementation of interfaces, or an extending implementation of the generated one\nprovide your implementation as a service to the interface. Requiring bundles will either filter to have your implementation, or you can remove the generated component to have only yours...\nI have to be honest, I didnot have test it with CDO, but to me, CDOObject interface does not need to be exposed in the very first set of interfaces. The separtion of interface and implementation is necessary to make the CDO legacy mode useless\n
\n
Implementation of this method can be done at by three means\nWhy the package to get the EClass, could&#x2019;n we give the Eclass only ?\n&#xAB;give the package because of some advanced generation pattern with FeatureMap and extended_metadata..&#xBB;\n
\n
\n
we inject epackage into the Epckage.registry and Service Registry through services\nany depending plugin is able to ask from one or the other registry\nno more simple singleton (less easy for newcomers) but much more modularity\n\n
emf has a great runtime, and when you are used to create thing with it, you can&#x2019;t do without it\nwhat if you have to do something with emf and another osgi runtime\n
it runs on several platforms but, some of them are hardwired to the target (but their lack are handled gracefully)\n
\n
poor solution to repackage\n\n
optional requirements and even more conditionnals into the code.\n
- EMF has tons of qualities\n- But not so much modular and dynamic regarding the models it creates\n- spread its usage on several osgi runtime, be used in more and more environment and from more and more people.\nIt would ease also version management of ecore models.\n