/* Copyright 2012-2015 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package eu.aniketos.securebpmn.validation;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants;
import org.activiti.designer.eclipse.extension.export.ExportMarshaller;
import org.activiti.designer.eclipse.preferences.PreferencesUtil;
import org.activiti.designer.eclipse.util.ExtensionPointUtil;
import org.activiti.designer.util.preferences.Preferences;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.satmc.SatmcLexer;
import org.antlr.satmc.SatmcParser;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import eu.aniketos.securebpmn.satmc.SatmcMessage;
import eu.aniketos.securebpmn.util.DialogUtil;
import eu.aniketos.securebpmn.util.SecurityUtil;
import eu.avantssar.satmc.SATMCPortType;
import eu.avantssar.satmc.SATMCService;
/**
* A Runnable that generates the ASLan file and analyzes it via SATMC for a
* given Diagram.
*
*
*/
public class ValidateAslanRunnable implements IRunnableWithProgress {
private Diagram diagram;
private boolean localValidation;
private SatmcMessage result;
/**
* Default constructor.
*
* @param diagram
* The diagram that should be validated.
* @param result
* The variable where the result is saved to.
* @param localValidation
* true if the local SATMC binary should be used, false for the
* SATMC web service.
*/
public ValidateAslanRunnable(Diagram diagram, SatmcMessage result,
boolean localValidation) {
this.diagram = diagram;
this.localValidation = localValidation;
this.result = result;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core
* .runtime.IProgressMonitor)
*/
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
try {
monitor.beginTask("Validating security properties", 10);
// get uri
URI uri = diagram.eResource().getURI();
URI platformUri = uri.trimFragment();
platformUri = platformUri.trimFileExtension();
platformUri = platformUri.appendFileExtension("aslan");
monitor.worked(1);
// generate file
monitor.subTask("Generating ASLan");
final ExportMarshaller marshaller = ExtensionPointUtil
.getExportMarshaller(ActivitiBPMNDiagramConstants.ASLAN_MARSHALLER_NAME);
if (marshaller == null) {
throw new IllegalArgumentException(
"Unable to invoke ExportMarshaller with name "
+ ActivitiBPMNDiagramConstants.ASLAN_MARSHALLER_NAME);
}
final IProgressMonitor subMonitor = new SubProgressMonitor(monitor,
2);
try {
marshaller.marshallDiagram(diagram, subMonitor);
} finally {
subMonitor.done();
}
// check for problem markers
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
final IFile diagramFile = workspace.getRoot().getFile(
new Path(diagram.eResource().getURI()
.toPlatformString(true)));
try {
if (diagramFile
.findMarkers(ExportMarshaller.MARKER_ID, true, 3).length > 0) {
Display.getDefault().syncExec(new Runnable() {
public void run() {
DialogUtil
.openMessageDialog(
"Export problems present",
"The diagram contains export problems! This might result in an outdated analysis result, you should fix the problems and run the analysis again.",
DialogUtil.WARNING);
}
});
}
} catch (CoreException e1) {
e1.printStackTrace();
}
// file validation
String res = "";
final String fileUri = getResource(platformUri).getLocation()
.toString();
if (localValidation) {
// call local binary and pass file path
monitor.subTask("Executing local SATMC binary");
try {
String pathToBinary = PreferencesUtil
.getStringPreference(Preferences.PATH_TO_SATMC_BINARY);
File workingDir = null;
if (pathToBinary.length() == 0) {
pathToBinary = "satmc";
} else {
int lastIndex = pathToBinary.lastIndexOf(System
.getProperty("file.separator"));
if (lastIndex > 0) {
workingDir = new File(pathToBinary.substring(0,
lastIndex));
}
}
String[] cmd = { pathToBinary, fileUri, "--max=80",
"--mutex=0"
};
res = cmdExec(cmd, workingDir);
} catch (IOException e) {
Display.getDefault().syncExec(new Runnable() {
public void run() {
DialogUtil
.openMessageDialog(
"SATMC Execution Error",
"Could not run SATMC. Try providing the full path to the executable file in the Activiti preferences.",
DialogUtil.ERROR);
}
});
e.printStackTrace();
monitor.worked(7);
monitor.done();
return;
}
} else {
// read file as string and call web service
monitor.subTask("Calling SATMC web service");
try {
final SATMCService service = new SATMCService();
final SATMCPortType port = service.getSATMCSOAPPort();
res = port.validate(SecurityUtil.readFileAsString(fileUri),
80, false, true, false, "aslan", "");
} catch (Exception e) {
Display.getDefault().syncExec(new Runnable() {
public void run() {
DialogUtil
.openMessageDialog(
"SATMC Execution Error",
"Could not reach SATMC web service. Check your internet connection and, if you are behind a firewall, try setting the proxy in Eclipse to \"manual\".",
DialogUtil.ERROR);
}
});
e.printStackTrace();
monitor.worked(7);
monitor.done();
return;
}
}
monitor.worked(4);
// save result to file
monitor.subTask("Saving results");
InputStream content = new ByteArrayInputStream(res.getBytes());
URI platformResultUri = uri.trimFragment();
platformResultUri = platformResultUri.trimFileExtension();
platformResultUri = platformResultUri.appendFileExtension("result");
final IFile newfile = workspace.getRoot().getFile(
new Path(platformResultUri.toPlatformString(true)));
try {
if (newfile.exists()) {
newfile.setContents(content, true, true,
new NullProgressMonitor());
} else {
newfile.create(content, true, new NullProgressMonitor());
}
newfile.refreshLocal(IResource.DEPTH_INFINITE, null);
} catch (CoreException e) {
e.printStackTrace();
}
monitor.worked(1);
// parse results
monitor.subTask("Parsing results");
try {
SatmcLexer lex = new SatmcLexer(new ANTLRStringStream(res));
CommonTokenStream tokens = new CommonTokenStream(lex);
SatmcParser parser = new SatmcParser(tokens);
SatmcMessage parserResult = parser.output();
// copy result to result variable
result.summary = parserResult.summary;
result.goal = parserResult.goal;
result.trace = parserResult.trace;
result.cfs = parserResult.cfs;
} catch (RecognitionException e) {
e.printStackTrace();
}
monitor.worked(2);
} finally {
monitor.done();
}
}
/**
* Retrieves the Resource for a given URI.
*
* @param resourceURI
* The URI for the Resource.
* @return The found Resource.
*/
private IResource getResource(URI resourceURI) {
final IResource fileResource = ResourcesPlugin.getWorkspace().getRoot()
.findMember(resourceURI.toPlatformString(true));
IResource result = null;
if (fileResource != null && fileResource.exists()) {
result = ResourcesPlugin.getWorkspace().getRoot()
.findMember(resourceURI.toPlatformString(true));
}
return result;
}
/**
* Executes a command on the local machine.
*
* @param cmdLine
* The command that should be executed.
* @param dir
* The working directory in which the command should be executed.
* @return The standard output of the command.
* @throws IOException
* Errors that occur during the execution.
*/
private String cmdExec(String[] cmdLine, File dir) throws IOException {
String line;
String output = "";
Process p = Runtime.getRuntime().exec(cmdLine, null, dir);
BufferedReader input = new BufferedReader(new InputStreamReader(
p.getInputStream()));
while ((line = input.readLine()) != null) {
output += (line + '\n');
}
input.close();
return output;
}
}