/*******************************************************************************
* 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.io.Console;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.Job;
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.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.handlers.HandlerUtil;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class TransHandler extends AbstractHandler implements IHandler {
public static final String TRANSLATION_JOB_FAMILY = "lu.uni.snt.translationJobFamily";
protected static boolean useOutputFolder;
private Job waitForSave;
private TranslationJobCreator[] creator = new TranslationJobCreator[MAX_TRANSFORMATION_THREADS];
public static int MAX_TRANSFORMATION_THREADS = (Runtime.getRuntime().availableProcessors() <= 1 ? 1 : Runtime.getRuntime().availableProcessors());
public static int MEMORY_NEEDED_FOR_TRANSLATION_PER_THREAD = 100;
private static Object[] lockObjects;
private int idx = 0;
private ConcurrentLinkedQueue<IFile> inputFiles;
private Hashtable<String,String> options = new Hashtable<String, String>();
private static final String CONFIG_RUNTIME_MODULE_NAME = "de.tub.tfs.henshin.tgg.interpreter.config.TggInterpreterConfigRuntimeModule";
private static com.google.inject.Module CONFIG_RUNTIME_MODULE = null;
private static Injector CONFIG_INJECTOR = null;
private Resource CONFIG_RESOURCE;
private static boolean inited;
static {
int maxThreadsInMemory = (int) (Runtime.getRuntime().maxMemory() / (MEMORY_NEEDED_FOR_TRANSLATION_PER_THREAD *1024 * 1024));
if (maxThreadsInMemory < MAX_TRANSFORMATION_THREADS && maxThreadsInMemory > 0){
MAX_TRANSFORMATION_THREADS = maxThreadsInMemory;
}
lockObjects = new Object[MAX_TRANSFORMATION_THREADS];
for (int i = 0; i < lockObjects.length; i++) {
lockObjects[i] = new Object();
}
Class<?> module = null;
try {
module = Class.forName(CONFIG_RUNTIME_MODULE_NAME);
CONFIG_RUNTIME_MODULE = (com.google.inject.Module) module.newInstance();
} catch (Exception e) {
module = null;
}
}
public Hashtable<String,String> getOptions() {
return options;
}
public void setOptions(Hashtable<String,String> options) {
this.options = options;
}
public Job getWaitForSave() {
return waitForSave;
}
public void setWaitForSave(Job waitForSave) {
this.waitForSave = waitForSave;
}
protected void loadConfigFile(IPath path) {
if (CONFIG_RESOURCE == null)
return;
try {
CONFIG_RESOURCE.unload();
} catch (Exception e){
}
URI uri = null;
if (path.getDevice() == null){
uri = URI.createPlatformResourceURI(path.toString() + "/config/Grammar.config",true);
} else {
uri = URI.createFileURI(path.toString() + "/config/Grammar.config");
}
CONFIG_RESOURCE.setURI(uri);
try {
CONFIG_RESOURCE.load(null);
EObject eObject = CONFIG_RESOURCE.getContents().get(0);
TreeIterator<EObject> eAllContents = eObject.eAllContents();
int entries = 0;
synchronized (getOptions()) {
while (eAllContents.hasNext()){
entries++;
EObject next = eAllContents.next();
EStructuralFeature keyFeature = next.eClass().getEStructuralFeature("key");
EStructuralFeature valueFeature = next.eClass().getEStructuralFeature("value");
if (keyFeature != null && valueFeature != null){
String value = (String) next.eGet(valueFeature);
if (value.contains("%DATE%")){
Date now = new Date();
SimpleDateFormat format = new SimpleDateFormat("dd-MMM-yyyy");
value = value.replace("%DATE%", format.format(now));
}
getOptions().put((String) next.eGet(keyFeature), value);
}
}
}
if (entries > 0){
System.out.println("Config file at " + uri.toFileString() + " has benn loaded.");
}
} catch (IOException e) {
try {
if (!path.equals(path.removeLastSegments(1)))
loadConfigFile(path.removeLastSegments(1));
} catch (Exception ex){
}
}
}
private void waitForJob(final Job loadGrammarJob,final Object[] locks) {
Job waitJob = new Job("Wait for Loading Grammars") {
private Job joinedJob = loadGrammarJob;
private Object[] lockedObjects = locks;
private int idx = 0;
private void joinJob(){
if (idx == lockedObjects.length){
try {
joinedJob.join();
} catch (InterruptedException e) {
}
System.out.println(joinedJob.getName() + " finished loading Grammars.");
} else {
synchronized (lockedObjects[idx]) {
idx++;
joinJob();
}
}
}
@Override
protected IStatus run(IProgressMonitor monitor) {
joinJob();
return Status.OK_STATUS;
}
};
waitJob.schedule();
}
@SuppressWarnings("unchecked")
public Object execute(ExecutionEvent event) throws ExecutionException {
// Get currently active shell:
useOutputFolder=false;
Shell shell = null;
if (event != null){
shell = HandlerUtil.getActiveWorkbenchWindow(event).getShell();
} else {
shell = new Shell();
}
// Load the transformation units during first run:
if (!inited){
inited = true;
if (CONFIG_RUNTIME_MODULE != null){
CONFIG_INJECTOR = Guice.createInjector(CONFIG_RUNTIME_MODULE);
try {
CONFIG_RESOURCE = (Resource) CONFIG_INJECTOR.getInstance(Class.forName("org.eclipse.xtext.resource.XtextResource"));
} catch (ClassNotFoundException e) {
}
}
}
LoadHandler.updateGrammars();
Job loadGrammarJob = LoadHandler.getLoadGrammarJob();
if (loadGrammarJob != null){
waitForJob(loadGrammarJob,lockObjects);
}
if (LoadHandler.trSystems == null) {
MessageDialog.openError(shell, "No Translator loaded",
"Please load the translator.");
}
Queue<IFile> transQueue = retrieveFilesForTranslation(event);
System.out.println(transQueue);
// Start jobs for all input files:
long execution_Begin=System.currentTimeMillis();
getOptions().put("_StartTime", ""+System.nanoTime());
final Map<String, ExecutionTimes> executionTimesMap = new TreeMap<String, ExecutionTimes>();
idx = 0;
inputFiles = new ConcurrentLinkedQueue<IFile>((List<IFile>) transQueue);
System.out.println(inputFiles);
for (int i = 0; i < creator.length; i++) {
idx = i;
creator[i] = new TranslationJobCreator() {
private int index = idx;
@Override
public Job createJob() {
//TranslationJob job = new TranslationJob(TransHandler.this, inputFiles,lockObjects[i]);
TranslationJob job = new TranslationJob(inputFiles,useOutputFolder,getOptions(),lockObjects[index]);
job.setTimesMap(executionTimesMap);
job.setPriority(Job.DECORATE);
return job;
}
};
}
for (int i = 0; i < creator.length; i++) {
if (creator[i] != null)
creator[i].createJob().schedule();
creator[i] = null;
}
long execution_End=0;
IJobManager jobMan = Job.getJobManager();
// wait for all jobs to complete
while(jobMan.find(TRANSLATION_JOB_FAMILY).length!=0 || !inputFiles.isEmpty()){
try {
if (!Display.getDefault().readAndDispatch())
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
execution_End=System.currentTimeMillis();
System.out.println("\n" + "==================================================================================== \n"
+ "Summary of execution times in ms (parsing, transformation, serialisation) \n"
+ "====================================================================================");
for (String file : executionTimesMap.keySet()) {
ExecutionTimes times=executionTimesMap.get(file);
System.out.println(file + " : " + times.overall + " ( " + times.stage1 + ", " + times.stage2 + ", " + times.stage3 + " )");
}
System.out
.println( "------------------------------------------------------------------------------------ \r\n"
+ "overall execution time (parallel processing)"
+ " : " + (execution_End - execution_Begin) +"\n"
+ "====================================================================================");
return null;
}
protected Queue<IFile> retrieveFilesForTranslation(ExecutionEvent event) {
// Find files to translate:
Queue<IFile> transQueue = new LinkedList<IFile>();
ISelection sel = HandlerUtil.getCurrentSelection(event);
if (sel != null && sel instanceof IStructuredSelection) {
IStructuredSelection structSel = (IStructuredSelection) sel;
for (Iterator<Object> it = structSel.iterator(); it.hasNext();) {
Object obj = it.next();
if (obj instanceof IFile) {
IFile file = (IFile) obj;
transQueue.add(file);
IPath path = file.getFullPath().removeLastSegments(1);
loadConfigFile(path);
}
if (obj instanceof IContainer) {
useOutputFolder=true;
IResource[] resArr;
try {
resArr = ((IContainer) obj).members();
for (int i=0; i<resArr.length; i++) {
if (resArr[i] instanceof IFile) {
IFile file = (IFile) resArr[i];
transQueue.add(file);
IPath path = file.getFullPath().removeLastSegments(1);
loadConfigFile(path);
}
}
} catch (CoreException e) {
e.printStackTrace();
}
}
}
}
return transQueue;
}
public static void waitForEnter(String message, Object... args) {
Console c = System.console();
if (c != null) {
// printf-like arguments
if (message != null)
c.format(message, args);
c.format("\nPress ENTER to proceed.\n");
c.readLine();
}
}
}