问题
My question has two parts:
1) How can I create and/or modify and then store EMF ecore files (ecore metamodels with .ecore suffixes) from my scala/java code?
2) How can I create and/or modify an instance of an ecore file (i.e. a model conforming to an ecore metamodel) from my scala/java code?
I am looking to see if there are some possible ways of doing these, other that manipulating directly their corresponding XML files using XML API's.
Providing a code spinet or a reference to it is very much appreciated.
ps. As a background thought, I am wondering if I can use a single API for performing both of the above tasks, as we can look to an ecore file as a model/instance of Ecore.ecore.
回答1:
Basic Concepts (Resource, ResourceSet, Resource Factory and Registry):
Before answering this question I will explain some concepts in ecore API. The First two concepts are Resource and ResourceSet. Resource is a program level representation of a persistent resource (like an ecore file), and ResourceSet is simply a set of these kind of resources. Each ecore metamodel document as well as a model document (which conforms to its metamodel) is a resource. Therefore the first step to work with these files is to provide a program level representation of them as resources in a resourceSet.
Another two concepts are Resource Factory and Registry. Factory classes are used to generate resources, and registries are keeping track of list of these factories in resourceSets. Depending on how our resource are stored, we can use different factories to manipulate them. For example, EcoreResourceFactoryImpl, XMLResourceFactoryImpl, and XMIResourceFactoryImpl are some examples of factory implementations that can be used to handle, respectively, ecore, xml, and xmi files. If we want to use these factories to handle resources in a resourceSet we need to put them in the registry list of resourceSet first. So, for each resourceSet that I mentioned above, there is a registry list.
With all the above being said, let's see how loading and modifying an ecore file (metamodel) and an instance file (model) happens in a java code.
First, We need to create a resourceSet to represent our persistent resources we would like to work with:
ResourceSet resourceSet = new ResourceSetImpl();
Then in the registry of this resourceSet, we need to register the Factories we want to work with:
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("ecore", new EcoreResourceFactoryImpl());
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl());
Above two lines of code simply register EcoreResourceFactoryImpl and XMIResourceFactoryImpl as, respectively, ecore and xmi file factories (note that ecore and xmi are file extensions there). I assumed that my metamodel file extension is ecore and my model file extension is xmi.
After registering these Factories, we can now ask our ResourceSet to load our metamode (i.e., ecore) file as below:
Resource myMetaModel= resourceSet.getResource(URI.createFileURI("./univ.ecore"), true);
univ.ecore is the name of my ecore file.
For loading a model file we need to take one further step! We need to first register one more thing in the our resourceSet. That is to register the package of our ecore metamodel in the registry list of packages in our resource set. For doing this we need to first get a programming level representation of our ecore package as bellow:
EPackage univEPackage = (EPackage) myMetaModel.getContents().get(0);
And then, register this package in the registry list of packages of our resource set as below:
resourceSet.getPackageRegistry().put("http://gholizadeh.org", univEPackage);
We are now ready to load our model (xmi file). we use the following code for this:
Resource myModel = resourceSet.getResource( URI.createURI( "./univModel.xmi"), true);
Now we have brought both of our metamode and model files to the programming level, and we can simply manipulate them in code.
Change the Metamodel:
for example, for creating a new Class in an ecore file, we use EcoreFactory API: we first obtain an instance of this class as below:
EcoreFactory theCoreFactory = EcoreFactory.eINSTANCE;
and then create an EClass as the following:
EClass adultEClass= theCoreFactory.createEClass();
Then for keeping this Class, we need to add it to the list of our loaded ecore package classifiers as bellow:
univEPackage.getEClassifiers().add(adultEClass);
For doing aditional changes you need to get more familiar with ecore API.
Change the Model:
for changing a model, we need to create objects of type EObject. Similar to EcoreFactory in the above, we need a factory to do this. But instead of EcoreFactory, we need an object factory. For each ecore package there is an specific object factory of type EFactory that we can get as the following:
EFactory univInstance = univEPackage.getEFactoryInstance();
Note that univEPackage in above code, represents our ecore package (see some paragraphs above). After doing this, we are ready to create objects for our model. For example
EObject adultObject = univInstance.create(adultEClass);
create an object of type adultEClass, in our model. Note that for persisting this newly created object we need to add it to the content of our resource (that represent our model, i.e., myModel). Since our persistent file is in xmi format and it has only one root we need to put all of our objects in a list and add this list to our resource:
EList<EObject> ModelObjects = new BasicEList<EObject>();
ModelObjects.add(adultObject);
myModel.getContents().addAll(ModelObjects);
Storing Model and Metamodel files:
Finally, after we modified our metamodel and model elements we need to store them again in their corresponding files. This is simply done by calling save method of their corresponding Resources:
myModel.save(null);
myMetaodel.save(null);
来源:https://stackoverflow.com/questions/30034826/create-and-modify-ecore-files-and-their-instances-from-code