Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Texo/Runtime Model

< Texo
Revision as of 07:13, 7 March 2010 by Mtaal.springsite.com (Talk | contribs) (Model-driven access to Pojo's)

Introduction

Runtime model access is very useful when trying to implement generic functions like export/import, security, archiving etc. Also when the model is explicitly used in the application then it can make sense to access model objects (entities) in a model-driven way.

To support a model-driven approach at runtime, Texo generates two extra java class files for each EPackage. These can be normally be found in the same package as the generated entities:

  • ModelPackage: provides access to the EPackage and its content (EClasses, EDataTypes, etc.)
  • ModelFactory: contains factory methods to create instances of an EClassifier and for String conversion. In addition this class provides access to the model wrappers.

Note the generation of the runtime model layer will be made optional. So if you don't need runtime model access then the ModelFactory and ModelPackage classes will not be generated.

Model Wrappers: the ModelObject

As noted in the previous section, the ModelFactory class contains so-called ModelWrappers. The model wrappers are the key to providing model-level access through a pojo, i.e. they wrap a pojo and give the pojo a 'model-face'.

To illustrate this with the EMF library example. For the EMF Library EClass, the following is generated:

  • a Library java class (a true pojo)
  • a LibraryModelObject which can be found inside the generated LibraryModelFactory class

The Library java class will have methods like getName, getBooks, etc. The LibraryModelObject provides the generic 'model-face', it has three methods:

  • eClass(): returning the Library EClass
  • eGet(EStructuralFeature): to get the value of an EStructuralFeature
  • eSet(EStructuralFeature, Object): to set the value of an EStructuralFeature

These three methods are also present in the other ModelObjects generated for the EClasses of the EPackage. The next section will show how these methods can be used for model access to a pojo.

The approach with generated ModelObject wrappers has been chosen because:

  • it performs much better than reflective access (about 100 times faster)
  • it does not require runtime class enhancements, i.e. no complex class loader configurations which can interfere with other frameworks.

The only 'price' is an extra class (the ModelFactory) which contains an inner-class for each EClass.

Model-driven access to Pojo's

The ModelObject (eClass, eGet, eSet) interface makes it possible to access generated pojo's at generic model level. Then how do you create or wrap a generated pojo into a ModelObject? This is where the org.eclipse.emf.texo.model.ModelResolver can be used. The ModelResolver provides global access to all registered/initialized ModelPackages. It also makes it easy to access pojo's in a 'model-driven' way. The ModelResolver.getModelObject(Object) is used for this.

Let's show an example. This example creates a pojo (Book), sets some values and then accesses this same pojo in a model-driven way:

final LibraryModelFactory factory = LibraryModelPackage.MODELFACTORY;
// create the pojo and set some values
final Book book = new Book();
book.setTitle(TITLE);
book.setCategory(BOOK_CATEGORY);
book.setPages(PAGES);
 
// now access this same pojo at model-level
final ModelObject<?> modelObject = ModelResolver.getInstance().getModelObject(book);
for (EStructuralFeature eFeature : modelObject.eClass().getEAllStructuralFeatures()) {
    System.err.println(eFeature.getName() + ": " + modelObject.eGet(eFeature)); //$NON-NLS-1$
}

The for loop walks through all the EStructuralFeatures of the EClass. The following is printed:

title: title
pages: 27
category: ScienceFiction
author: null

The example above created a Book instance and used it directly, so maybe that's not very illustrative. Let's show how model access can be used to create a generic method which can convert any list of objects to xml (as it is a simple example it ignores things like conversions etc. and only handle EAttributes).

  private String convertToXML(java.util.List<Object> objects) {
    final StringBuilder sb = new StringBuilder();
    // create the root tag
    sb.append("<Root>\n"); //$NON-NLS-1$
 
    // walk over the objects
    for (Object object : objects) {
      // wrap the object
      final ModelObject<?> modelObject = ModelResolver.getInstance().getModelObject(object);
      sb.append("<" + modelObject.eClass().getName() + ">\n"); //$NON-NLS-1$ //$NON-NLS-2$
 
      // iterate over the EAttributes
      for (EAttribute eAttribute : modelObject.eClass().getEAllAttributes()) {
        // create the XML
        sb.append("<" + eAttribute.getName() + ">"); //$NON-NLS-1$ //$NON-NLS-2$
        sb.append("" + modelObject.eGet(eAttribute)); //$NON-NLS-1$
        sb.append("</" + eAttribute.getName() + ">\n"); //$NON-NLS-1$ //$NON-NLS-2$
      }
      // and close the tag
      sb.append("</" + modelObject.eClass().getName() + ">\n"); //$NON-NLS-1$ //$NON-NLS-2$
    }
    sb.append("</Root>\n"); //$NON-NLS-1$
    return sb.toString();
  }

This snippet walks through the objects, wraps each of them in a ModelObject, gets the EClass and iterates over the EAttributes. The output when passing a list with a Library, Book and Writer will be something like this:

<Root>
<Library>
<name>library</name>
</Library>
<Writer>
<name>writer</name>
</Writer>
<Book>
<title>title</title>
<pages>27</pages>
<category>ScienceFiction</category>
</Book>
</Root>

Access to the ModelFactory and ModelPackage

There are several ways to get to the ModelFactory or ModelPackage instance. The first method is to use the generated statics:

final LibraryModelFactory modelFactory = LibraryModelPackage.MODELFACTORY;
final LibraryModelPackage modelPackage = LibraryModelPackage.INSTANCE;

The other method is to use the org.eclipse.emf.texo.model.ModelResolver. The ModelResolver roughly has the same meaning as the EMF EPackageRegistry. All initialized ModelPackage instances are present in the global ModelResolver instance (which can be retrieved using ModelResolver.getInstance()). The following code snippet for example returns the LibraryModelPackage:

ModelPackage modelPackage = ModelResolver.getInstance().getModelPackage(LibraryModelPackage.NS_URI);

Back to the top