A Usage scenario
Create an EMF project and an ecore model, say a Bees.ecore meta-model containing a bees package, with classes Hive and Bee with a containment relationship. You can access the bees package with an xmiLoadModelElement :
js> bees = loadModelElement( 'platform:/resource/MyProject/model/Bees.ecore' );
(EPackage) Bees

If some Java code has been generated for Bees.ecore and this code is installed as a plugin in Eclipse, you can also use getModelDef with the declared URI of the metamodel.
js> bees = getModelDef( 'http://metamodel/bee' );
(EPackage) bees

You can create an instance model this way :
js> hive = bees.$Hive.create();
(Hive)
js>
bee1 = bees.$Bee.create();
(Bee)
js> bee2 = bees.$Bee.create();
(Bee)
js> hive.bees.add( bee1 );
true
js> hive.bees.add( bee2 );
true

You can save the instance model this way :
js> saveModelElement( 'platform:/resource/MyProject/model/hive1.xmi', hive );

However, if you want to load back a hive from hive.xmi, you need to have generated code and installed it as a plugin inside Eclipse.
js> hive = loadModelElement( 'platform:/resource/MyProject/model/hive1.xmi' );
(Hive)


Commands specific to EMFScript
listModelDef( )
List all registered EMF packages. Such a list is useful to use the getModelDef command.

Example :
js> listModelDef();
http://www.eclipse.org/emf/2004/Ecore2Ecore
http://www.eclipse.org/emf/2002/GenModel
http://www.eclipse.org/gmf/2005/ToolDefinition
http://www.eclipse.org/uml2/1.1.0/GenModel
http://www.eclipse.org/gmf/2005/GenModel
http://www.eclipse.org/emf/2003/XMLType
http://www.eclipse.org/uml2/2.0.0/UML
http://www.eclipse.org/emf/2003/Change
http://www.eclipse.org/xsd/2002/XSD
http://www.w3.org/XML/1998/namespace
http://www.eclipse.org/emf/2002/Tree
http://www.eclipse.org/gmf/2005/GraphicalDefinition
http://www.eclipse.org/emf/2002/Mapping
http://www.eclipse.org/emf/2005/Ecore2XML
http://www.eclipse.org/emf/2002/Ecore
http://www.eclipse.org/OCL2/1.0.0/ocl/query
http://www.eclipse.org/gmf/2005/mappings
http://www.eclipse.org/OCL2/1.0.0/ocl/expressions

getModelDef( packageURI ) : EPackage
Import a model package from a bundle installed in the Eclipse environment.
• packageURI is the URI of the model package to load. This is generally one the string returned by listModelDef.
• The result is the package containing the model or null if the package was not found.

Examples :

