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.createResourceURI.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 = (EClassmetapackage.getEClassifier("Entity");
    EClass attributeClass = (EClassmetapackage.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 = (EAttributeentityClass.getEStructuralFeature("name");
    EReference attributesRef = (EReferenceentityClass.getEStructuralFeature("attributes");
    // finally, we get the metaobject for the name attribute of attributes
    EAttribute attrNameAttr = (EAttributeattributeClass.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.createentityClass );
    // 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.eSetentityNameAttr, "Customer" );
    
    // we then create a number attribute...
    EObject numberAttr = metafactory.createattributeClass );
    // and set its name.
    numberAttr.eSetattrNameAttr, "number" );
    
    // same for the address attribute
    EObject addressAttr = metafactory.createattributeClass );
    addressAttr.eSetattrNameAttr, "address" );
    
    // finally, we add the two attributes to the entity.
    // there is not add...(...) Operation, so this is a bit
    // awkward.
    ((EList)customerEntity.eGetattributesRef )).addnumberAttr );
    ((EList)customerEntity.eGetattributesRef )).addaddressAttr );
    
    // finally, we store the model. If you look at the XML.
    // it's basically equivalent to the one created in the
    // ModelCreationTest
    try {
      IOHelper.storeAsXMIcustomerEntity, "l:/exampleWorkspace-v4-emf/emfdynamic/genericmodel.xmi" );
    catch (IOException e1) {
      faile1.getMessage() );
    }
    
    
    

    
  }
  
}