blob: 88176069a5217e8e61f97301d59f030a5a08c21c [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2017-2020 Robert Bosch GmbH and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Robert Bosch GmbH - initial API and implementation
********************************************************************************
*/
package org.eclipse.app4mc.sca2amalthea.ui.handlers;
import java.util.Timer;
import java.util.TimerTask;
import org.eclipse.app4mc.sca.logging.manager.Logmanager;
import org.eclipse.app4mc.sca2amalthea.llvm.headless.GenerateAmaltheaModelFromLLVM;
import org.eclipse.app4mc.sca2amalthea.ui.Activator;
import org.eclipse.app4mc.sca2amalthea.utils.UtilityForProcessHandling;
import org.eclipse.app4mc.sca2amalthea.utils.constants.SCA2AmaltheaConstants;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.internal.resources.Resource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
/**
*/
@SuppressWarnings("restriction")
public class SCAToAmaltheaHandler extends AbstractHandler {
private String cFilePath = "";
private String traverseASTPath = "";
private String outPutPath = "";
private String taskListFile = "";
private String headerTextFilePath = "";
private String buildCmdLogFilePath = "";
private String lockfunctionFile = "";
private boolean isStructMemberEnabled = false;
private volatile Boolean isGenerationDone = Boolean.FALSE;
private final Object mutex = new Object();
private Job currentJob = null;
private boolean confirmation = true;
private Shell currentShell;
private static String infoMessage;
private static String confirmationMessage;
private static String title;
private static int timerDelay;
private static int timerPeriod;
/**
* Sets the timer delay for the timer
*
* @param timerDelay time delay in milliseconds.
*/
public static void setTimerDelay(final int timerDelay) {
SCAToAmaltheaHandler.timerDelay = timerDelay;
}
/**
* Returns the timer delay that was set.
*
* @return timer delay.
*/
public static int getTimerDelay() {
return SCAToAmaltheaHandler.timerDelay;
}
/**
* Sets the time period after which the timer task would be executed.
*
* @param timerPeriod time period in milliseonds.
*/
public static void setTimerPeriod(final int timerPeriod) {
SCAToAmaltheaHandler.timerPeriod = timerPeriod;
}
/**
* Returns the time period that was set.
*
* @return timer period.
*/
public static int getTimerPeriod() {
return SCAToAmaltheaHandler.timerPeriod;
}
@Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
IPreferenceStore preferenceStore = org.eclipse.app4mc.sca2amalthea.utils.Activator.getDefault().getPreferenceStore();
this.currentShell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
if (event != null) {
ISelection selection = HandlerUtil.getCurrentSelection(event);
if (((TreeSelection) selection).getFirstElement() instanceof Resource) {
Resource resource = (Resource) ((TreeSelection) selection).getFirstElement();
this.cFilePath = resource.getLocation().toString();
this.isStructMemberEnabled = preferenceStore.getBoolean(SCA2AmaltheaConstants.ENABLE_STRUCT_MEMBER);
}
}
this.traverseASTPath = preferenceStore.getString(SCA2AmaltheaConstants.AST_PATH);
this.taskListFile = preferenceStore.getString(SCA2AmaltheaConstants.TASK_INFO);
this.headerTextFilePath = preferenceStore.getString(SCA2AmaltheaConstants.HDIR_LIST);
this.buildCmdLogFilePath = preferenceStore.getString(SCA2AmaltheaConstants.BLOG);
this.lockfunctionFile = preferenceStore.getString(SCA2AmaltheaConstants.LOCK_INFO);
if (preferenceStore.getBoolean(SCA2AmaltheaConstants.ENABLE_OPTIONAL_FIELDS)) {
this.outPutPath = preferenceStore.getString(SCA2AmaltheaConstants.OUTPUT_PATH);
}
else {
this.outPutPath = preferenceStore.getDefaultString(SCA2AmaltheaConstants.OUTPUT_PATH);
}
if(this.traverseASTPath.isEmpty()){
MessageDialog.openError(this.currentShell, "Error Amalthea model generation", "Path to LLVM executable is not configured in sca2Amalthea preferences");
}
else{
if (UtilityForProcessHandling.getCurrentRunningProcess() == null) {
createAndExecuteJobForModelGeneration();
}
else {
String information = "The generation of 2 models at the same time is not allowed";
this.currentShell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MessageDialog.openInformation(this.currentShell, "Operation not allowed", information);
Logmanager.getInstance().log(information);
}
}
return null;
}
/**
*
*/
private void createAndExecuteJobForModelGeneration() {
Job job = new Job("AMALTHEA model generation") {
@Override
public IStatus run(final IProgressMonitor monitor) {
final SubMonitor subMonitor = SubMonitor.convert(monitor, 600);
Thread progressMonitorObserverThread = null;
boolean isPopupToBeDisplayed = false;
try {
progressMonitorObserverThread = createInfiniteProgressMonitor(subMonitor);
progressMonitorObserverThread.start();
GenerateAmaltheaModelFromLLVM generator = new GenerateAmaltheaModelFromLLVM(
SCAToAmaltheaHandler.this.cFilePath, SCAToAmaltheaHandler.this.outPutPath,
SCAToAmaltheaHandler.this.traverseASTPath, SCAToAmaltheaHandler.this.taskListFile,
SCAToAmaltheaHandler.this.headerTextFilePath, SCAToAmaltheaHandler.this.buildCmdLogFilePath,
SCAToAmaltheaHandler.this.lockfunctionFile,
SCAToAmaltheaHandler.this.isStructMemberEnabled);
setInfoMessage("The time required to generate the Amalthea model depends on the size of the PVER.");
setTitle("Information-Amalthea Model Generation");
Display.getDefault().syncExec(new InfoPopUp());
startTimer();
int returncode = generator.run();
synchronized (SCAToAmaltheaHandler.this.mutex) {
SCAToAmaltheaHandler.this.isGenerationDone = true;
}
// check the exit status of the process and show a information popup
if ((returncode != 0) || (UtilityForProcessHandling.getCurrentRunningProcess().exitValue() != 0)) {
if (SCAToAmaltheaHandler.this.confirmation) {
setInfoMessage("There was some error while parsing c files or when generating the AMALTHEA model.");
setTitle("Error");
Display.getDefault().syncExec(new InfoPopUp());
}
else {
SCAToAmaltheaHandler.this.confirmation = true;
}
UtilityForProcessHandling.setCurrentRunningProcess(null);
}
else {
isPopupToBeDisplayed = true;
}
}
catch (Exception e) {
Logmanager.getInstance().logException(this.getClass(), e, Activator.PLUGIN_ID);
if (progressMonitorObserverThread != null) {
waitForThread(progressMonitorObserverThread);
}
subMonitor.done();
return Status.CANCEL_STATUS;
}
waitForThread(progressMonitorObserverThread);
subMonitor.done();
if (isPopupToBeDisplayed) {
setInfoMessage("Amathea model generation completed");
setTitle("Amathea model generated");
Display.getDefault().syncExec(new InfoPopUp());
}
return new Status(IStatus.OK, Activator.PLUGIN_ID, "AMALTHEA model generation completed");
}
/**
* @param t
*/
private void waitForThread(final Thread t) {
try {
if (t != null) {
t.join();
}
}
catch (InterruptedException e) {
Logmanager.getInstance().log(e.getMessage());
}
}
};
this.currentJob = job;
job.schedule();
}
/**
* @param subMonitor
*/
private Thread createInfiniteProgressMonitor(final SubMonitor subMonitor) {
return new InfiniteProgressMonitorObserver(subMonitor);
}
class InfiniteProgressMonitorObserver extends Thread {
private String message = "Terminating AMALTHEA model generation job";
private final SubMonitor subMonitor;
/**
* @param subMonitor monitor which will be observed
*/
public InfiniteProgressMonitorObserver(final SubMonitor subMonitor) {
super();
this.subMonitor = subMonitor;
}
@Override
public void run() {
this.message = runLogarithmicWaitOnProgressMonitor();
terminateMonitorIn10Secondes();
UtilityForProcessHandling.setCurrentRunningProcess(null);
UtilityForProcessHandling.setModelGenerationcancelled(false);
SCAToAmaltheaHandler.this.isGenerationDone = false;
}
/**
* @param subMonitor
* @param message
* @return
*/
private String runLogarithmicWaitOnProgressMonitor() {
String messageToRenameJob = "Terminating AMALTHEA model generation job";
boolean isProcessCompleted = false;
int advancementCounter = 0;
while (!isProcessCompleted) {
if (this.subMonitor.isCanceled()) {
synchronized (SCAToAmaltheaHandler.this.mutex) {
SCAToAmaltheaHandler.this.isGenerationDone = true;
}
Process p = UtilityForProcessHandling.getCurrentRunningProcess();
p.destroyForcibly();
UtilityForProcessHandling.setCurrentRunningProcess(null);
UtilityForProcessHandling.setModelGenerationcancelled(true);
messageToRenameJob = "Cancelling the model generation job";
}
try {
this.subMonitor.worked(1);
advancementCounter++;
if ((advancementCounter % 300) == 0) {
advancementCounter = 1;
this.subMonitor.setWorkRemaining(600);
}
Thread.sleep(1000);
}
catch (InterruptedException e) {
Logmanager.getInstance().log(e.getMessage());
}
synchronized (SCAToAmaltheaHandler.this.mutex) {
isProcessCompleted = SCAToAmaltheaHandler.this.isGenerationDone;
}
}
return messageToRenameJob;
}
/**
* @param subMonitor
* @param message
*/
private void terminateMonitorIn10Secondes() {
int numberOfSecondUntilEnd = 10;
this.subMonitor.setWorkRemaining(numberOfSecondUntilEnd);
this.subMonitor.setTaskName(this.message);
SCAToAmaltheaHandler.this.currentJob.setName(this.message);
while (numberOfSecondUntilEnd > 0) {
try {
this.subMonitor.worked(1);
Thread.sleep(1000);
}
catch (InterruptedException e) {
Logmanager.getInstance().log(e.getMessage());
}
--numberOfSecondUntilEnd;
}
}
}
/**
* Inner class to show a confirmation pop up.
*
*/
class ConfirmationPopUp implements Runnable {
@Override
public void run() {
SCAToAmaltheaHandler.this.confirmation =
MessageDialog.openConfirm(SCAToAmaltheaHandler.this.currentShell, title, confirmationMessage);
}
}
/**
* Inner class to show a information pop up.
*/
class InfoPopUp implements Runnable {
@Override
public void run() {
MessageDialog.openInformation(SCAToAmaltheaHandler.this.currentShell, title, infoMessage);
}
}
/**
* This method starts the timer.The timer is sceduled to run after every 15mins.Every time the timer runs it checks if
* the eclipse job is still alive. If so it pops up a confirmation dialog asking if the user wishes to continue. If
* the user wishes to continue the timer keeps running and keeps showing the popup after every 15 mins and if the user
* wishes to abort then it cancels the eclipse job, cancels the timer and kills the sca.exe process.If the eclipse job
* is not alive it cancels the timer.
*/
private void startTimer() {
if (getTimerDelay() == 0) {
setTimerDelay(40 * 60 * 1000);
}
if (getTimerPeriod() == 0) {
setTimerPeriod(40 * 60 * 1000);
}
Job eclipseJob = Job.getJobManager().currentJob();
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if ((eclipseJob.getThread() != null) && eclipseJob.getThread().isAlive()) {
setConfirmationMessage(
"The amalthea model generation job is still running.It might take some more time. Do you wish to continue? Press Ok to continue or cancel to abort");
setTitle("Amalthea Job status");
Display.getDefault().syncExec(new ConfirmationPopUp());
if (!SCAToAmaltheaHandler.this.confirmation) {
t.cancel();
eclipseJob.cancel();
Process p = UtilityForProcessHandling.getCurrentRunningProcess();
if (p != null) {
p.destroyForcibly();
}
}
}
else {
t.cancel();
}
}
}, getTimerDelay(), getTimerPeriod());
}
private static void setInfoMessage(final String message) {
SCAToAmaltheaHandler.infoMessage = message;
}
private static void setTitle(final String message) {
SCAToAmaltheaHandler.title = message;
}
private static void setConfirmationMessage(final String message) {
SCAToAmaltheaHandler.confirmationMessage = message;
}
}