/******************************************************************************* * Copyright (c) 2010-2015 Henshin developers. 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: * TU Berlin, University of Luxembourg, SES S.A. *******************************************************************************/ package de.tub.tfs.henshin.tgg.interpreter.gui; import java.lang.reflect.Field; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.PriorityQueue; import java.util.Vector; import java.util.concurrent.ConcurrentLinkedQueue; import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.emf.common.notify.Adapter; 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.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.Resource.Diagnostic; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.util.Diagnostician; import org.eclipse.emf.ecore.util.EContentsEList; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.henshin.interpreter.Engine; import org.eclipse.emf.henshin.model.IndependentUnit; import org.eclipse.emf.henshin.model.Module; import org.eclipse.emf.henshin.model.Rule; import org.eclipse.emf.henshin.model.Unit; import org.eclipse.jdt.core.formatter.CodeFormatter; import org.eclipse.jdt.internal.formatter.DefaultCodeFormatter; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.text.edits.TextEdit; import de.tub.tfs.henshin.tgg.TGG; import de.tub.tfs.henshin.tgg.interpreter.config.JavaScriptTggInitializer; import de.tub.tfs.henshin.tgg.interpreter.impl.TggEngineImpl; import de.tub.tfs.henshin.tgg.interpreter.impl.TggTransformationImpl; import de.tub.tfs.henshin.tgg.interpreter.postprocessing.AbstractPostProcessor; import de.tub.tfs.henshin.tgg.interpreter.postprocessing.AbstractPostProcessorFactory; import de.tub.tfs.henshin.tgg.interpreter.util.NodeUtil; // //... //class FamilyJob extends Job { // ... //} public class TranslationJob extends Job { public static String DEFAULT_EXT = "out"; protected String targetExt = ""; protected TggTransformationImpl tggTransformation; protected TggEngineImpl emfEngine; protected URI inputURI; protected URI xmiURI; protected URI outputURI; protected TGG module= null; //protected String trFileName; protected List<EObject> inputEObjects=null; protected Map<String, ExecutionTimes> executionTimesMap = null; private ConcurrentLinkedQueue<IFile> inputFiles; private IFile inputFile; private Object lock; private static boolean debug = true; private boolean useOutputFolder; private Map<String,String> engineOptions; private static HashMap<?,?> sharedObjectRegistry = new HashMap(); private boolean useOutputFolder2; public TranslationJob(ConcurrentLinkedQueue<IFile> inputFiles, boolean useOutputFolder,Map<String,String> options,Object lock) { super("Translating " + ( inputFiles.peek() == null ? "" : inputFiles.peek().getName())); this.engineOptions = options; debug = "true".equals(this.engineOptions.get("Debug")); inputFile = inputFiles.poll(); this.inputFiles = inputFiles; this.useOutputFolder = useOutputFolder; if (inputFile != null){ if (inputFile.getFullPath().getDevice() == null){ this.inputURI = URI.createPlatformResourceURI(inputFile. getFullPath().toString(), true); } else { this.inputURI = URI.createFileURI(inputFile.getFullPath().toString()); } //this.inputURI = URI.createPlatformResourceURI(inputFile. // getFullPath().toString(), true); this.xmiURI = this.inputURI.trimFileExtension(). appendFileExtension("xmi"); this.lock = lock; } else { this.lock = lock; } } protected IStatus run(IProgressMonitor monitor) { if (inputFile == null) return Status.OK_STATUS; if (this.getThread() != null){ this.getThread().setName("TranslationJob " + this.getThread().getName()); } synchronized (lock) { // check that grammar is loaded if (LoadHandler.trSystems.size()==0){ return new Status(RUNNING, "tgg-plugin", "Transformation System was not loaded"); } // clear list of rules from previous executions //TggUtil.initClassConversions(); ExecutionTimes executionTimes = new ExecutionTimes(); try { monitor.beginTask("Translating " + inputURI.lastSegment(), 3); System.out.println("====="); System.out.println("Translating: " + inputURI.lastSegment()); long time0 = System.currentTimeMillis(); monitor.subTask("Loading input"); ResourceSet resSet = new ResourceSetImpl(); HashMap<String,Object> options = new HashMap<String,Object>(); options.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); options.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); options.put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); options.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); options.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); options.put(XMLResource.OPTION_USE_LEXICAL_HANDLER, Boolean.TRUE); resSet.getLoadOptions().putAll(options); Resource res = resSet.getResource(inputURI, true); // Print out syntax parsing errors // and abort translation if errors occur EList<Diagnostic> errors = res.getErrors(); if (!errors.isEmpty()) { String msg = "===========================\n"; msg += "Translation failed. No output was generated. The following syntax errors occured while parsing:\n"; for (Diagnostic d : errors) { msg += "(" + inputURI.lastSegment() + ") line " + d.getLine() + ": " + d.getMessage() + "\n"; msg += "-------------------------------\n"; } msg += "===========================\n"; throw new RuntimeException(msg); } EObject inputRoot = (EObject) res.getContents().get(0); inputEObjects = res.getContents(); // add all of root tggTransformation = new TggTransformationImpl(); tggTransformation.setStartTime(Long.parseLong(engineOptions.get("_StartTime"))); tggTransformation.setInput(inputEObjects); tggTransformation.opRulesList.clear(); // Validate input AST based on custom constraints org.eclipse.emf.common.util.Diagnostic validation_result = Diagnostician.INSTANCE.validate(inputRoot); if (!validation_result.getChildren().isEmpty()) { String msg = "===========================\n"; msg += "Translation failed. No output was generated. The following syntax errors occured while parsing:\n"; for (org.eclipse.emf.common.util.Diagnostic d : validation_result.getChildren()) { msg += "(" + inputURI.lastSegment() + ") " + d.getMessage() + " (" + d.getSource() + ")\n"; msg += "-------------------------------\n"; } msg += "===========================\n"; throw new RuntimeException(msg); } emfEngine = tggTransformation.getEmfEngine(); JavaScriptTggInitializer.registerWithScriptingEngine(emfEngine.getScriptEngine()); emfEngine.getScriptEngine().put("emfEngine", emfEngine); Bindings bindings = emfEngine.getScriptEngine().getBindings(ScriptContext.ENGINE_SCOPE); synchronized (this.engineOptions) { String init = this.engineOptions.get("Initialisation"); if (init == null){ for (Entry<String, String> entry : this.engineOptions.entrySet()) { bindings.put(entry.getKey(), entry.getValue()); } } else { for (Entry<String, String> entry : this.engineOptions.entrySet()) { bindings.put(entry.getKey(), entry.getValue()); } init = this.engineOptions.get("Initialisation"); if (init != null){ if (init.startsWith("{*")){ init = init.substring(2,init.length()-2); } try { //org.eclipse.core.runtime.Platform emfEngine.getScriptEngine().eval(init); } catch (Throwable e) { System.err.println("Error while initialising Grammar!"); e.printStackTrace(); } this.engineOptions.remove("Initialisation"); } } } this.emfEngine.updateOptions(); long time1 = System.currentTimeMillis(); long stage1 = time1 - time0; System.out.println("Stage 1 -- Loading: " + stage1 + " ms"); monitor.worked(1); if (monitor.isCanceled()) { monitor.done(); return Status.CANCEL_STATUS; } Iterator<TGG> moduleIt = LoadHandler.trSystems.iterator(); List<String> fileNames = LoadHandler.trFileNames; boolean foundApplicationForRound = false; boolean foundApplicationForModule = false; boolean newMatchesArePossible = true; boolean initialRound = true; // execute all modules as long as there are matches TGG module=null; ArrayList<Module> modules = new ArrayList<Module>(); ArrayList<List<Rule>> opRules = new ArrayList<List<Rule>>(); // retrieve modules and lists of operational rules while (moduleIt.hasNext()) { module = moduleIt.next(); modules.add(module); opRules.add(getOpRules(module)); //for (Module module2 : priorModules) { // opRules.add(getOpRules(module2)); //} //priorModules.add(module); } while (newMatchesArePossible) { foundApplicationForRound = false; // execute all modules once for (int modulePos=0;modulePos<modules.size();modulePos++) { tggTransformation.setOpRuleList(opRules.get(modulePos)); tggTransformation.setNullValueMatching(modules.get(modulePos) .isNullValueMatching()); String trFileName = fileNames.get(modulePos); monitor.subTask("Applying " + trFileName ); if (debug) System.out.println("Applying " + trFileName); foundApplicationForModule = tggTransformation.applyRules(monitor,"Applying " + trFileName,debug); monitor.worked(1); if (monitor.isCanceled()) { monitor.done(); return Status.CANCEL_STATUS; } foundApplicationForRound = foundApplicationForRound || foundApplicationForModule; for (int i = 0; i < modulePos; i++) { tggTransformation.setOpRuleList(opRules.get(i)); tggTransformation.setNullValueMatching(modules.get(i) .isNullValueMatching()); trFileName = fileNames.get(i); monitor.subTask("Applying " + trFileName ); if (debug) System.out.println("Applying " + trFileName); foundApplicationForModule = tggTransformation.applyRules(monitor,"Applying " + trFileName,debug); monitor.worked(1); if (monitor.isCanceled()) { monitor.done(); return Status.CANCEL_STATUS; } foundApplicationForRound = foundApplicationForRound || foundApplicationForModule; } } if (!initialRound && foundApplicationForRound) System.out .println("Warning: some ruleapplications depend on rules that are applied in a subsequent module. This can cause inefficient executions. " + "Try to reorder the modules or rules."); initialRound = false; newMatchesArePossible = foundApplicationForRound; } // while (moduleIt.hasNext() && fileNames.hasNext()) { // module = moduleIt.next(); // trFileName = fileNames.next(); // addFTRules(module); // tggTransformation.setNullValueMatching(module.isNullValueMatching()); // // monitor.subTask("Applying " + trFileName); // // tggTransformation.applyRules(monitor,"Applying " + trFileName,debug); // monitor.worked(1); // if (monitor.isCanceled()) { // monitor.done(); // return Status.CANCEL_STATUS; // } // } if (monitor.isCanceled()) { monitor.done(); return Status.CANCEL_STATUS; } long time2 = System.currentTimeMillis(); long stage2 = time2 - time1; System.out.println("Stage 2 -- Transformation: " + stage2 + " ms"); monitor.subTask("Saving result"); List<EObject> roots = tggTransformation.getGraph().getRoots(); Iterator<EObject> it = roots.iterator(); EObject targetRoot = null; EObject current = null; //TGG tgg = LoadHandler.layoutModels.get(0); boolean targetRootFound=false; Class<?> targetClass = null; if (this.engineOptions.containsKey("TargetClass")){ try { String targetClassScript = this.engineOptions.get("TargetClass"); if (targetClassScript.startsWith("{*")){ targetClassScript = targetClassScript.substring(2,targetClassScript.length() - 2); } targetClass = (Class) emfEngine.getScriptEngine().eval(targetClassScript); } catch (Throwable e) { e.printStackTrace(); } } while (it.hasNext() && !targetRootFound) { current = it.next(); if (NodeUtil.isTargetClass(module, current.eClass())) { targetRoot = current; targetRootFound = true; if (targetClass != null && !targetClass.isInstance(targetRoot)){ targetRoot = null; targetRootFound = false; } } } String moduleName = module.getName(); String[] moduleNameComponents = moduleName.split("2"); if(moduleNameComponents.length==2) targetExt=moduleNameComponents[1]; if (targetExt != null && targetExt.isEmpty()){ targetExt = DEFAULT_EXT; } if (this.engineOptions.containsKey("TargetExtension")){ targetExt = this.engineOptions.get("TargetExtension"); } if (targetRoot != null) { PriorityQueue<AbstractPostProcessorFactory> postProcessorFactories = getPostProcessorFactories(); PriorityQueue<AbstractPostProcessorFactory> postProcessorFactories2 = new PriorityQueue<AbstractPostProcessorFactory>(postProcessorFactories); EObject newRoot = targetRoot; while (!postProcessorFactories2.isEmpty()){ AbstractPostProcessorFactory postProcessorFactory = postProcessorFactories2.poll(); if (postProcessorFactory.isValid(inputURI)){ AbstractPostProcessor postProcessor = postProcessorFactory.createPostProcessor(newRoot); postProcessor.registerSharedObjects(sharedObjectRegistry); newRoot = postProcessor.process(); } } targetRoot = newRoot; // remove all backreferences TreeIterator<EObject> nodesIt = targetRoot.eAllContents(); EObject targetObject=targetRoot; //AbstractTarget tNode; removeT2C(targetObject); while(nodesIt.hasNext()){ targetObject=nodesIt.next(); removeT2C(targetObject); } if (targetExt == null) { Export.saveModel(resSet, roots, xmiURI); } else{ this.outputURI = this.inputURI.trimFileExtension() .appendFileExtension(targetExt); Export.saveTargetModel(resSet, targetRoot, outputURI,postProcessorFactories,inputURI,sharedObjectRegistry); } } else { System.out.println("No target root!"); } monitor.worked(1); if(useOutputFolder){ this.outputURI = outputURI.trimSegments(1).appendSegment("output").appendSegment(outputURI.lastSegment()); } Import.unloadModel(resSet, outputURI); resSet.getResource(inputURI, true).unload(); try { if (outputURI.isPlatformResource()) { String platformString = outputURI.toPlatformString(true); IFile file = (IFile) ResourcesPlugin.getWorkspace().getRoot(). findMember(platformString); Path path = Paths.get(file.getLocation().toString()); Charset charset = StandardCharsets.UTF_8; String content = new String(Files.readAllBytes(path), charset); CodeFormatter cf = new DefaultCodeFormatter(); TextEdit te = cf.format(CodeFormatter.K_UNKNOWN, content, 0, content.length(), 0, null); IDocument dc = new Document(content); te.apply(dc); Files.write(path, dc.get().getBytes(charset)); } } catch (Exception e) { //e.printStackTrace(); } long time3 = System.currentTimeMillis(); long stage3 = time3 - time2; System.out.println("Stage 3 -- Saving: " + stage3 + " ms"); executionTimes.stage1=stage1; executionTimes.stage2=stage2; executionTimes.stage3=stage3; executionTimes.overall=stage1+stage2+stage3; } finally { monitor.done(); } // put the execution time for this file in the global list synchronized(executionTimesMap) { executionTimesMap.put(inputURI.path(), executionTimes); } for (Module m : LoadHandler.trSystems) { cleanGrammar(m); } if (emfEngine != null) emfEngine.clearCache(); if (this.getThread() != null && this.getThread().getName().startsWith("TranslationJob ")){ this.getThread().setName(this.getThread().getName().replaceFirst("TranslationJob ", "")); } if (!monitor.isCanceled()){ // Start next Translation Job new TranslationJobCreator() { @Override public Job createJob() { TranslationJob job = new TranslationJob(inputFiles,useOutputFolder,engineOptions,lock); job.setTimesMap(executionTimesMap); job.setPriority(Job.DECORATE); return job; } }.createJob().schedule(); } return Status.OK_STATUS; } } protected void removeT2C(EObject targetObject) { EContentsEList.FeatureIterator featureIterator = (EContentsEList.FeatureIterator) targetObject .eCrossReferences().iterator(); EReference eReference = null; EReference t2cEReference = null; while (featureIterator.hasNext()) { featureIterator.next(); if (featureIterator.feature() instanceof EReference) { eReference = (EReference) featureIterator.feature(); if (eReference.getName().endsWith("2c")) t2cEReference = eReference; } } if (t2cEReference != null) targetObject.eUnset(t2cEReference); } public static void cleanGrammar(Module m){ TreeIterator<EObject> treeIterator = m.eAllContents(); while (treeIterator.hasNext()){ EObject eObject = treeIterator.next(); if (!eObject.eAdapters().isEmpty()) { for (Iterator<Adapter> itr = eObject.eAdapters().iterator();itr.hasNext();){ Adapter next = itr.next(); try { Field field = next.getClass().getDeclaredField("this$0"); field.setAccessible(true); Object object = field.get(next); if (object instanceof Engine){ itr.remove(); } } catch (Exception e){ e.printStackTrace(); } } } } } public void setTimesMap(Map<String, ExecutionTimes> executionTimesMap2) { this.executionTimesMap=executionTimesMap2; } public boolean belongsTo(Object family) { return family == TransHandler.TRANSLATION_JOB_FAMILY; } public void addFTRules(Module module) { if (module == null) return; String name_OP_RULE_FOLDER = "FTRuleFolder"; IndependentUnit opRuleFolder = (IndependentUnit) module.getUnit(name_OP_RULE_FOLDER); List<Rule> opRules = new Vector<Rule>(); getAllRules(opRules, opRuleFolder); tggTransformation.getOpRuleList().addAll(opRules); } private PriorityQueue<AbstractPostProcessorFactory> getPostProcessorFactories(){ PriorityQueue<AbstractPostProcessorFactory> postProcessorFactories = new PriorityQueue<AbstractPostProcessorFactory>(10,new Comparator<AbstractPostProcessorFactory>() { @Override public int compare(AbstractPostProcessorFactory o1, AbstractPostProcessorFactory o2) { return o1.getPriority() - o2.getPriority(); } }); IExtensionRegistry reg = Platform.getExtensionRegistry(); IExtensionPoint ep = reg.getExtensionPoint("de.tub.tfs.henshin.tgg.interpreter"); IExtension[] extensions = ep.getExtensions(); for (int i = 0; i < extensions.length; i++) { IExtension ext = extensions[i]; IConfigurationElement[] ce = ext.getConfigurationElements(); for (int j = 0; j < ce.length; j++) { try { AbstractPostProcessorFactory obj = (AbstractPostProcessorFactory) ce[j].createExecutableExtension("class"); postProcessorFactories.add(obj); } catch (CoreException e) { e.printStackTrace(); } } } return postProcessorFactories; } protected static void getAllRules(List<Rule> units,IndependentUnit folder){ for (Unit unit : folder.getSubUnits()) { if (unit instanceof IndependentUnit){ } else { units.add((Rule) unit); } } } protected static List<Rule> getOpRules(Module module){ if (module == null) return null; String name_OP_RULE_FOLDER = "FTRuleFolder"; IndependentUnit opRuleFolder = (IndependentUnit) module.getUnit(name_OP_RULE_FOLDER); List<Rule> opRules = new Vector<Rule>(); getAllRules(opRules, opRuleFolder); return opRules; } }