package de.voelter.emf.dynamic;
import java.io.IOException;
import junit.framework.TestCase;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import de.voelter.emf.dynamic.util.IOHelper;
/**
* This piece of code actually does the same thing as the
* ModelCreationTest, however, without using the generated
* (meta) classes. Instead, EMF's reflective API is used.
* You can run this test *without* having generated the
* implementation classes. You may want to verify that by
* deleting the generated classes....
*
* Note that this reflective API can also be used on models
* represented with the generated classes (such as in the
* ModelCreationTest). This means that
* - in case of the generated classes, the reflective API
* is mapped to the concrete features (you may look at the
* EntityImpl class in order to understand that)
* - in case of the purely generic way (in this test) a
* default implementatoin is used that uses hash maps
* etc. to generically store the object model.
*
* The cool thing is that tools can access any kind of model
* and access it using the reflective API. Technically speaking,
* the generate metaclasses have their own runtime metametamodel
* with them. A very powerful thing.
* @author MarkusVoelter
*/
public class DynamicModelCreationTest extends TestCase {
public void testCreateModelGenerically() throws IOException {
// we first have to load the "meta" package, i.e. the
// one we saved in the MetaModelCreationTest. Again, we
// use a resource set for that.
ResourceSet rs = new ResourceSetImpl();
// the usual file extension registration
rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("ecore", new XMIResourceFactoryImpl());
// we then create the URI (note that creating the resource does
// not mean it's overwritten or anything).
Resource res = rs.createResource( URI.createFileURI( "l:/exampleWorkspace-v4-emf/emfdynamic/metamodel.ecore" ));
// finally, we load the resource.
res.load(null);
// the following lines of code of course do assume some
// knowledge about the structure of the metamodel saved
// in the MetaModelCreationTest. In practice, if this were
// some kind of "generic tool", it would generically inspect
// the contents and show them in some kind of browser, etc.
// Here, we know what's in the resource, and we can use it.
// so, we know that the toplevel element is a package.
// this package contains the classes that play the role
// of the metaclasses for this test.
EPackage metapackage = (EPackage)res.getContents().get(0);
// we can retrieve the class object for our entity class
// by name. We can do the same for the Attribute.
EClass entityClass = (EClass) metapackage.getEClassifier("Entity");
EClass attributeClass = (EClass) metapackage.getEClassifier("Attribute");
// from the entity class, we can now query the structural features
// name and attributes. These are EAttributes and EReferences, respec-
// tively.
EAttribute entityNameAttr = (EAttribute) entityClass.getEStructuralFeature("name");
EReference attributesRef = (EReference) entityClass.getEStructuralFeature("attributes");
// finally, we get the metaobject for the name attribute of attributes
EAttribute attrNameAttr = (EAttribute) attributeClass.getEStructuralFeature("name");
// now this is interesting: from the package, we can
// get the factory that allows us to subsequently instan-
// tiate elemnets of that package!
EFactory metafactory = metapackage.getEFactoryInstance();
// so, here we create an instance of the entityClass model
// element. Note how don't use the generated classes, rather
// we use EObject to point to the new object and the metaobject
// to identify what we want to create an instance of.
EObject customerEntity = metafactory.create( entityClass );
// we then use the reflective API to set the name of the
// new thing. Note again how we use the "metaobject" retrieved
// above to identify what we want to set.
customerEntity.eSet( entityNameAttr, "Customer" );
// we then create a number attribute...
EObject numberAttr = metafactory.create( attributeClass );
// and set its name.
numberAttr.eSet( attrNameAttr, "number" );
// same for the address attribute
EObject addressAttr = metafactory.create( attributeClass );
addressAttr.eSet( attrNameAttr, "address" );
// finally, we add the two attributes to the entity.
// there is not add...(...) Operation, so this is a bit
// awkward.
((EList)customerEntity.eGet( attributesRef )).add( numberAttr );
((EList)customerEntity.eGet( attributesRef )).add( addressAttr );
// finally, we store the model. If you look at the XML.
// it's basically equivalent to the one created in the
// ModelCreationTest
try {
IOHelper.storeAsXMI( customerEntity, "l:/exampleWorkspace-v4-emf/emfdynamic/genericmodel.xmi" );
} catch (IOException e1) {
fail( e1.getMessage() );
}
}
}
|