# Gecko EMF Addons This projects contains two separate features. * EMF Compare Support * QVT Model-2-Model Transformation Support To use that with the Eclipse Bundles from the 2019-03 release train, some errors will occur. ## Patches and Dependency Issues There are several ways to run both projects without Equinox. ### EMF Common org.eclipse.emf.common `java.lang.NoClassDefFoundError: Could not initialize class org.eclipse.emf.common.util.Diagnostic` A **NoClassDefFound** caused from an exception within the *org.eclipse.emf.util.DelegatingResourceLocator* in EMF Common when trying to initialize a **Diagnostic**. For that line 205 must be changed from *baseURL = new URL(uri.toString() + "/");* into *baseURL = new URL(uri.toString());* Exporting the artifact is enough to solve the problem. A Eclipse Bugzilla bugreport will follow. But it will work with the latest version in the launch current setup, using the patched version of *org.eclipse.core.runtime* (*de.dim.eclipse.core.runtime*)from the gecko project. ### OCL org.eclipse.ocl The occurs an error initializing the *org.eclipse.ocl.internal.OCLPlugin*, because of setting a *static private Implementation plugin* in line 48 from the internal static class constructor of *Implementation*, that act as bundle activator. Apache Felix causes an exception, when trying to initialize the *Implementation* instance using reflections. Changing line 48 from *static private Implementation plugin* to e.g. *static public Implementation plugin* solves the problem. So there is a patched version of *org.eclipse.ocl* used as well. In addition to that the bundle Manifest was modified in a way not to use a require bundle declaration for *org.eclipse.core.runtime* ``` Import-Package: com.ibm.icu.lang;version="4.0.0";resolution:=optional, com.ibm.icu.text;version="4.0.0";resolution:=optional, org.eclipse.core.runtime, org.eclipse.core.runtime.preferences;resolution:=optional, org.eclipse.osgi.util, org.osgi.framework Require-Bundle: org.eclipse.emf.ecore;bundle-version="[2.7.0,3.0.0)";visibility:=reexport, org.eclipse.emf.ecore.xmi;bundle-version="[2.7.0,3.0.0)";visibility:=reexport, lpg.runtime.java;bundle-version="[2.0.17,3.0.0)";visibility:=reexport, org.eclipse.ocl.common;bundle-version="[1.0.0,2.0.0)";visibility:=reexport Bundle-Activator: org.eclipse.ocl.internal.OCLPlugin$Implementation ``` Notice that the import for *org.eclipse.core.runtime.preferences* is marked as optional to avoid unused dependencies to the bundle *org.eclipse.equinox.preferences* ### QVT org.eclipse.m2m.qvt.oml and org.eclipse.m2m.qvt.oml.ecore.util In the current 19.03 release there are new dependencies introduced for the tracing. This belongs to the both project project. Therefore the manifest removed the Require-Bundle declaration to *org.eclipse.core.resources*. Instead we use the optional package import to *org.eclipse.core.resources*. **org.eclipse.m2m.qvt.oml** ``` Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)", org.eclipse.emf.ecore;bundle-version="[2.8.0,3.0.0)";visibility:=reexport, org.eclipse.emf.ecore.xmi;bundle-version="[2.5.0,3.0.0)", org.eclipse.emf.ecore.change;bundle-version="[2.4.0,3.0.0)", org.eclipse.m2m.qvt.oml.common;bundle-version="[3.1.0,4.0.0)";visibility:=reexport, org.eclipse.m2m.qvt.oml.cst.parser;bundle-version="[3.0.0,4.0.0)";visibility:=reexport, org.eclipse.ocl.ecore;bundle-version="[3.1.0,4.0.0)";visibility:=reexport, org.eclipse.m2m.qvt.oml.ecore.imperativeocl;bundle-version="[3.0.0,4.0.0)";visibility:=reexport, org.eclipse.ocl;visibility:=reexport ... Import-Package: org.eclipse.core.resources;resolution:=optional ``` **org.eclipse.m2m.qvt.oml.ecore.util** ``` Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)", org.eclipse.emf.ecore.xmi;bundle-version="[2.5.0,3.0.0)", org.eclipse.ocl.ecore;bundle-version="[3.0.0,4.0.0)" ... Import-Package: org.eclipse.core.resources;resolution:=optional ``` So we use patched versions, for these two bundles as well. ## EMF Compare This implementation uses *org.eclipse.emf.compare* as implementation. All that functionality is wrapped around an API. The service interface is *org.gecko.emf.osgi.compare.api.ModelObjectMerger* that contains convenient methods to compare and/or merge resources. There are currently two ways to use EMF Compare as an OSGi service. * **EMFModelObjectMerger** * **ConfigurableModelObjectMerger** ### EMFModelObjectMerger This is the default implementation, that uses all default settings of EMF Compare. A default *IEqualityHelperFactory* is registered as well as a *IComparisonFactory*. Both have the service property **type=default** and are injected into the *EMFModelObjectMerger*. In addition to that there is a interface *org.gecko.emf.osgi.compare.api.ModelDiffVisitor* that can be used as visitor for the *ModelObjectMerger* service. An implementation can be registered as service. Theses services use then the EMFModelObjectMerger as whiteboard. **It is necessary to register these visitors with a 'type=default' service property** Otherwise the visitors are not accepted from the *EMFModelObjectMerger* ## EMF QVT Model Transformation To use QVT model transformations there are two ways. * **Model Transformation Factory** * **Configurable Model Transformator** The QVT implementation is based upon https://projects.eclipse.org/projects/modeling.mmt.qvt-oml ### Model Transformation Factory A simple way is just to consume the org.gecko.qvt.osgi.api.ModelTransformationFactory service. For that the bundle org.gecko.qvt.osgi.component contains the implementation. This factory can register your QVT template URI and returns a ModelTransformator instance. With that the object instance can be mapped. Create an template URI like this: ```java @Reference ModelTransformationFactory mtf; ResourceSet resourceSet = ...; Bundle b = context.getBundle(); URL resource = context.getBundle().getResource("MyTemplate.qvto"); java.net.URI uri = resource.toURI(); org.eclipse.emf.common.util.URI mapping = URI.createHierarchicalURI(uri.getScheme(), uri.getAuthority(), null, uri.getPath().split("/"), null, null); ModelTransformator transformator = mtf.createModelTransformator(resourceSet, mapping); EObject result = transformator.startTransformation(p1); ``` ### Configurable Model Transformator It is also possible to create a ModelTransformator by configuration. FOr that either the configurationAdmin or the Configurator can be used. There is a facotry that creates the instances. The Factory-PID is *ConfigurableTransformationService*. You can create a configuration like this: ```java Configuration configuration = configAdmin.getFactoryConfiguration(ModelTransformationConstants.CONFIGURABLE_TRANSFORMATOR_FACTORY_ID, "test-trafo", "?"); Dictionary properties = new Hashtable(); properties.put(ModelTransformationConstants.TRANSFORMATOR_NAME, "test-trafo");//qvt.transformatorName String path = context.getBundle().getSymbolicName(); path += ":" + context.getBundle().getVersion().toString(); path += "/MyTemplate.qvto"; properties.put(ModelTransformationConstants.TEMPLATE_PATH, path);//qvt.templatePath configuration.update(properties); Filter filter = FrameworkUtil.createFilter("(" + ModelTransformationConstants.TRANSFORMATOR_NAME + "=test-trafo)"); ModelTransformator transformator = getService(filter); EObject result = transformator.startTransformation(p1); ``` This configuration property *qvt.templatePath* uses the following syntax: :/.qvto. A Json file for the configurator can look like this: ```json { ":configurator:resource-version": 1, "ConfigurableTransformationService~test-trafo": { "qvt.templatePath": "org.test.mybundle:1.0.0/transforms/MyTemplate.qvto", "qvt.transformatorName": "test-trafo" } } ``` Please note, that it is necessary, to already have all needed model registered. For that it is possible to define a filter *qvt.model.target*, that defines the requirements for the models like this: ```json { ":configurator:resource-version": 1, "ConfigurableTransformationService~test-trafo": { "qvt.templatePath": "org.test.mybundle:1.0.0/transforms/MyTemplate.qvto", "qvt.transformatorName": "test-trafo", "qvt.model.target":"(&(emf.model.name=modelA)(emf.model.name=modelB)" } } ``` This example defines the restriction that at least modelA and modelB have to be registered in Gecko EMF, to handle the transformation. Without this target, it may happen that the mapping works, because luckily the models are registered before the configuration is initialized. But this case may change, because the start ordering cannot be ensured. So it is strongly recommended to use this target restriction. The mapping may fail with an error like this: ``` Caused by: java.lang.IllegalStateException: Error executing transformation because of diagnostic errors: Diagnostic ERROR source=org.eclipse.m2m.qvt.oml.execution code=130: Compilation errors found in unit 'bundle:////.qvto' ... ``` ### Blackbox Support You can register a blackbox as a service by just providing the service property *qvt.blackbox=true*. Additionally there are two properties *qvt.blackbox.moduleName* and *qvt.blackbox.unitQualifiedName* to customize the import names of the blackbox in an QVT template. The typical Eclipse QVT Blackbox can be annotated like this: ```java @Component(property={"qvt.blackbox=true"}) @Module(packageURIs={"http://dim.de/test"}) public class BlackboxTest { @Operation(contextual=true) public static Address getCopyAddress(Address self) { Address copy = EcoreUtil.copy(self); copy.setCity(self.getCity() + "Copy"); copy.setStreet(self.getStreet() + "Copy"); return copy; } } ```