js>
ecore = getModelDef( 'http://www.eclipse.org/emf/2002/Ecore' );
(EPackage) ecore
js> uml2 = getModelDef( 'http://www.eclipse.org/uml2/2.0.0/UML);
(EPackage) uml

registerModelDef( ePackage )
register a model package (model definition) in the Eclipse environment.
• ePackage is the package to register

js> registerModelDef( uml2 );
http://www.eclipse.org/uml2/2.0.0/UML


loadModelElement( strResName ) : EObject
Load a model element from its persisted XMI or XML representation. Such a model element uses dynamic EMF.
strResName is a URI for an XMI resource. Any kind of URIs can be used, included Eclipse platform URIs such as : 'platform:/plugin/org.eclipse.emf.ecore/model/Ecore.ecore' or 'platform:/resource/eu.telecomlille1.MyProject/model/MyModel.ecore'
• The result is the model element.
An exception stack trace appears if the resource was not found, or was not a valid XMI/XML resource. An exception stack trace also appears if attempt to load an instance model for which no meta-model code was found.

Examples :
js> eom = loadModelElement( 'platform:/resource/eu.telecomlille1.emf.eom/model/eom.ecore' );
(EPackage) eom

saveModelElement( strResName, modelElement )
Save a model element to an XMI persisted representation.
strResName is a URI for an XMI resource. Any kind of URIs can be used, included Eclipse platform URIs such as : 'platform:/resource/eu.telecomlille1.emf.eom/model/prj.xmi'
modelElement is the model element to save

Examples :

js> saveModelElement( 'platform:/resource/eu.telecomlille1.emf.eom/model/prj.xmi', prj );
MyProject

How to script a model ?

Navigation in a model

The knowledge of the meta-model is all you need to navigate inside a model. For instance, if you want to navigate inside a Bees.ecore meta-model, you must know about its meta-model Ecore.ecore. For instance, if you want to display the name of the bees package, you must know that EPackage inherits from ENamedElement which has a name attribute. If you want to access the factory associated with the bees package, you must know that EPackage defines a eFactoryInstance reference to EFactory.

js> bees =loadModelElement( 'platform:/resource/MyProject/model/Bees.ecore' );
(EPackage) Bees

js>
bees.name;
bees

js>
bees.eFactoryInstance;
(EFactory)

The JavaScript syntax allows the alternative following syntax which is especially useful when the attribute or reference name is a computed string.
js> bees['name'];
bees
js>
bees['eFactoryInstance'];
(EFactory)

Multiple reference
Multivalued references are seen as some kind of JavaScript arrays called EList. For instance, Ecore defines the eClassifiers reference between EPackage and EClassifier.

js>
bees.eClassifiers;
(EList)
(EClass) Hive
(EClass) Bees

js>
bees.eClassifiers[0];
(EClass) Hive

Remind that, in JavaScript, the index of a for loop is not an element of a set but the index of this element :
js> for (i in bees.eClassifiers) print(i);
0
1
js> for (i in bees.eClassifiers) {
print(bees.eClassifiers[i]);
}
(EClass) Hive
(EClass) Bees


An EList also supports OCL-like operators such as select. Let's first declare a function which tells if an EClassifier is an EClass.
js> function isEClass(clsf){
return clsf instanceof ecore.$EClass; // see below 'The $ facility'
}

You can use this function as an argument for the EList's select operator :
js> bees.eClassifiers.select(isEClass);
(EList)
(EClass) Hive
(EClass) Bee


Current available operation on EList are:
any(function) : returns any element from the input Collection matching the filter condition.
js> elt = eList.any( function(elt) { return elt.value >= 0; } );

collect(function) : builds an output collection by applying a filter on each element from the input collection. The returned
collection comprises the filter returned objects.

js> list = eList.collect( function(elt) { return elt.name;} );

reject(function) : builds an output collection from the input collection elements NOT matching the filter condition.
js> list = eList.reject( function(elt) { return elt.value < 0;} );

exists(function) : returns true if at least one element from the input collection matches the filter condition.
js> binit = eList.exists(function (elt) { return elt.name == 'init'; } );

forAll(function) : returns true if all the elements from the input collection match the filter condition.
js> bAll = eList.forAll( function(elt) { return elt.name != '';} );
apply(function) : execute the procedure argument to every elements from the input collection.
js> eList.apply( function(elt) { print(elt.name); } );
includesAll(list) : return true if all the elements from the argument collection are included in this collection.
js> bAll = eList.includesAll( otherList);
excludesAll(list) : return true if all the elements from the argument collection are excluded from this collection.
js> bAll = eList.excludesAll( otherList);
count(function) : returns the number of elements matching the filter condition.
js> iCount = eList.count( function(elt) { return elt.name=='init';} );
one(function) : returns true if the number of elements matching the filter condition is exactly 1.
js> bOne = eList.one(function(elt) { return elt.name == 'init'; } );
isUnique(value, function) : returns true if the number of elements matching the value is exactly 1.
js> bInit = eList.isUnique( 'init', function (elt) { return elt.name; } );
sum() : returns the sum of this collection values that must be numeric.
js> result = eList.sum();
iterate(resultValue, function) : The OCL-like 'iterate' function implementation. The iterate function has 2 parameters : an initial 'result' value and a 'filter' function. The filter function itself has 2 parameters : a result and a list 'element'. The filter is applied to each list element, it returns a new result computed from its 'result' and 'element' parameters. The filter is applied to the first element with the initial result. The result returned by a filter application becomes the result parameter for application to the next element. The iterate function returns the final 'result' value.
js> result = eList.iterate('', function(result, e) { return result + e;} );

The $ facility
The $ facility provides an easy designation mechanism for sub-elements. For instance, the eClassifier reference and its opposite reference ePackage define an association between EClassifier and EPackage. Because this association is a containment relation, a classifier (i.e. Bee) is a sub-element of a package (i.e. bees) and you can navigate from bees to Bee by specifying bees.$Bee.

js>
bees.$Bee;
(EClass) Bee

In fact, this facility is restricted to named sub-elements. For instance, eClassifiers is a containment reference to an EClassifier and EClassifier inherits from ENamedElement.

Notice that the name of the containment reference (eClassifiers) does'nt appear in the $ expression (bees.$Bee) : any containment reference is involved in this facility. Also notice that $Bee can be a computed string :
js> str='Bee';
js> bees['$'+str];
(EClass) Bee

The create facility
The create facility abbreviates the following creation script :
js> myEClass = ecore.eFactoryInstance.create( ecore.$EClass );(EClass) null
to :
js> myEClass = ecore.$EClass.create();(EClass) null

Invoking operations

Models described with Ecore define classes that may have operations. If some Java code has been generated for this meta-model, these operations can be invoked from JavaScript.

js>
bees = getModelDef( 'http://metamodel/bee' );
(EPackage) bees

js>
bee1 = bees.$Bee.create(); // see below 'The create facility'
(Bee)

js>
bee1.fly();
Buzz...

Notice that you must have imported the model with importModelDef. An xmiLoadModel is not appropriate in this case.

Providing operations behavior
If no code was generated for the Bees model, you may want to prototype some operations behavior thanks to the _body notation and a JavaScript function :
js> bees =loadModelElement( 'platform:/resource/MyProject/model/Bees.ecore' );
(EPackage) bees
js> bee1 = bees.$Bee.create();
(Bee)
js> bees.$Bee.$fly._body = function() { print( 'Buzz, Buzz...' ); }
function () {
print("Buzz, Buzz...");
}
js> bee2 = bees.$Bee.create();
(Bee)
js> bee1.fly();
Buzz, Buzz...
js> bee2.fly();
Buzz, Buzz...
Notice that a bee can have been created previously to the fly operation body definition.

Providing operations behavior through the 'emfscript/body' annotation

If you consider that the operation behavior should be part of the model, you can want to provide it through an annotation. EMFScript defines the http://www.telecom-lille1.eu/2006/emfscript annotation source. An annotation detail, key of which is body allows a JavaScript function as a value. So, you should annotate an eOperation this way :
js> eAnn = ecore.$EAnnotation.create();
(EAnnotation)
js> bees.$Bee.$fly.eAnnotations.add(eAnn);
true
js> eAnn.source = 'http://www.telecom-lille1.eu/2006/emfscript';
http://www.telecom-lille1.eu/2006/emfscript
js> entry = ecore.$EStringToStringMapEntry.create();
(EStringToStringMapEntry)
js> eAnn.details.add( entry );
true
js> entry.key='body';
body
js> entry.value= "print( 'Buzz, Buzz...' );";
print( 'Buzz, Buzz...' );

Notice that the value is a string, not a function. Also notice that you must not provide the function () {...} wrapper for the body annotation code.
Then you can invoke the operation as usual :
js> bee1.fly();
Buzz, Buzz...

After the first execution, the function is set as a _body property of the EOperation. If the eOperation has parameters, their name will appear in the function parameters list.
js> bees.$Bee.$fly._body;

function () {
print( 'Buzz, Buzz...' );
}


You can also mix generated Java code and EMFScript/body annotations. By default, Java code generated for an operation is just a throw new UnsupportedOperationException(); instruction :
/**
*
*
* @generated
*/
public void fly() {
// TODO: implement this method
// Ensure that you remove @generated or mark it @generated NOT
throw new UnsupportedOperationException();
}

In this case, if a body annotation exists, it is executed. No modification is needed to generated code.

Invoking EMFScript evaluation from generated Java code

The last possibility is to modify Java code generation so that the evaluation of EMFScript is invoked :
/**
*
*
* @generated
*/
public void fly() {
String strBody = "function() { print( 'Buzz, Buzz...' ); }";
Context cx = Context.getCurrentContext();
Scriptable thisObj = (Scriptable)this;
Scriptable global = ScriptRuntime.getGlobal(cx);
Callable callable = cx.compileFunction( global, strBody, "", 1, null );
callable.call(cx, global, thisObj, new Object[0] );
}

Ecore to JavaScript mappings
constructor
The JavaScript constructor clause provides the object used to build an object. So :
js> tab = [];
js> tab.constructor
function Array() { [native code for Array.Array, arity=1] }

Applied to an ecore object, constructor provides the same information as the eClass() operation :

js>
ecore.constructor
(EClass) EPackage


instanceof

In JavaScript, instanceof telles if an object was built from another or not :

js>
tab = [];
js>
tab.instanceof Arraytrue
Applied to an ecore object, instanceof tells if it is an instance of its meta-object or not :
js> ecore instanceof ecore.$EPackagetrue
Inheritance links are taken into account, for instance, the result takes into consideration the fact that EPackage inherits from ENamedElement :
js> ecore instanceof ecore.$ENamedElementtrue


Model decoration

EMFShell includes a decoration mechanism for model elements based on JavaScript prototypes.

For instance, ecore can be decorated with a function which displays an ENamedElement's name attribute. To do this, an affName() function is attached to the ecore.$ENamedElement prototype :

js>
ecore.$ENamedElement.prototype.affName = function() {

print( this.name );
}
function () {
print(this.name);
}

Every ENamedElement will benefit from the affName() function. So, since the ecore package is itself a ENamedElement :

js>
ecore.affName();
ecore

Nothe the use of this to designate a ENamedElement instance and from there to access its name attribute.

TrimPath templates with EMFShell

TrimPath JavaScript Templates (JST) is a template engine written in JavaScript. It allows to generate code from templates. Once compiled, a template is a JavaScript. The EMFShell model decoration mechanism enables execution of compiled templates attached to different model elements.

js>
ecore.$ENamedElement.prototype.affName = 'Element name is ${name |ucfirst}'.asTemplate();
js> ecore.affName();
Element name is Ecore


However, a TrimPath JST syntax limitation prevents the use of braces as ordinary text inside a template source. Such a template is not correct :

js>
ecore.$EPackage.prototype.classes = '{for c in eClassifiers.select(function(clsf){return clsf instanceof ecore.$EClass;})} ${c.name} {/for}'.asTemplate();
js: "bundleentry://8/template.js#46(eval)", line 1: uncaught JavaScript runtime exception: SyntaxError: il manque ')' après une liste d'arguments ...

A workaround consists in replacing the argument of select (an unnamed function) by a named function defined somewhere else :
js> fClasses = function(clsf){return clsf instanceof ecore.$EClass;};

function (clsf) {

return clsf instanceof ecore.$EClass;

}

js>
ecore.$EPackage.prototype.classes = '{for c in eClassifiers.select(fClasses)} ${c.name} {/for}'.asTemplate();
...

js>
ecore.classes();
EAttribute EAnnotation EClass EClassifier EDataType EEnum EEnumLiteral EFactory EModelElement ENamedElement EObject EOperation
EPackage EParameter EReference EStructuralFeature ETypedElement EStringToStringMapEntry

In case of numerous functions such as fClasses, collision risks can be limited by embedding these functions as model decorations :
js> ecore.$EModelElement.prototype.fClasses = function(clsf){return clsf instanceof ecore.$EClass;};
function (clsf) {
 return clsf instanceof ecore.$EClass;
}

js>
ecore.$EPackage.prototype.classes = '{for c in eClassifiers.select(this.fClasses)} ${c.name} {/for}'.asTemplate();
...

js>
ecore.classes();
EAttribute EAnnotation EClass EClassifier EDataType EEnum EEnumLiteral EFactory EModelElement ENamedElement EObject EOperation
EPackage EParameter EReference EStructuralFeature ETypedElement EStringToStringMapEntry


If the template source is long, it can located in a text file that can be read thanks to the readUrl command.

A complete description of the TrimPath JST syntax can be found at http://trimpath.com/project/wiki/JavaScriptTemplateSyntax.

Commands from the Rhino shell
The genuine Rhino shell also provides useful functions such as readUrl : which can use any kind of URL, included Eclipse-specific ones :
js> HiveMetamodel = readUrl( 'platform:/resource/MyProject/model/Bees.ecore' );










js> serializedHive = readUrl( 'platform:/resource/MyProject/model/hive1.xmi' );





An exhaustive list of these commands can be found at : http://www.mozilla.org/rhino/shell.html