Java tutorial
/******************************************************************************* * Copyright (c) 2014-2015 TELECOM ParisTech and AdaCore. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Elie Richa - initial implementation *******************************************************************************/ package fr.tpt.atlanalyser.examples; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.filefilter.SuffixFileFilter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.compare.Comparison; import org.eclipse.emf.compare.Diff; import org.eclipse.emf.compare.DifferenceKind; import org.eclipse.emf.compare.EMFCompare; import org.eclipse.emf.compare.match.DefaultComparisonFactory; import org.eclipse.emf.compare.match.DefaultEqualityHelperFactory; import org.eclipse.emf.compare.match.DefaultMatchEngine; import org.eclipse.emf.compare.match.IComparisonFactory; import org.eclipse.emf.compare.match.IMatchEngine; import org.eclipse.emf.compare.match.eobject.IEObjectMatcher; import org.eclipse.emf.compare.match.impl.MatchEngineFactoryImpl; import org.eclipse.emf.compare.match.impl.MatchEngineFactoryRegistryImpl; import org.eclipse.emf.compare.scope.IComparisonScope; import org.eclipse.emf.compare.utils.UseIdentifiers; import org.eclipse.emf.ecore.EClass; 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.Resource.IOWrappedException; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.xmi.DanglingHREFException; import org.eclipse.emf.ecore.xmi.XMIResource; import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl; import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; import org.eclipse.emf.henshin.interpreter.ApplicationMonitor; import org.eclipse.emf.henshin.interpreter.EGraph; import org.eclipse.emf.henshin.interpreter.Engine; import org.eclipse.emf.henshin.interpreter.RuleApplication; import org.eclipse.emf.henshin.interpreter.UnitApplication; import org.eclipse.emf.henshin.interpreter.impl.AssignmentImpl; import org.eclipse.emf.henshin.interpreter.impl.EngineImpl; import org.eclipse.emf.henshin.interpreter.util.InterpreterUtil; import org.eclipse.emf.henshin.model.Edge; import org.eclipse.emf.henshin.model.Formula; import org.eclipse.emf.henshin.model.Graph; import org.eclipse.emf.henshin.model.HenshinFactory; import org.eclipse.emf.henshin.model.HenshinPackage; import org.eclipse.emf.henshin.model.Module; import org.eclipse.emf.henshin.model.Node; import org.eclipse.emf.henshin.model.Rule; import org.eclipse.emf.henshin.model.Unit; import org.eclipse.emf.henshin.model.resource.HenshinResourceFactory; import org.eclipse.emf.henshin.model.resource.HenshinResourceSet; import org.eclipse.emf.henshin.model.util.HenshinSwitch; import org.eclipse.m2m.atl.emftvm.EmftvmFactory; import org.eclipse.m2m.atl.emftvm.ExecEnv; import org.eclipse.m2m.atl.emftvm.Metamodel; import org.eclipse.m2m.atl.emftvm.Model; import org.eclipse.m2m.atl.emftvm.ModelDeclaration; import org.eclipse.m2m.atl.emftvm.impl.resource.EMFTVMResourceFactoryImpl; import org.eclipse.m2m.atl.emftvm.util.ExecEnvPool; import org.javatuples.Triplet; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import fr.tpt.atlanalyser.ATLAnalyserException; import fr.tpt.atlanalyser.atl2agt.ATL2Henshin; import fr.tpt.atlanalyser.post2pre.Post2Pre4ATL; import fr.tpt.atlanalyser.utils.EPackageUtils; import fr.tpt.atlanalyser.utils.Utils; public class ExampleRunner { // public static void main(String[] args) throws IOException, // ATLAnalyzerException { // ExampleRunner ex = new ExampleRunner("examples/SimpleCMG"); // ex.compileAndTransform(); // Resource atlRes = ex.applyAtlTransformation( // "examples/SimpleCMG/InputModels/in1.xmi", // "examples/SimpleCMG/ATLOutput/in1_atl.xmi"); // Resource henshinRes = ex.applyHenshinTransformation( // "examples/SimpleCMG/InputModels/in1.xmi", // "examples/SimpleCMG/HenshinOutput/in1_henshin.xmi"); // ex.compareModels(atlRes, henshinRes); // } private static final Logger LOGGER = LogManager.getLogger(ExampleRunner.class.getSimpleName()); protected final File baseDir; protected final File inputMMDir; protected final File outputMMDir; protected final File transformationDir; protected final File inputDir; protected final File atlOutputDir; protected final File henshinOutputDir; protected final ATL2Henshin atl2Henshin; protected final HenshinResourceSet resourceSet; private File compiledTransfo; private static final EmftvmFactory emftvmFactory = EmftvmFactory.eINSTANCE; private static final boolean IGNORE_EREF_ORDERING = false; private EPackage inputMM; private EPackage outputMM; private File atlTransformation; private int jobs; private static Map<Object, Object> xmiSaveOptions; static { xmiSaveOptions = Maps.newHashMap(); xmiSaveOptions.put(XMIResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); // xmiSaveOptions.put(XMIResource.OPTION_PROCESS_DANGLING_HREF, // XMIResource.OPTION_PROCESS_DANGLING_HREF_RECORD); } public ExampleRunner(String baseDir) { this.baseDir = new File(baseDir); this.inputMMDir = new File(this.baseDir, "InputMM"); this.outputMMDir = new File(this.baseDir, "OutputMM"); this.transformationDir = new File(this.baseDir, "Transformation"); this.inputDir = new File(this.baseDir, "InputModels"); this.atlOutputDir = new File(this.baseDir, "ATLOutput"); this.henshinOutputDir = new File(this.baseDir, "HenshinOutput"); this.resourceSet = new HenshinResourceSet(this.baseDir.getPath()); Map<String, Object> extensionToFactoryMap = this.resourceSet.getResourceFactoryRegistry() .getExtensionToFactoryMap(); extensionToFactoryMap.put(Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()); extensionToFactoryMap.put("ecore", new EcoreResourceFactoryImpl()); extensionToFactoryMap.put("emftvm", new EMFTVMResourceFactoryImpl()); extensionToFactoryMap.put("henshin", new HenshinResourceFactory()); EPackage.Registry.INSTANCE.put(HenshinPackage.eNS_URI, HenshinPackage.eINSTANCE); this.atl2Henshin = new ATL2Henshin(resourceSet); } public ExampleRunner(String baseDir2, int jobs) { this(baseDir2); this.jobs = jobs; } public void executePost2Pre(File postFile) throws IOException { executePost2Pre(postFile, 1); } public void executePost2Pre(File postFile, int maxNumRuleIterations) throws IOException { // checkDirs(); inputMM = getInputMMEPkg(); outputMM = getOutputMMEPkg(); makeAbstractClassesInstantiable(inputMM); makeAbstractClassesInstantiable(outputMM); Module transfo = loadHenshinTransformation(); EcoreUtil.resolveAll(transfo); EPackage traceMM = resourceSet.getPackageRegistry().getEPackage("http://traces/1.0"); stripFromAttributes(transfo); Resource postRes = resourceSet.getResource(URI.createFileURI(postFile.getCanonicalPath()), true); Module postModule = (Module) postRes.getContents().get(0); EList<Unit> units = postModule.getUnits(); List<Formula> postconditions = Lists.transform(units, new Function<Unit, Formula>() { @Override public Formula apply(Unit arg0) { return ((Rule) arg0).getLhs().getFormula(); } }); Module preModule = HenshinFactory.eINSTANCE.createModule(); preModule.setName("Preconditions"); LOGGER.info("Starting Post2Pre for {}", transfo.getName()); Post2Pre4ATL post2Pre = new Post2Pre4ATL(transfo, inputMM, outputMM, traceMM, jobs); ScheduledExecutorService memMonitorExecutor = Executors.newScheduledThreadPool(1); memMonitorExecutor.scheduleAtFixedRate(new Runnable() { private final MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); private final Logger LOGGER = LogManager.getLogger("MemMon"); @Override public void run() { // LOGGER.setAdditivity(false); // for (Enumeration iterator = // AGGWrapper.LOGGER.getAllAppenders(); iterator // .hasMoreElements();) { // Appender appender = (Appender) iterator.nextElement(); // LOGGER.addAppender(appender); // } MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage(); final long used = heapUsage.getUsed(); double usedGB = (double) used / (1 << 30); final long max = heapUsage.getMax(); double maxGB = (double) max / (1 << 30); LOGGER.info(String.format("Memory use : %6.3fGB of %6.3fGB (%.2f%%)", usedGB, maxGB, (float) used / max * 100)); } }, 0, 10, TimeUnit.SECONDS); try { for (Formula formula : postconditions) { Formula pre = post2Pre.post2Pre(formula, maxNumRuleIterations); Rule preRule = HenshinFactory.eINSTANCE.createRule(); Graph preLhs = HenshinFactory.eINSTANCE.createGraph(); preLhs.setFormula(EcoreUtil.copy(pre)); preRule.setLhs(preLhs); preModule.getUnits().add(preRule); } } finally { memMonitorExecutor.shutdown(); } File outputDir = new File(baseDir, "Preconditions"); if (!outputDir.isDirectory()) { outputDir.mkdir(); } Resource outputRes = resourceSet .createResource(URI.createFileURI("Preconditions/" + postFile.getName() + "_pre.henshin")); outputRes.getContents().add(preModule); LOGGER.info("Writing Precondition in {}", outputRes.getURI().toString()); outputRes.save(xmiSaveOptions); LOGGER.info("Done!"); } private void makeAbstractClassesInstantiable(EPackage pkg) { TreeIterator<EObject> eAllContents = pkg.eAllContents(); for (TreeIterator<EObject> iterator = eAllContents; iterator.hasNext();) { EObject obj = iterator.next(); if (obj instanceof EClass) { EClass eClass = (EClass) obj; if (eClass.isAbstract()) { eClass.setAbstract(false); } } } } private void stripFromAttributes(Module transfo) { new HenshinSwitch<Object>() { @Override public Object caseRule(Rule object) { object.getParameters().clear(); object.getAttributeConditions().clear(); return object; }; public Object caseNode(Node object) { object.getAttributes().clear(); return object; }; public Object caseEdge(Edge object) { object.setIndex(null); return object; }; @Override public Object doSwitch(EObject eObject) { final EList<EObject> eContents = eObject.eContents(); for (EObject contObj : eContents) { this.doSwitch(contObj); } return super.doSwitch(eObject); } }.doSwitch(transfo); } public void compileAndTransform() throws IOException, ATLAnalyserException { // checkDirs(); LOGGER.info("Loading input metamodel"); inputMM = getInputMMEPkg(); assertNotNull(inputMM); atl2Henshin.registerInputMetamodel(inputMM); LOGGER.info("Loading output metamodel"); outputMM = getOutputMMEPkg(); assertNotNull(outputMM); atl2Henshin.registerOutputMetamodel(outputMM); LOGGER.info("Translating ATL transformation to Henshin"); atlTransformation = transformationDir.listFiles((FilenameFilter) new SuffixFileFilter(".atl"))[0]; Module henshinModule = atl2Henshin.translateToHenshin(atlTransformation); assertNotNull(henshinModule); assertTrue("Resulting module contains no rules!", EcoreUtil.getObjectsByType(henshinModule.getUnits(), HenshinPackage.Literals.RULE).size() > 0); File henshinTransformation = new File(atlTransformation.getParentFile(), FilenameUtils.getBaseName(atlTransformation.getPath()) + ".henshin"); LOGGER.info("Writing Henshin transformation to {}", henshinTransformation.getPath()); Resource henshinRes = resourceSet .createResource(URI.createFileURI(henshinTransformation.getCanonicalPath())); henshinRes.getContents().add(henshinModule); File tracesMM = new File(atlTransformation.getParentFile(), FilenameUtils.getBaseName(atlTransformation.getPath()) + ".traces.ecore"); Resource tracesRes = resourceSet.createResource(URI.createFileURI(tracesMM.getCanonicalPath())); tracesRes.getContents().add(atl2Henshin.getTraceMM()); tracesRes.save(xmiSaveOptions); try { henshinRes.save(xmiSaveOptions); } catch (IOWrappedException ex) { Throwable cause = ex.getCause(); if (cause != null && cause instanceof DanglingHREFException) { List<Triplet<EObject, EReference, EObject>> danglingObjects = Utils.getDanglingHrefs(henshinRes); String join = Joiner.on("\n").join(danglingObjects); System.out.println(join); } else { ex.printStackTrace(); } } } /** * * @param inputModelPath * @param outputModelPath * @return Resource containing the result of the transformation * @throws IOException */ public Resource applyAtlTransformation(String inputModelPath, String outputModelPath) throws IOException { LOGGER.info("Executing ATL Transformation"); LOGGER.info(" input: {}", inputModelPath); LOGGER.info(" output: {}", outputModelPath); ExecEnvPool pool = new ExecEnvPool(); ExecEnv execEnv = pool.getExecEnv(); compiledTransfo = transformationDir.listFiles((FilenameFilter) new SuffixFileFilter(".emftvm"))[0]; assertTrue(compiledTransfo.isFile()); PathModuleResolver resolver = new PathModuleResolver(); org.eclipse.m2m.atl.emftvm.Module emftvmModule = resolver.resolveModule(compiledTransfo.getPath()); ModelDeclaration inModelDecl = emftvmModule.getInputModels().get(0); ModelDeclaration outModelDecl = emftvmModule.getOutputModels().get(0); Metamodel inputMetamodel = emftvmFactory.createMetamodel(); inputMetamodel.setResource(getInputMMEPkg().eResource()); execEnv.registerMetaModel(inModelDecl.getMetaModelName(), inputMetamodel); Metamodel outputMetamodel = emftvmFactory.createMetamodel(); outputMetamodel.setResource(getOutputMMEPkg().eResource()); execEnv.registerMetaModel(outModelDecl.getMetaModelName(), outputMetamodel); execEnv.loadModule(resolver, compiledTransfo.getPath()); Model inModel = emftvmFactory.createModel(); File inFile = new File(inputModelPath); Resource inRes = resourceSet.createResource(URI.createFileURI(inFile.getCanonicalPath())); inRes.load(Collections.emptyMap()); inModel.setResource(inRes); execEnv.registerInputModel(inModelDecl.getModelName(), inModel); Model outModel = emftvmFactory.createModel(); File outFile = new File(outputModelPath); outModel.setResource(resourceSet.createResource(URI.createFileURI(outFile.getCanonicalPath()))); execEnv.registerOutputModel(outModelDecl.getModelName(), outModel); execEnv.run(null); outModel.getResource().save(xmiSaveOptions); return outModel.getResource(); } public Module loadHenshinTransformation() throws IOException { getTracesMM(); File henshinFile = transformationDir.listFiles((FilenameFilter) new SuffixFileFilter(".henshin"))[0]; Module henshinModule = (Module) resourceSet .getResource(URI.createFileURI(henshinFile.getCanonicalPath()), true).getContents().get(0); return henshinModule; } private EPackage getTracesMM() throws IOException { File[] listFiles = transformationDir.listFiles((FilenameFilter) new SuffixFileFilter(".traces.ecore")); EPackage traceMM = null; if (listFiles.length > 0) { File tracesFile = listFiles[0]; traceMM = (EPackage) resourceSet.getResource(URI.createFileURI(tracesFile.getCanonicalPath()), true) .getContents().get(0); String[] extraURIs = { URI.createFileURI(tracesFile.getCanonicalPath()).toString() }; EPackageUtils.registerPackageAndAllSubPackages(traceMM, resourceSet.getPackageRegistry(), extraURIs); } return traceMM; } public Resource applyHenshinTransformation(String inputModelPath, String outputModelPath) throws FileNotFoundException, IOException { LOGGER.info("Executing Henshin Transformation"); LOGGER.info(" input: {}", inputModelPath); LOGGER.info(" output: {}", outputModelPath); File inFile = new File(inputModelPath); Resource inputRes = resourceSet.getResource(URI.createFileURI(inFile.getCanonicalPath()), true); Engine engine = new EngineImpl(); Module henshinModule = loadHenshinTransformation(); Unit mainUnit = henshinModule.getUnit("Main"); ApplicationMonitor monitor = new ApplicationMonitor() { @Override public void notifyUndo(UnitApplication application, boolean succeess) { // TODO Auto-generated method stub } @Override public void notifyRedo(UnitApplication application, boolean success) { // TODO Auto-generated method stub } @Override public void notifyExecute(UnitApplication application, boolean success) { String name = application.getUnit().toString(); if (success) { LOGGER.debug(" Applied {}", name); if (application instanceof RuleApplication) { RuleApplication ruleApp = (RuleApplication) application; LOGGER.debug(" {}", ruleApp.getCompleteMatch().toString()); } } else { LOGGER.debug(" Failed to apply {}", name); } EGraph graph = application.getEGraph(); graph.size(); // if (application instanceof RuleApplication || success // && name.contains("i1, j1")) { // LOGGER.debug(" Applied {} with match\n{}", name, // ((RuleApplication) application).getCompleteMatch()); // } else { // LOGGER.debug(" Applied {}", name); // } } @Override public boolean isUndo() { // TODO Auto-generated method stub return false; } @Override public boolean isCanceled() { // TODO Auto-generated method stub return false; } @Override public void cancelAndUndo() { // TODO Auto-generated method stub } @Override public void cancel() { // TODO Auto-generated method stub } }; InterpreterUtil.applyToResource(new AssignmentImpl(mainUnit), engine, inputRes, monitor); File outFile = new File(outputModelPath); Resource outputRes = resourceSet.createResource(URI.createFileURI(outFile.getCanonicalPath())); outputRes.getContents().addAll(inputRes.getContents()); outputRes.save(xmiSaveOptions); return outputRes; } public void compareModels(Resource left, Resource right) throws IOException { LOGGER.info("Comparing output models"); IEObjectMatcher matcher = DefaultMatchEngine.createDefaultEObjectMatcher(UseIdentifiers.NEVER); IComparisonFactory comparisonFactory = new DefaultComparisonFactory(new DefaultEqualityHelperFactory()); IMatchEngine.Factory matchEngineFactory = new MatchEngineFactoryImpl(matcher, comparisonFactory); matchEngineFactory.setRanking(20); IMatchEngine.Factory.Registry matchEngineRegistry = new MatchEngineFactoryRegistryImpl(); matchEngineRegistry.add(matchEngineFactory); EMFCompare comparator = EMFCompare.builder().setMatchEngineFactoryRegistry(matchEngineRegistry).build(); IComparisonScope scope = EMFCompare.createDefaultScope(left, right); Comparison comp = comparator.compare(scope); File rightFile = new File(right.getURI().path()); File diffFile = new File(rightFile.getParentFile(), FilenameUtils.getBaseName(rightFile.getPath()) + ".diff"); Resource diffRes = resourceSet.createResource(URI.createFileURI(diffFile.getPath())); LOGGER.info("Writing diff to {}", diffFile.getPath()); diffRes.getContents().add(comp); diffRes.save(xmiSaveOptions); EList<Diff> differences = comp.getDifferences(); if (IGNORE_EREF_ORDERING) { for (Diff diff : differences) { assertTrue("Found non-move diff: " + diff.toString(), diff.getKind() == DifferenceKind.MOVE); } } else { assertTrue("Found diffs: " + diffFile.getPath(), differences.size() == 0); } } protected EPackage getOutputMMEPkg() throws IOException { return EPackageUtils.loadDynamicEcore(resourceSet, getOutputMM().getCanonicalPath()).get(0); } protected File getOutputMM() { return outputMMDir.listFiles((FilenameFilter) new SuffixFileFilter(".ecore"))[0]; } protected EPackage getInputMMEPkg() throws IOException { return EPackageUtils.loadDynamicEcore(resourceSet, getInputMM().getCanonicalPath()).get(0); } protected File getInputMM() { return inputMMDir.listFiles((FilenameFilter) new SuffixFileFilter(".ecore"))[0]; } }