This repository has been archived on 2018-08-08. You can view files and clone it, but cannot push or open issues or pull requests.
SecureBPMN/designer/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/CheckServiceTaskFeature.java

301 lines
11 KiB
Java

/* 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.features;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.activiti.designer.util.eclipse.ActivitiUiUtil;
import org.eclipse.bpmn2.ServiceTask;
import org.eclipse.bpmn2.impl.ServiceTaskImpl;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.ICustomContext;
import org.eclipse.graphiti.features.custom.AbstractCustomFeature;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.FileEditorInput;
import eu.aniketos.securebpmn.util.DialogUtil;
import eu.aniketos.securebpmn.validation.ProcVarCheckASTVisitor;
/**
* This feature provides a feature that checks a provided ServiceTask Java implementation if
* it accesses a process variable with a provided name and displays the result
* to the user.
*
*
*/
public class CheckServiceTaskFeature extends AbstractCustomFeature {
public CheckServiceTaskFeature(IFeatureProvider fp) {
super(fp);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.graphiti.features.impl.AbstractFeature#getName()
*/
@Override
public String getName() {
return "Check service task"; //$NON-NLS-1$
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.graphiti.features.custom.AbstractCustomFeature#getDescription
* ()
*/
@Override
public String getDescription() {
return "Check if service task accesses a specific process variable"; //$NON-NLS-1$
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.graphiti.features.custom.AbstractCustomFeature#canExecute
* (org.eclipse.graphiti.features.context.ICustomContext)
*/
@Override
public boolean canExecute(ICustomContext context) {
if (context.getPictogramElements() == null)
return false;
for (PictogramElement pictogramElement : context.getPictogramElements()) {
if (pictogramElement.getLink() == null)
continue;
Object boObject = getBusinessObjectForPictogramElement(pictogramElement);
if (boObject instanceof ServiceTask == false) {
return false;
}
}
return true;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.graphiti.features.custom.ICustomFeature#execute(org.eclipse
* .graphiti.features.context.ICustomContext)
*/
public void execute(ICustomContext context) {
ServiceTask servicetask = null;
// get BusinessObject
try {
servicetask = (ServiceTask) ActivitiUiUtil
.getBusinessObjectFromContext(context,
ServiceTaskImpl.class);
} catch (Exception e) {
DialogUtil.openMessageDialog("BO Missing",
"No ServiceTask BusinessObject for Context found",
DialogUtil.ERROR);
}
if (servicetask == null)
return;
// check if service task has java impl
if (servicetask.getImplementationType() == null
|| !(servicetask.getImplementationType().equals("classType"))) {
DialogUtil.openMessageDialog("Wrong Type",
"Type must be \"Java class\" to perform this check.",
DialogUtil.ERROR);
return;
}
if (servicetask.getImplementation() == null
|| servicetask.getImplementation().length() == 0) {
DialogUtil.openMessageDialog("Missing Class definition",
"No Java class specified.", DialogUtil.ERROR);
return;
}
// prompt user for process variable
String procVar = DialogUtil.openInputDialog("Process Variable",
"Enter the process variable that should not be accessed.", "",
null);
if (procVar == null) {
// user canceled
return;
}
// map FQ class name to java file
// TODO hack, do this nicely
String[] classParts = servicetask.getImplementation().split("\\.");
String implFileName = classParts[classParts.length - 1] + ".java";
StringBuilder sb = new StringBuilder();
sb.append("/");
sb.append("src");
sb.append("/");
sb.append("main");
sb.append("/");
sb.append("java");
sb.append("/");
for (int i = 0; i < classParts.length - 1; i++) {
sb.append(classParts[i]);
sb.append("/");
}
sb.append(implFileName);
IResource resourceToRead = null;
int filesFound = 0;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot root = workspace.getRoot();
IProject[] projects = root.getProjects();
for (IProject project : projects) {
IResource resourceInRuntimeWorkspace = root.findMember(project
.getName() + sb.toString());
if (resourceInRuntimeWorkspace != null) {
filesFound++;
if (resourceToRead == null) {
resourceToRead = resourceInRuntimeWorkspace;
}
}
}
if (filesFound == 0) {
DialogUtil.openMessageDialog("Missing source",
"Implementation source file not found in workspace.",
DialogUtil.ERROR);
return;
} else if (filesFound > 1) {
DialogUtil
.openMessageDialog(
"Multiple files",
"Found "
+ filesFound
+ " matching source files in workspace, using the following:\n\n"
+ resourceToRead.getFullPath(),
DialogUtil.WARNING);
}
// read file
StringBuffer fileData = new StringBuffer(1000);
try {
BufferedReader reader = new BufferedReader(new FileReader(new File(
resourceToRead.getLocationURI())));
char[] buf = new char[1024];
int numRead = 0;
while ((numRead = reader.read(buf)) != -1) {
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1024];
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
DialogUtil.openMessageDialog("IO Error",
"Error while reading source file: " + e.getMessage(),
DialogUtil.ERROR);
return;
}
// build AST for Impl
List<Integer> locationList = new ArrayList<Integer>();
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setSource(fileData.toString().toCharArray());
CompilationUnit node = (CompilationUnit) parser.createAST(null);
node.accept(new ProcVarCheckASTVisitor(procVar, locationList));
// remove duplicates
List<Integer> uniqueLocationList = new ArrayList<Integer>();
for (Integer i : locationList) {
Integer newLoc = node.getLineNumber(i);
if (!uniqueLocationList.contains(newLoc))
uniqueLocationList.add(newLoc);
}
if (uniqueLocationList.size() > 0) {
// notify user
StringBuilder msgSB = new StringBuilder();
msgSB.append("Process variable access of \"" + procVar
+ "\" found in implementation at ");
if (uniqueLocationList.size() > 1) {
msgSB.append("lines ");
for (int i = 0; i < uniqueLocationList.size() - 1; i++) {
msgSB.append(uniqueLocationList.get(i) + ", ");
}
msgSB.append("and "
+ uniqueLocationList.get(uniqueLocationList.size() - 1));
} else {
msgSB.append("line " + uniqueLocationList.get(0));
}
msgSB.append(".");
int answer = DialogUtil.openMessageDialog("Violation",
msgSB.toString(), DialogUtil.ERROR, new String[] { "OK",
"Open File"
}, 0);
if (answer == 1) {
// open source file
IWorkbench wb = PlatformUI.getWorkbench();
IWorkbenchPage page = wb.getActiveWorkbenchWindow()
.getActivePage();
IFile file = (IFile) resourceToRead;
IEditorDescriptor desc = wb.getEditorRegistry()
.getDefaultEditor(file.getName());
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put(IMarker.LINE_NUMBER, uniqueLocationList.get(0));
try {
IMarker marker = file.createMarker(IMarker.TEXT);
marker.setAttributes(map);
page.openEditor(new FileEditorInput(file), desc.getId());
IDE.openEditor(page, marker);
marker.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
DialogUtil.openMessageDialog("No violation",
"No process variable access of \"" + procVar
+ "\" found in implementation.", DialogUtil.INFO);
}
}
}