Difference between revisions of "Henshin Interpreter"

From Eclipsepedia

Jump to: navigation, search
(17 intermediate revisions by one user not shown)
Line 1: Line 1:
The Henshin interpreter is the default engine for executing model transformations defined in Henshin. The interpreter can be invoked either using a wizard or programmatically.
+
The Henshin interpreter is the default engine for executing model transformations defined in Henshin. The interpreter can be invoked either using a wizard or programmatically using an API.
 +
 
 +
__TOC__
  
 
== Interpreter Wizard ==
 
== Interpreter Wizard ==
Line 17: Line 19:
 
== Interpreter API ==
 
== Interpreter API ==
  
The interpreter can be also invoked programatically. To do this, you need to set up an Eclipse Plug-In including a dependency to the Henshin run-time.
+
The interpreter can be also invoked programatically, either as an IApplication in Eclipse or as a simple stand-alone Java application.
 
+
=== Setting up the Plug-In Project ===
+
 
+
If you want to create a new plug-in from scratch, go to ''New...→Other...→Plug-in Development→Plug-in Project'' and follow the wizard.
+
 
+
If you have an existing project which is not a plug-in project (e.g. just a Java project), right-click on the project in the Package Explorer and select ''Configure→Convert to Plug-in projects...''.
+
 
+
Now you need to make sure that the dependency to the Henshin interpreter plug-in is set. For this, open either the ''plugin.xml'' or the ''META-INF/MANIFEST.MF'' file in your project and click on the ''Dependencies'' tab. If it is not yet listed there, add the following plug-in dependencies
+
* ''org.eclipse.core.runtime''
+
* ''org.eclipse.core.resources''
+
* ''org.eclipse.emf.ecore''
+
* ''org.eclipse.emf.ecore.xmi''
+
* ''org.eclipse.emf.henshin.interpreter''
+
When you are done, save and close the file.
+
  
