...
- Create a new empty Plug-In Project.
- Add your metamodel project as a dependency of your new project through the Plugin Manifest Editor.
- Create a simple Java class that implements a main method. Hint: In a new Java class, simply type main and hit Ctrl+Space. Eclipse content assist will create the method for you.
- Import all packages of your metamodel code (i.e.,
packagename
,packagename.impl
, andpackagename.util
).
Creating a Model
...
Info | ||
---|---|---|
|
...
To talk about programmatically handling models, we will have to assume some sort of design for your model. The design we're assuming here is not the only possible design for your Turing Machines. Don't be alarmed if your model is different. |
For instantiation of a model from code you cannot directly use the Java classes generated for the model. Instead, the main package contains interfaces for all of your model object classes. The impl
package contains the actual implementation and the util
package contains some helper classes. Do not instantiate objects directly by manually calling new
. EMF generates a Factory to create new objects. The factory itself uses the singleton pattern to get access to it:
Code Block | |
---|---|
|
...
| |
// assuming the model is called "Turing" |
...
// and classes are "Model","State" and "Transition" |
...
TuringFactory factory = TuringFactory.eINSTANCE; |
...
Model myModel = factory.createModel(); |
...
State state1 = factory.createState(); |
...
State state2 = factory.createState(); |
...
Transition trans1 = factory.createTransition(); |
...
For all simple attributes, there are getter and setter methods:
...
Code Block | ||
---|---|---|
| ||
state1.setName("State 1"); |
...
Simple references (multiplicity of 1) also have getters and setters:
...
Code Block | ||
---|---|---|
| ||
// assume a transition has simple references to its source and target state |
...
trans1.setSourceState(state1); |
...
trans1.setTargetState(state2); |
List references (multiplicity of > 1) have only a list getter, which is used to manipulate the list:
Code Block |
---|
...
| ||
EList<State> states = myModel.getStates(); |
...
states.add(state1); |
...
states.add(state2); |
...
With these information out of the way, on we go to some model creation:
...
- Add a dependency to the
org.eclipse.emf.ecore.xmi
plug-in. Use something like the following code to save the model from above:
Code Block language java // Create a resource set.
ResourceSet resourceSet =
new
ResourceSetImpl();
// Register the default resource factory -- only needed for stand-alone!
// this tells EMF to use XML to save the model
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
Resource.Factory.Registry.DEFAULT_EXTENSION,
new
XMIResourceFactoryImpl());
// Get the URI of the model file.
URI fileURI = URI.createFileURI(new
File("myTuringMachine.xmi").getAbsolutePath());
// Create a resource for this file.
Resource resource = resourceSet.createResource(fileURI);
// Add the model objects to the contents.
resource.getContents().add(myModel);
// Save the contents of the resource to the file system.
try
{
{ resource.save(Collections.EMPTY_MAP);
// the map can pass special saving options to the operation
}
catch
{(IOException e)
{ /* error handling */
}
- Execute the main method.
- Refresh the project.
- Hopefully be pleased about the new file in your project. Open the file to see if it contains all elements. Do you understand why opening the model does not correctly open your tree editor? Think about it. (And open it with a text editor.)
...
- Create a second class with a main() method.
Load the resource with something like the following code:
Code Block language java // Create a resource set.
ResourceSet resourceSet =
new
ResourceSetImpl();
// Register the default resource factory -- only needed for stand-alone!
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
Resource.Factory.Registry.DEFAULT_EXTENSION,
new
XMIResourceFactoryImpl());
// Register the package -- only needed for stand-alone!
// You find the correct name of the package in the generated model code
TuringPackage libraryPackage = TuringPackage.eINSTANCE;
// Get the URI of the model file.
URI fileURI = URI.createFileURI(new
File("myTuringMachine.xmi").getAbsolutePath());
// Demand load the resource for this file, here the actual loading is done.
Resource resource = resourceSet.getResource(fileURI,
true);
// get model elements from the resource
// note: get(0) might be dangerous. why?
EObject myModelObject = resource.getContents().get(0);
// Do something with the model
if
myModelObject(
myModelObject instanceof
{Model)
model{ // Model is the root class of your
model for(State state: ((Model) myModelObject).getStates()){
System.out.println(state.getName());
}
} }
Print the model to the console with something like the following code:
Code Block language java resource.save(System.out, Collections.EMPTY_MAP);
Implementing a Head Controller
This is where all the model design and model generation pays off and where we will establish the link to the second tutorial: you will write an anIHeadController
implementation that can simulate Turing Machines specified as models following the metamodel you just designed. Your simulator should be able to execute arbitrary instances of your metamodel.
...
- Add a new class to one of your plug-ins named TuringHeadController. Make sure it implements the IHeadController interface we defined in the second tutorial and register it with the appropriate extension point.
- Add a new method
initialize()
to your controller that loads a Turing Machine model from a fixed path. - Implement the
nextCommand()
andreset()
methods:- You can access all references and attributes of model elements using generated getter methods.
reset()
selects a state that is marked as being an initial state of the Turing Machine and saves it as the current state in a private field of the controller. (You did think about modeling initial states, right? If not, don't be frustrated, that's not too big of a deal. Just make the necessary changes to your metamodel and regenerate the code.)nextCommand()
analyzes the outgoing transitions of the currently active state and takes the first one that matches the current character. It then selects the target state of that transition as the new active state and returns the actions of the transition as asHeadCommand
. If there is no transition that matches the current input, return a command that does nothing.- At the beginning of
nextCommand()
, check if there is an active state. If not, callinitialize()
andreset()
before doing the simulation. - Remember that if you add the new controller to the
de.cau.cs.rtprak.login.simple
plug-in, you will have to add a dependency to the...turingmodel
plug-in and make sure the latter exports the required packages.
...