Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX

By submitting your information, you agree that devx.com may send you DevX offers via email, phone and text message, as well as email offers about other products and services that DevX believes may be of interest to you. DevX will process your information in accordance with the Quinstreet Privacy Policy.


Discover the Eclipse Modeling Framework (EMF) and Its Dynamic Capabilities : Page 2

Given a model, EMF can generate Java source code that will allow you to create, query, update, serialize, deserialize, validate, and track changes to instances of your models. EMF provides an efficient reflective API and allows you to work with dynamic, non-generated, models.




Application Security Testing: An Integral Part of DevOps

Using Dynamic EMF Capabilities
In general, if you have models at development time, it is typically best to generate Java code because in this case your application will use less memory and provide faster access to data (using either the generated or the reflective API). While generating Java code serves a need for most applications, this might not always be the case. You might need to process data without requiring the availability of generated implementation classes. For example, you might not know at development time the model of the data you will be processing, making generated Java code a poor option.

Dynamic, i.e., non-generated, classes can be created at runtime in several ways. Let's start by creating a company model programmatically using the Ecore API. The company model describes a company that has a name and departments. Each department is identified by a number and has employees. Each employee has a name. The code below shows an Ecore metamodel that corresponds to this model.

EcoreFactory ecoreFactory = EcoreFactory.eINSTANCE; EcorePackage ecorePackage = EcorePackage.eINSTANCE; // create an Company class EClass companyClass = ecoreFactory.createEClass(); companyClass.setName("Company"); // create company name EAttribute companyName = ecoreFactory.createEAttribute(); companyName.setName("name"); companyName.setEType(ecorePackage.getEString()); companyClass.getEStructuralFeatures().add(companyName); //create an Employee class EClass employeeClass = ecoreFactory.createEClass(); employeeClass.setName("Employee"); //add a name attribute to an Employee class EAttribute employeeName = ecoreFactory.createEAttribute(); employeeName.setName("name"); employeeName.setEType(ecorePackage.getEString()); employeeClass.getEStructuralFeatures().add(employeeName); //create a Department class EClass departmentClass = ecoreFactory.createEClass(); departmentClass.setName("Department"); //add department identification number EAttribute departmentNumber = ecoreFactory.createEAttribute(); departmentNumber.setName("number"); departmentNumber.setEType(ecorePackage.getEInt()); departmentClass.getEStructuralFeatures().add(departmentNumber); //department class can contain reference to one or many employees EReference departmentEmployees = ecoreFactory.createEReference(); departmentEmployees.setName("employees"); departmentEmployees.setEType(employeeClass); // specify that it could be one or more employees departmentEmployees.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY); departmentEmployees.setContainment(true); departmentClass.getEStructuralFeatures().add(departmentEmployees); // company can contain reference to one or more departments EReference companyDepartments = ecoreFactory.createEReference(); companyDepartments.setName("department"); companyDepartments.setEType(departmentClass); companyDepartments.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY); companyDepartments.setContainment(true); companyClass.getEStructuralFeatures().add(companyDepartments); //create a package that represents company EPackage companyPackage = ecoreFactory.createEPackage(); companyPackage.setName("company"); companyPackage.setNsPrefix("company"); companyPackage.setNsURI("http:///com.example.company.ecore"); companyPackage.getEClassifiers().add(employeeClass); companyPackage.getEClassifiers().add(departmentClass); companyPackage.getEClassifiers().add(companyClass);

Using the reflective API you can create and initialize an instance of your model:

// get company factory EFactory companyFactory = companyPackage.getEFactoryInstance(); // using the factory create instance of company class and // set company name EObject company = companyFactory.create(companyClass); company.eSet(companyName, "MyCompany"); // create an instance of employee class EObject employee = companyFactory.create(employeeClass); //using reflective API initialize name of employee employee.eSet(employeeName, "John"); // create an instance of department class EObject department = companyFactory.create(departmentClass); department.eSet(departmentNumber, new Integer(123)); //add "John" to department ((List)department.eGet(departmentEmployees)).add(employee); // add the department to the company ((List)company.eGet(companyDepartments)).add(department);

Serializing and Deserializing Data
To serialize your model instances, you need to put a root object of your instance model into a resource. The EMF org.eclipse.emf.ecore.resource.Resource interface represents a physical storage location (such as file or URL) and provides methods to serialize and load data. Each resource is stored in a ResourceSet, which represents a collection of resources that have been created and loaded together, allowing for references among them. In particular, a ResourceSet keeps track of which resources have been loaded and makes sure that no resource in a ResourceSet is loaded twice.

Because EMF is capable of dealing with multiple model sources, e.g., XML Schema, it is also important to specify which resource implementation should be used for (de)serializing your data. Normally, when you invoke the ResourceSet.createResource(URI) method, it queries the Resource.Factory.Registry to look up a factory that is registered for that URI and uses it to create an appropriate resource implementation. Therefore, before you (de)serialize your data ensure that you register the appropriate resource factory implementation. EMF provides several Resource.Factory implementations:

  • For XML data use org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl.
  • For XMI data use org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl.
  • For Ecore models use org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl.
With these EMF resources in your toolbox, you can use this code to serialize your data:

// create resource set and resource ResourceSet resourceSet = new ResourceSetImpl(); // Register XML resource factory resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl()); Resource resource = resourceSet.createResource(URI.createFileURI("c:/temp/company.xmi")); // add the root object to the resource resource.getContents().add(company); // serialize resource – you can specify also serialization // options which defined on org.eclipse.emf.ecore.xmi.XMIResource resource.save(null);

The serialized form of the company.xmi is:

<?xml version="1.0" encoding="ASCII"?> <company:Company xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:company="http:///com.example.company.ecore" name="MyCompany"> <department number="123"> <employees name="John"/> </department> </company:Company>

During deserialization, the namespace URIs of XML data are used to locate the required Ecore packages (which describe the model for your instance documents). Therefore, before you attempt to load any model, ensure that you register the namespace URI for each Ecore package your documents will be using:

// register package in local resource registry resourceSet.getPackageRegistry().put(companyPackage.getNsURI(), companyPackage); // load resource resource.load(null);

It is also important to notice the difference between local and global package (EPackage.Registry.INSTANCE) and resource factory (Resource.Factory.Registry.INSTANCE) registries. The global registry is static and therefore any application during lifetime of JVM can access the global registry and possibly overwrite it. To ensure that your registrations do not overwrite global registrations and vice versa, it is typically better to use local resource set registry.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.
Thanks for your registration, follow us on our social networks to keep up-to-date