=== Invoking the Interpreter ===
+
Make sure you have all dependencies fulfilled to the Henshin runtime and to EMF. For Henshin, you should include the the '''model''' and the '''interpreter''' plug-in into your classpath (e.g. as a plug-in dependency). For examples, see also the Java source codes in the documented  [http://www.eclipse.org/modeling/emft/henshin/examples.php examples page].
  
In your Java class, e.g. an IApplication (see [http://www.eclipsezone.com/eclipse/forums/t99762.html here] for a hello world example) you can now invoke the interpreter as follows.
+
=== Loading & Saving ===
  
<pre>
+
For loading and saving of models and transformations you can use the class '''HenshinResourceSet''', which provides some convenience methods. Below you can see how to load models and transformations.
import org.eclipse.equinox.app.IApplication;
+
import org.eclipse.equinox.app.IApplicationContext;
+
  
import org.eclipse.emf.ecore.EObject;
+
<source lang="java">
import org.eclipse.emf.ecore.EPackage;
+
// Create a resource set for the working directory "my/working/directory"
import org.eclipse.emf.henshin.interpreter.EmfEngine;
+
HenshinResourceSet resourceSet = new HenshinResourceSet("my/working/directory");
import org.eclipse.emf.henshin.interpreter.RuleApplication;
+
import org.eclipse.emf.henshin.interpreter.util.Match;
+
import org.eclipse.emf.henshin.interpreter.util.ModelHelper;
+
import org.eclipse.emf.henshin.matching.EmfGraph;
+
import org.eclipse.emf.henshin.model.Rule;
+
import org.eclipse.emf.henshin.model.TransformationSystem;
+
import org.eclipse.emf.henshin.model.impl.HenshinPackageImpl;
+
  
public class MyTransformation implements IApplication {
+
// Load a model:
 +
Resource model = resourceSet.getResource("mymodel.xmi");
  
  public Object start(IApplicationContext context) throws Exception {
+
// Load the Henshin module:
 +
Module module = resourceSet.getModule("mytransformation.henshin");
  
    // Register file extensions:
+
// Apply the transformation (see below)...
    ModelHelper.registerFileExtension("henshin");
+
    // You may need to register the extensions of your model files here too
+
  
    // Register packages:
+
// Save the model:
    HenshinPackageImpl.init();
+
model.save(null);
    // Add your generated packages here...
+
</source>
 +
Note that all relative file paths will be resolved using the working directory of the resource set. You should make sure that you use a single resource set for all loading and saving operations. There are also some more convenience methods for loading and saving (see the Javadoc).
  
    // Load the transformation system:
+
=== Transforming and more ===
    TransformationSystem trans = (TransformationSystem) ModelHelper.loadFile("model/myTransformation.henshin");
+
  
    // Load the model to be transformed:
+
Here is a typical use case for the interpreter:
    EObject root = ModelHelper.loadFile("model/myModel.xmi"); // or another registered file extension
+
  
    // Initialize the Henshin interpreter:
+
<source lang="java">
    EmfGraph graph = new EmfGraph();
+
// Prepare the engine:
    graph.addRoot(root);
+
Engine engine = new EngineImpl();
   
+
    EmfEngine engine = new EmfEngine(graph);
+
  
    // Load a rule (or a transformation unit)
+
// Initialize the graph:
    Rule myRule = trans.findRuleByName("MyRule");
+
EGraph graph = new EGraphImpl(model);
  
    // Create a RuleApplication (or UnitApplication)
+
// Find the unit to be applied:
    RuleApplication application = new RuleApplication(engine, myRule);
+
Unit unit = module.getUnit("myMainUnit");
 +
 +
// Apply the unit:
 +
UnitApplication application = new UnitApplicationImpl(engine, graph, unit, null);
 +
application.execute(null);
 +
</source>
 +
This is all code necessary to execute a transformation in Henshin! Note that engines should always be reused (you need only a single instance). The same holds for the EGraph. UnitApplications can be reused, but there is also no harm in creating new instances.
  
    // Find a match:
+
You can also use the following convenience method. It also properly updates the contents of the model resource based on the changes to the EGraph.
    Match match = myRukle.findMatch();
+
<source lang="java">
    if (match!=null) {
+
InterpreterUtil.applyToResource(unit, engine, model);
 +
</source>
  
      // Apply the rule:
+
'''Setting and Getting Parameter Values''' This is how you can assign parameter values for the unit application (before executing it), and retrieving the resulting values (after the application):
      application.setMatch(match);
+
<source lang="java">
      application.apply();
+
application.setParameterValue("p1", "helloworld");
 +
application.setParameterValue("p2", object);
  
      // Save the transformed model to a file:
+
application.execute(null);
      ModelHelper.saveFile("model/transformed.xmi", root);
+
  
    } else {
+
Object newValue = application.getResultParameterValue("p2");
      System.out.println("Rule " + myRule.getName() + " not applicable");
+
</source>
    }
+
If you want to apply a single rule, you can also use RuleApplication. In this class, you can also specify partial or complete matches, and get the result match (a.k.a. ''co-match'') after the rule application. The classes for parameter assignments and matches implement toString() -- so you can also easily inspect their details.
  
    return IApplication.EXIT_OK;
+
'''Canceling, Logging and Profiling''' Maybe you noticed already the ''null'' parameter passed to the ''execute()'' method. Here you can also base an ''ApplicationMonitor'' instance which give you the possibility to inspect and to cancel unit or rule applications. For logging, you can use the already implemented class ''LoggingApplicationMonitor'' which will print detailed logs on every rule application. You can filter the logging ask this monitor to automatically save the intermediate results of your transformation or to abort the execution after a certain amount of steps. Another very interesting implementation is ''ProfilingApplicationMonitor'' which automatically collects statistics on the execution times for rule. Just run ''printStats()'' after the transformation to find out where the bottlenecks are in your transformation. If you think that Henshin should be able to apply a particular rule faster, contact the Henshin mailing list with your profiling results.
  }
+
  
  public void stop() {
+
'''Finding matches''' Sometimes, you just want to find matches for a rule without actually applying the rule. You can directly use the engine for this:
  }
+
<source lang="java">
 +
Match partialMatch = new MatchImpl(rule);  // can be also null
 +
partialMatch.setParameterValue(p1,"foo");
  
 +
// Iterate over all matches and print them on the console:
 +
for (Match match : engine.findMatches(rule, graph, partialMatch)) {
 +
  System.out.println(match);
 
}
 
}
 +
</source>
 +
Note that matches are computed on-demand and that ''findMatches()'' returns an instance of Iterable<Match>. If you need all matches anyway, you can also use ''InterpreterUtil.findAllMatches()'' which will return a list of all matches.
  
</pre>
+
'''Checking graph isomorphy''' You can use this to check whether to EGraphs are isomorphic:
 +
<source lang="java">
 +
InterpreterUtil.areIsomorphic(graph1, graph2);  // or resources
 +
</source>
 +
Note that this is not really fast because the necessary metadata for a more efficient isomorphy checking is not available for plain EGraphs. Faster isomorphy checking is implemented separately in the state space tools but requires to compute hash codes first.

Revision as of 04:18, 1 November 2012

The Henshin interpreter is the default engine for executing model transformations defined in Henshin. The interpreter can be invoked either using a wizard or programmatically using an API.

Contents


Interpreter Wizard

Henshin Interpreter Wizard

The interpreter wizard can be invoked by a right-click on a *.henshin file in the Package Explorer and selecting Henshin→Apply with Henshin.

In the first page of the wizard, you need to enter the following information:

  • Choose a transformation rule or unit to be applied.
  • Specify a model file to be transformed using the rule or unit.
  • Enter possible parameters of the rule or unit. Make sure that the type of the parameters is correctly set. Ignore means that the parameter is not set and will be matched automatically by the interpreter.

If you click Preview you should either see the modifications to the model or get a message that the rule or unit could not be applied. If you think it should be applicable but still get a message that it is not, make sure the parameters are all correctly set including their types.

If you click Transform the model will be transformed and saved, if possible.

Interpreter API

The interpreter can be also invoked programatically, either as an IApplication in Eclipse or as a simple stand-alone Java application.

Make sure you have all dependencies fulfilled to the Henshin runtime and to EMF. For Henshin, you should include the the model and the interpreter plug-in into your classpath (e.g. as a plug-in dependency). For examples, see also the Java source codes in the documented examples page.

Loading & Saving

For loading and saving of models and transformations you can use the class HenshinResourceSet, which provides some convenience methods. Below you can see how to load models and transformations.

// Create a resource set for the working directory "my/working/directory"
HenshinResourceSet resourceSet = new HenshinResourceSet("my/working/directory");
 
// Load a model:
Resource model = resourceSet.getResource("mymodel.xmi");
 
// Load the Henshin module:
Module module = resourceSet.getModule("mytransformation.henshin");
 
// Apply the transformation (see below)...
 
// Save the model:
model.save(null);

Note that all relative file paths will be resolved using the working directory of the resource set. You should make sure that you use a single resource set for all loading and saving operations. There are also some more convenience methods for loading and saving (see the Javadoc).

Transforming and more

Here is a typical use case for the interpreter:

// Prepare the engine:
Engine engine = new EngineImpl();
 
// Initialize the graph:
EGraph graph = new EGraphImpl(model);
 
// Find the unit to be applied:
Unit unit = module.getUnit("myMainUnit");
 
// Apply the unit:
UnitApplication application = new UnitApplicationImpl(engine, graph, unit, null);
application.execute(null);

This is all code necessary to execute a transformation in Henshin! Note that engines should always be reused (you need only a single instance). The same holds for the EGraph. UnitApplications can be reused, but there is also no harm in creating new instances.

You can also use the following convenience method. It also properly updates the contents of the model resource based on the changes to the EGraph.

InterpreterUtil.applyToResource(unit, engine, model);

Setting and Getting Parameter Values This is how you can assign parameter values for the unit application (before executing it), and retrieving the resulting values (after the application):

application.setParameterValue("p1", "helloworld");
application.setParameterValue("p2", object);
 
application.execute(null);
 
Object newValue = application.getResultParameterValue("p2");

If you want to apply a single rule, you can also use RuleApplication. In this class, you can also specify partial or complete matches, and get the result match (a.k.a. co-match) after the rule application. The classes for parameter assignments and matches implement toString() -- so you can also easily inspect their details.

Canceling, Logging and Profiling Maybe you noticed already the null parameter passed to the execute() method. Here you can also base an ApplicationMonitor instance which give you the possibility to inspect and to cancel unit or rule applications. For logging, you can use the already implemented class LoggingApplicationMonitor which will print detailed logs on every rule application. You can filter the logging ask this monitor to automatically save the intermediate results of your transformation or to abort the execution after a certain amount of steps. Another very interesting implementation is ProfilingApplicationMonitor which automatically collects statistics on the execution times for rule. Just run printStats() after the transformation to find out where the bottlenecks are in your transformation. If you think that Henshin should be able to apply a particular rule faster, contact the Henshin mailing list with your profiling results.

Finding matches Sometimes, you just want to find matches for a rule without actually applying the rule. You can directly use the engine for this:

Match partialMatch = new MatchImpl(rule);  // can be also null
partialMatch.setParameterValue(p1,"foo");
 
// Iterate over all matches and print them on the console:
for (Match match : engine.findMatches(rule, graph, partialMatch)) {
  System.out.println(match);
}

Note that matches are computed on-demand and that findMatches() returns an instance of Iterable<Match>. If you need all matches anyway, you can also use InterpreterUtil.findAllMatches() which will return a list of all matches.

Checking graph isomorphy You can use this to check whether to EGraphs are isomorphic:

InterpreterUtil.areIsomorphic(graph1, graph2);  // or resources

Note that this is not really fast because the necessary metadata for a more efficient isomorphy checking is not available for plain EGraphs. Faster isomorphy checking is implemented separately in the state space tools but requires to compute hash codes first.