diff --git a/swan_assist/build.gradle b/swan_assist/build.gradle index a4f3cba9..302e2cdc 100644 --- a/swan_assist/build.gradle +++ b/swan_assist/build.gradle @@ -14,8 +14,10 @@ repositories { dependencies { compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1' - compile group:'de.upb.cs.swt', name: 'swan_core', version: '1.0.0' + compile group:'de.upb.cs.swt', name: 'swan_core', version: '1.3.0' compile group: 'ca.mcgill.sable', name: 'soot', version: '3.3.0' + compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.5' + compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.5' testCompile group: 'junit', name: 'junit', version: '4.12' } diff --git a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/actions/LaunchSwanAction.java b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/actions/LaunchSwanAction.java index bed30553..45da3f4f 100644 --- a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/actions/LaunchSwanAction.java +++ b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/actions/LaunchSwanAction.java @@ -20,20 +20,20 @@ import de.fraunhofer.iem.swan.assist.data.MethodWrapper; import de.fraunhofer.iem.swan.assist.ui.dialog.SwanLauncherDialog; import de.fraunhofer.iem.swan.assist.util.Constants; +import de.fraunhofer.iem.swan.data.Method; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Objects; -import java.util.Properties; +import java.io.InputStreamReader; +import java.util.*; /** * Action opens dialog for user to set parameters for running SWAN. After which thread is created to run SWAN. */ public class LaunchSwanAction extends AnAction { + protected Set methods = new HashSet(); /** * Obtains application parameters from user, exports updated JSON file and starts thread to run SWAN. * @param anActionEvent source event @@ -70,27 +70,35 @@ public void actionPerformed(AnActionEvent anActionEvent) { HashMap swanParameters = dialog.getParameters(); - //Merge current list with training methods - HashMap methods = JSONFileLoader.getAllMethods(); + if(JSONFileLoader.isFileSelected()) { + //Merge current list with training methods + HashMap methods = JSONFileLoader.getAllMethods(); - //Load training methods - String trainingFile = Objects.requireNonNull(getClass().getClassLoader().getResource(config.getProperty("train_config_file"))).getPath() ; - JSONFileParser fileParser = new JSONFileParser(trainingFile); - HashMap trainingMethods = fileParser.parseJSONFileMap(); + InputStream stream = getClass().getClassLoader().getResourceAsStream(config.getProperty("train_config_file")); + HashMap trainingMethods = new HashMap<>(); - HashMap mergedMethods = new HashMap<>(methods); - mergedMethods.putAll(trainingMethods); + if (stream != null) { - //Export changes to configuration files - JSONWriter exportFile = new JSONWriter(); - String newConfigFile = swanParameters.get(Constants.SWAN_OUTPUT_DIR) + File.separator + config.getProperty("input_json_suffix"); - try { - exportFile.writeToJsonFile(new ArrayList<>(mergedMethods.values()), newConfigFile); - } catch (IOException e) { - e.printStackTrace(); - } + JSONFileParser fileParser = new JSONFileParser(); + trainingMethods = fileParser.parseJSONFileStream(new InputStreamReader(stream)); + } + + HashMap mergedMethods = new HashMap<>(methods); + mergedMethods.putAll(trainingMethods); - swanParameters.put(Constants.SWAN_CONFIG_FILE, newConfigFile); + //Export changes to configuration files + JSONWriter exportFile = new JSONWriter(); + String newConfigFile = swanParameters.get(Constants.SWAN_OUTPUT_DIR) + File.separator + config.getProperty("input_json_suffix"); + try { + exportFile.writeToJsonFile(new ArrayList<>(mergedMethods.values()), newConfigFile); + } catch (IOException e) { + e.printStackTrace(); + } + swanParameters.put(Constants.SWAN_CONFIG_FILE, newConfigFile); + } + else{ + swanParameters.put(Constants.SWAN_CONFIG_FILE, config.getProperty("swan_default_param_value")); + } SwanProcessBuilder processBuilder = new SwanProcessBuilder(project, dialog.getParameters()); processBuilder.start(); @@ -108,7 +116,7 @@ public void actionPerformed(AnActionEvent anActionEvent) { public void update(AnActionEvent event) { //Disable/Enable action button - if (JSONFileLoader.isReloading() || !JSONFileLoader.isFileSelected()) + if (JSONFileLoader.isReloading()) event.getPresentation().setEnabled(false); else event.getPresentation().setEnabled(true); diff --git a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/actions/SwanProcessBuilder.java b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/actions/SwanProcessBuilder.java index 3c4a136e..2801d7fc 100644 --- a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/actions/SwanProcessBuilder.java +++ b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/actions/SwanProcessBuilder.java @@ -9,11 +9,11 @@ import com.intellij.openapi.project.Project; import com.intellij.util.messages.MessageBus; +import de.fraunhofer.iem.swan.Main; import de.fraunhofer.iem.swan.assist.comm.SwanNotifier; import de.fraunhofer.iem.swan.assist.util.Constants; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.HashMap; @@ -46,51 +46,36 @@ public void run() { ResourceBundle resource = ResourceBundle.getBundle("dialog_messages"); - String currentTimestamp = getCurrentTimestamp("yyyy-MM-dd-HHmmss"); + String currentTimestamp = getCurrentTimestamp(); File outputFolder = new File(parameters.get(Constants.SWAN_OUTPUT_DIR)); - outputFolder.mkdirs(); + + if(!outputFolder.exists()) + outputFolder.mkdir(); File logFile = new File(outputFolder, currentTimestamp + parameters.get(Constants.SWAN_OUTPUT_LOG)); try { logFile.createNewFile(); parameters.replace(Constants.SWAN_OUTPUT_LOG, logFile.getPath()); + FileOutputStream fileOutputStream = new FileOutputStream(logFile.getAbsolutePath()); + + System.setOut(new PrintStream(fileOutputStream)); + } catch (IOException e) { e.printStackTrace(); } - ProcessBuilder processBuilder = new ProcessBuilder("java", "-jar", - parameters.get(Constants.SWAN_JAR_DIR), - parameters.get(Constants.SWAN_SOURCE_DIR), + Main.main(new String[]{parameters.get(Constants.SWAN_SOURCE_DIR), parameters.get(Constants.SWAN_TRAIN_DIR), parameters.get(Constants.SWAN_CONFIG_FILE), - parameters.get(Constants.SWAN_OUTPUT_DIR)); + parameters.get(Constants.SWAN_OUTPUT_DIR)}); - processBuilder.redirectErrorStream(true); - processBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(logFile)); - - String message; - - try { - Process swanProcess = processBuilder.start(); - int result = swanProcess.waitFor(); - - if (result == 0) - message = resource.getString("Messages.Notification.Success"); - else - message = resource.getString("Messages.Notification.Failure"); - - } catch (IOException | InterruptedException e) { - - e.printStackTrace(); - message = resource.getString("Messages.Notification.Failure"); - } + System.setOut(System.out); HashMap results = new HashMap(); results.put(Constants.SWAN_OUTPUT_FILE, parameters.get(Constants.SWAN_OUTPUT_FILE)); results.put(Constants.SWAN_OUTPUT_LOG, parameters.get(Constants.SWAN_OUTPUT_LOG)); - results.put(Constants.SWAN_OUTPUT_MESSAGE, message); MessageBus messageBus = project.getMessageBus(); SwanNotifier publisher = messageBus.syncPublisher(SwanNotifier.END_SWAN_PROCESS_TOPIC); @@ -99,12 +84,11 @@ public void run() { /** * Get the timestamp in a specified format. - * @param dateFormat Date format that should be used. * @return Formatted date */ - private String getCurrentTimestamp(String dateFormat) { + private String getCurrentTimestamp() { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HHmmss"); return LocalDateTime.now().format(formatter); } } \ No newline at end of file diff --git a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/data/JSONFileLoader.java b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/data/JSONFileLoader.java index ce82afcd..e6628f92 100644 --- a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/data/JSONFileLoader.java +++ b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/data/JSONFileLoader.java @@ -73,14 +73,20 @@ public static void loadInitialFile() { } /** - * Compares new JSON file with original file and updates list with merged results + * Compares new JSON file with original file and updates list with merged results. Loads new file + * is a JSON file was not selected. * @param newFilePath File path of new configuration file */ public static void loadUpdatedFile(String newFilePath) { - JSONFileComparator fileComparator = new JSONFileComparator(congFile, newFilePath); - methods = fileComparator.compareJSONFile(); - setConfigurationFile(newFilePath); + if(isFileSelected()){ + JSONFileComparator fileComparator = new JSONFileComparator(congFile, newFilePath); + methods = fileComparator.compareJSONFile(); + setConfigurationFile(newFilePath); + }else{ + setConfigurationFile(newFilePath); + loadInitialFile(); + } } /** @@ -215,8 +221,6 @@ public static boolean methodExists(String methodSignature) { return methods.containsKey(methodSignature); } - //Returns method for the specified signature - /** * Returns an instance of the method * @param methodSignature Method Signature of requested method. @@ -227,8 +231,6 @@ public static MethodWrapper getMethod(String methodSignature) { return methods.get(methodSignature); } - //Remove method from list - /** * Remove method from list * @param method Method to be removed diff --git a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/data/JSONFileParser.java b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/data/JSONFileParser.java index 16913bad..1ef12452 100644 --- a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/data/JSONFileParser.java +++ b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/data/JSONFileParser.java @@ -14,8 +14,10 @@ import de.fraunhofer.iem.swan.assist.util.Constants; import de.fraunhofer.iem.swan.data.Method; +import java.io.InputStreamReader; import java.util.HashMap; import java.util.ResourceBundle; +import java.util.Set; /** * Parses JSON file and returns methods. @@ -32,6 +34,13 @@ public JSONFileParser(String path) { congFilePath = path; } + /** + * Default constructor + */ + public JSONFileParser() { + + } + /** * Returns file path for configuration file * @return File path as a string. @@ -54,12 +63,30 @@ public void setCongFilePath(String congFilePath) { */ public HashMap parseJSONFileMap() { - HashMap methods = new HashMap(); Parser parser = new Parser(congFilePath); + parser.parse(congFilePath); + + return parseMethods(parser.methods()); + } + + /** + * Parses file and returns method. + * @return HashMap of methods + */ + public HashMap parseJSONFileStream(InputStreamReader streamReader) { + + Parser parser = new Parser(); + parser.parseStream(streamReader); + return parseMethods(parser.methods()); + } + + private HashMap parseMethods(Set methodsSet){ + ResourceBundle resource = ResourceBundle.getBundle("dialog_messages"); + HashMap methods = new HashMap(); try { - for (Method method : parser.parseFile(congFilePath)) { + for (Method method :methodsSet ) { MethodWrapper methodWrapper = new MethodWrapper(method); diff --git a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/ui/MethodListTree.java b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/ui/MethodListTree.java index b5968e3f..b23991ef 100644 --- a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/ui/MethodListTree.java +++ b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/ui/MethodListTree.java @@ -40,11 +40,13 @@ import de.fraunhofer.iem.swan.assist.comm.*; import de.fraunhofer.iem.swan.assist.data.JSONFileLoader; import de.fraunhofer.iem.swan.assist.data.MethodWrapper; +import de.fraunhofer.iem.swan.assist.ui.dialog.MethodDialog; import de.fraunhofer.iem.swan.assist.ui.dialog.SwanResultsDialog; import de.fraunhofer.iem.swan.assist.util.Constants; import de.fraunhofer.iem.swan.assist.util.Formatter; import de.fraunhofer.iem.swan.assist.util.PsiTraversal; import de.fraunhofer.iem.swan.data.Category; +import de.fraunhofer.iem.swan.data.Method; import javafx.util.Pair; import org.jetbrains.annotations.NotNull; @@ -70,6 +72,7 @@ public class MethodListTree extends Tree { /** * Initialises method list tree + * * @param project Active project in IDE */ public MethodListTree(Project project) { @@ -98,55 +101,62 @@ public void mouseClicked(MouseEvent e) { if ((SwingUtilities.isRightMouseButton(e) || (e.isControlDown()) && !isEmpty())) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) getLastSelectedPathComponent(); - Object object = node.getUserObject(); - if (object instanceof MethodWrapper) { + if (node != null) { + + Object object = node.getUserObject(); + + if (object instanceof MethodWrapper) { - MethodWrapper method = (MethodWrapper) object; + MethodWrapper method = (MethodWrapper) object; - RESTORE_METHOD = method.getUpdateOperation().equals(Constants.METHOD_DELETED); + RESTORE_METHOD = method.getUpdateOperation().equals(Constants.METHOD_DELETED); - ActionPopupMenu actionPopupMenu = ActionManager.getInstance().createActionPopupMenu("Method", new MethodActionGroup(method)); - actionPopupMenu.getComponent().show(e.getComponent(), e.getX(), e.getY()); + ActionPopupMenu actionPopupMenu = ActionManager.getInstance().createActionPopupMenu("Method", new MethodActionGroup(method)); + actionPopupMenu.getComponent().show(e.getComponent(), e.getX(), e.getY()); + } } } else if (e.getClickCount() == 2) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) getLastSelectedPathComponent(); - Object object = node.getUserObject(); + if (node != null) { + Object object = node.getUserObject(); - if (object instanceof MethodWrapper) { + if (object instanceof MethodWrapper) { - MethodWrapper method = (MethodWrapper) object; + MethodWrapper method = (MethodWrapper) object; - //Get PSI element location - PsiFile[] files = FilenameIndex.getFilesByName(project, method.getFileName(), GlobalSearchScope.allScope(project)); + //Get PSI element location + PsiFile[] files = FilenameIndex.getFilesByName(project, method.getFileName(), GlobalSearchScope.allScope(project)); - boolean methodFound = false; + boolean methodFound = false; - for (PsiFile file : files) { + for (PsiFile file : files) { - PsiJavaFile psiJavaFile = (PsiJavaFile) file; + PsiJavaFile psiJavaFile = (PsiJavaFile) file; - for (PsiClass psiClass : psiJavaFile.getClasses()) { - for (PsiMethod psiMethod : psiClass.getMethods()) { + for (PsiClass psiClass : psiJavaFile.getClasses()) { + for (PsiMethod psiMethod : psiClass.getMethods()) { - if (Objects.equals(PsiTraversal.getMethodSignature(psiMethod), method.getSignature(true))) { + if (Objects.equals(PsiTraversal.getMethodSignature(psiMethod), method.getSignature(true))) { - methodFound = true; - FileEditorManager.getInstance(project).openFile(psiJavaFile.getVirtualFile(), true, true); - FileEditorManager.getInstance(project).getSelectedTextEditor().getCaretModel().moveToOffset(psiMethod.getTextOffset()); + methodFound = true; + FileEditorManager.getInstance(project).openFile(psiJavaFile.getVirtualFile(), true, true); + FileEditorManager.getInstance(project).getSelectedTextEditor().getCaretModel().moveToOffset(psiMethod.getTextOffset()); + } } } } - } - if (!methodFound) { - JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(resource.getString("Messages.Error.MethodNotFound"), MessageType.ERROR, null) - .createBalloon() - .show(JBPopupFactory.getInstance().guessBestPopupLocation((JComponent) e.getComponent()), Balloon.Position.below); + if (!methodFound) { + JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(resource.getString("Messages.Error.MethodNotFound"), MessageType.ERROR, null) + .createBalloon() + .show(JBPopupFactory.getInstance().guessBestPopupLocation((JComponent) e.getComponent()), Balloon.Position.below); + } } } + } } }); @@ -279,12 +289,11 @@ public void launchSwan(HashMap values) { JSONFileLoader.setReloading(false); NotificationType notificationType = NotificationType.INFORMATION; - if (!values.get(Constants.SWAN_OUTPUT_MESSAGE).equals(resource.getString("Messages.Notification.Success"))) { - notificationType = NotificationType.ERROR; - } + String message = "" + + resource.getString("Messages.Notification.Completed") + + "
View Logs or Load Changes"; - String message = "" + values.get(Constants.SWAN_OUTPUT_MESSAGE) + "
View Logs or Load Changes"; - Notifications.Bus.notify(new Notification(Constants.PLUGIN_GROUP_DISPLAY_ID, "Completed", message, notificationType, new NotificationListener() { + Notifications.Bus.notify(new Notification(Constants.PLUGIN_GROUP_DISPLAY_ID, resource.getString("Messages.Notification.Title.Completed"), message, notificationType, new NotificationListener() { @Override public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent hyperlinkEvent) { @@ -305,6 +314,52 @@ public void hyperlinkUpdate(@NotNull Notification notification, @NotNull Hyperli } }); + + //Update Tool Window to notify user that SWAN is running + bus.connect().subscribe(SuggestNotifier.START_SUGGEST_TOPIC, new SuggestNotifier() { + @Override + public void setStartSuggestTopic() { + JSONFileLoader.setReloading(true); + Notifications.Bus.notify(new Notification(Constants.PLUGIN_GROUP_DISPLAY_ID, resource.getString("Messages.Title.SuggestStarted"), resource.getString("Messages.Notification.SuggestStarted"), NotificationType.INFORMATION)); + + } + + @Override + public void setEndSuggestTopic(Set values) { + JSONFileLoader.setReloading(false); + + NotificationType notificationType = NotificationType.INFORMATION; + + String message = "" + resource.getString("Messages.Notification.Suggest.Successful") + "
View methods"; + Notifications.Bus.notify(new Notification(Constants.PLUGIN_GROUP_DISPLAY_ID, "Completed", message, notificationType, new NotificationListener() { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent hyperlinkEvent) { + + if (hyperlinkEvent.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + + if (hyperlinkEvent.getDescription().equals("methods")) { + + HashMap suggestedMethods = new HashMap<>(); + + for(Method m: values){ + + MethodWrapper methodWrapper = new MethodWrapper(m); + methodWrapper.setStatus(MethodWrapper.MethodStatus.SUGGESTED); + + suggestedMethods.put(methodWrapper.getSignature(true), methodWrapper); + } + + MethodDialog dialog = new MethodDialog(suggestedMethods, (String)suggestedMethods.keySet().toArray()[0], project, JSONFileLoader.getCategories()); + dialog.show(); + + + } + } + } + })); + } + }); + //Connect to project bus and obtain filter for Method Tree bus.connect().subscribe(FilterNotifier.FILTER_SELECTED_TOPIC, new FilterNotifier() { @Override @@ -379,6 +434,7 @@ private DefaultMutableTreeNode searchNode(DefaultMutableTreeNode root, String me /** * Add new node to tree + * * @param method New method to be added */ private void addNode(MethodWrapper method) { @@ -390,6 +446,7 @@ private void addNode(MethodWrapper method) { /** * Extracts categories from method and adds them to the DefaultMutableTreeNode node. + * * @param method the method that is being added to the tree * @return the node object with the categories as children */ @@ -399,6 +456,7 @@ private DefaultMutableTreeNode addCategoriesToNode(MethodWrapper method) { /** * Extracts categories from method and adds them to the DefaultMutableTreeNode node. + * * @param node method to be added to tree * @param method the method that is being added to the tree * @return the node object with the categories as children diff --git a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/ui/dialog/SwanLauncherDialog.java b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/ui/dialog/SwanLauncherDialog.java index ba0c10cb..ad2bcb60 100644 --- a/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/ui/dialog/SwanLauncherDialog.java +++ b/swan_assist/src/main/java/de/fraunhofer/iem/swan/assist/ui/dialog/SwanLauncherDialog.java @@ -52,15 +52,14 @@ public class SwanLauncherDialog extends DialogWrapper { private JButton trainButton; private JPanel advancedPanel; private HashMap parameters = new HashMap(); - private String defaultTrainDirectory; - private String swanJarDirecory; private ResourceBundle resourceBundle; private Properties config; /** * Initializes dialog to launch SWAN. + * * @param project Active project in the editor - * @param modal Modal setting for dialog + * @param modal Modal setting for dialog */ public SwanLauncherDialog(Project project, boolean modal) { @@ -88,24 +87,8 @@ public SwanLauncherDialog(Project project, boolean modal) { File configurationFile = new File(JSONFileLoader.getConfigurationFile(true)); - Path path = Paths.get(PathManager.getJarPathForClass(SwanLauncherDialog.class)); - String jarDirectory = path.getParent().toString(); - - // trainingTextbox.setText(jarDirectory); - - defaultTrainDirectory = jarDirectory+File.separator+"training_libs";//Objects.requireNonNull(getClass().getClassLoader().getResource(config.getProperty("train_dir_name"))).getPath(); - - //trainingTextbox.setText(com.intellij.openapi.application.PathManager.getJarPathForClass(SwanLauncherDialog.class)); - - String jarDir = jarDirectory+File.separator+"swan_core.jar";// config.getProperty("swan_jar_name");//Objects.requireNonNull(getClass().getClassLoader().getResource(config.getProperty("swan_jar_name"))).getPath(); - - if (PlatformUtil.isWindows() || System.getProperty("os.name").toLowerCase().contains("win")) - swanJarDirecory = jarDir.substring(1); - else - swanJarDirecory = jarDir; - sourceDirTextbox.setText(project.getBasePath()); - outputDir.setText(configurationFile.getParent() + File.separator + config.getProperty("output_dir_name")); + outputDir.setText(project.getBasePath() + File.separator + config.getProperty("output_dir_name")); for (Component component : advancedPanel.getComponents()) { component.setEnabled(advancedCheckbox.isSelected()); @@ -174,8 +157,6 @@ public void actionPerformed(ActionEvent e) { protected void doOKAction() { if (isOKActionEnabled()) { - //set path for jar directory - parameters.put(Constants.SWAN_JAR_DIR, swanJarDirecory); //ensure that required fields are populated if (sourceDirTextbox.getText().trim().isEmpty()) { @@ -192,24 +173,24 @@ protected void doOKAction() { .show(JBPopupFactory.getInstance().guessBestPopupLocation(advancedCheckbox), Balloon.Position.below); } else if (!advancedCheckbox.isSelected()) { - parameters.put(Constants.SWAN_SOURCE_DIR, sourceDirTextbox.getText()); - parameters.put(Constants.SWAN_TRAIN_DIR, defaultTrainDirectory); - parameters.put(Constants.SWAN_OUTPUT_DIR, outputDir.getText()); - parameters.put(Constants.SWAN_OUTPUT_LOG, config.getProperty("log_suffix")); - parameters.put(Constants.SWAN_OUTPUT_FILE, parameters.get(Constants.SWAN_OUTPUT_DIR) + File.separator + config.getProperty("output_json_suffix")); - super.doOKAction(); + parameters.put(Constants.SWAN_TRAIN_DIR, config.getProperty("swan_default_param_value")); + setParameters(); } else { - parameters.put(Constants.SWAN_SOURCE_DIR, sourceDirTextbox.getText()); parameters.put(Constants.SWAN_TRAIN_DIR, trainingTextbox.getText()); - parameters.put(Constants.SWAN_OUTPUT_DIR, outputDir.getText()); - parameters.put(Constants.SWAN_OUTPUT_LOG, config.getProperty("log_suffix")); - parameters.put(Constants.SWAN_OUTPUT_FILE, parameters.get(Constants.SWAN_OUTPUT_DIR) + File.separator + config.getProperty("output_json_suffix")); - super.doOKAction(); + setParameters(); } } } + private void setParameters(){ + parameters.put(Constants.SWAN_SOURCE_DIR, sourceDirTextbox.getText()); + parameters.put(Constants.SWAN_OUTPUT_DIR, outputDir.getText()); + parameters.put(Constants.SWAN_OUTPUT_LOG, config.getProperty("log_suffix")); + parameters.put(Constants.SWAN_OUTPUT_FILE, parameters.get(Constants.SWAN_OUTPUT_DIR) + File.separator + config.getProperty("output_json_suffix")); + super.doOKAction(); + } + @Nullable @Override protected JComponent createCenterPanel() { @@ -218,8 +199,9 @@ protected JComponent createCenterPanel() { /** * Accept users file or folder selection and send return value + * * @param selectionMethod Selection method that should be used by File chooser - * @param path Default path + * @param path Default path * @return Returns default path or path selected by the user. */ private String fileSelector(int selectionMethod, String path) { @@ -241,6 +223,7 @@ private String fileSelector(int selectionMethod, String path) { /** * Returns parameters + * * @return HashMap of parameters used to run SWAN, */ public HashMap getParameters() { diff --git a/swan_assist/src/main/resources/META-INF/plugin.xml b/swan_assist/src/main/resources/META-INF/plugin.xml index bfef7407..05583f0f 100644 --- a/swan_assist/src/main/resources/META-INF/plugin.xml +++ b/swan_assist/src/main/resources/META-INF/plugin.xml @@ -43,10 +43,10 @@ + text="Load or Reload SWAN"> - diff --git a/swan_assist/src/main/resources/config.properties b/swan_assist/src/main/resources/config.properties index 5b4208f1..cae6f563 100644 --- a/swan_assist/src/main/resources/config.properties +++ b/swan_assist/src/main/resources/config.properties @@ -2,6 +2,5 @@ log_suffix = _swanassist_log.txt output_dir_name = output output_json_suffix = output.json input_json_suffix = config_input.json -train_dir_name = training_libs train_config_file = trainingmethods.json -swan_jar_name = swan_core.jar \ No newline at end of file +swan_default_param_value = internal \ No newline at end of file diff --git a/swan_assist/src/main/resources/dialog_messages.properties b/swan_assist/src/main/resources/dialog_messages.properties index 2ca8b437..6fe80116 100644 --- a/swan_assist/src/main/resources/dialog_messages.properties +++ b/swan_assist/src/main/resources/dialog_messages.properties @@ -21,8 +21,8 @@ Launcher.TrainingJars = Training Jars #Notifications when running SWAN Messages.Title.RefreshStarted = Reloading SWAN Messages.Notification.RefreshStarted = SWAN refresh started -Messages.Notification.Success = SWAN execution completed -Messages.Notification.Failure = There was an error +Messages.Notification.Title.Completed = SWAN Rerun Completed +Messages.Notification.Completed = SWAN execution completed Messages.Notification.EmptyTree = Select a configuration file using the \"Import\" button Messages.Notification.NoFilterResults = No methods match the filters you've selected diff --git a/swan_assist/src/main/resources/swan_core.jar b/swan_assist/src/main/resources/swan_core.jar deleted file mode 100644 index 9fa42406..00000000 Binary files a/swan_assist/src/main/resources/swan_core.jar and /dev/null differ diff --git a/swan_core/src/main/java/de/fraunhofer/iem/swan/Parser.java b/swan_core/src/main/java/de/fraunhofer/iem/swan/Parser.java index 80424b66..e125c37c 100644 --- a/swan_core/src/main/java/de/fraunhofer/iem/swan/Parser.java +++ b/swan_core/src/main/java/de/fraunhofer/iem/swan/Parser.java @@ -1,7 +1,9 @@ package de.fraunhofer.iem.swan; +import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; @@ -26,324 +28,329 @@ * Loads methods from file or jars. * * @author Lisa Nguyen Quang Do - * */ public class Parser { - private static final Logger logger = LoggerFactory.getLogger(Parser.class); - - protected final String trainingCp; - protected Set methods = new HashSet(); - private Set cwes = new HashSet(); - - public Parser(String trainingCp) { - this.trainingCp = trainingCp; - } - - public Set methods() { - return methods; - } - - public void loadTrainingSet(Set trainingSetFiles) throws IOException { - loadMethods(trainingSetFiles); - prefilterInterfaces(); - Util.createSubclassAnnotations(methods, trainingCp); - methods = Util.sanityCheck(methods, new HashSet()); - Util.printStatistics("Training set complete", methods); - } - - public void resetMethods() { - for (Method m : methods) - m.setCategoryClassified(null); - } - - /** - * Removes all interfaces from the given set of methods and returns the purged - * set. - * - * @param methods - * The set of methods from which to remove the interfaces. - * @return The purged set of methods. - */ - private void prefilterInterfaces() { - Set purgedMethods = new HashSet(methods.size()); - for (Method am : methods) { - AbstractSootFeature asf = new AbstractSootFeature(trainingCp) { - @Override - public Type appliesInternal(Method method) { - SootMethod sm = getSootMethod(method); - if (sm == null) - return Type.NOT_SUPPORTED; - - if (sm.isAbstract()) - return Type.FALSE; - else - return Type.TRUE; - } - }; - Type t = asf.applies(am); - if (t == Type.TRUE) - { - purgedMethods.add(am); - } - else - System.out.println("Purged method: " + am.getSignature()); - - } - logger.info(methods.size() + " methods purged down to " - + purgedMethods.size() + "."); - this.methods = purgedMethods; - } - - public void loadMethods(Set trainingSetFiles) throws IOException { - - parse(trainingSetFiles); - Set methodsWithoutDuplicates = new HashSet(); - - for (Method am : methods) { - if (methodsWithoutDuplicates.contains(am)) { - // Merge the methods - for (Method amOrig : methodsWithoutDuplicates) - if (am.equals(amOrig)) { - // Merge the classification - amOrig.addCategoriesTrained(am.getCategoriesTrained()); - break; - } - } else { - methodsWithoutDuplicates.add(am); - } - } - - methods = methodsWithoutDuplicates; - logger.info( - "Collected " + methods.size() + " methods from the training set."); - } + private static final Logger logger = LoggerFactory.getLogger(Parser.class); - protected void parse(Set files) { - for (String file : files) - parse(file); - } + protected final String trainingCp; + protected Set methods = new HashSet(); + private Set cwes = new HashSet(); - private void parse(String fileName) { - try { - JSONParser parser = new JSONParser(); - Object obj = parser.parse(new FileReader(fileName)); - JSONObject jsonObject = (JSONObject) obj; + public Parser() { + this.trainingCp = null; + } - // get the lists in the file (4 types of files) - JSONArray methodsList = (JSONArray) jsonObject.get("methods"); - // JSONArray cwesList = (JSONArray) jsonObject.get("cwes"); + public Parser(String trainingCp) { + this.trainingCp = trainingCp; + } - // create all cwes - // if (cwesList != null) loadMethodsFromJsonArray(cwesList, "cwes"); - if (methodsList != null) loadMethodsFromJsonArray(methodsList, "methods"); + public Set methods() { + return methods; + } - } catch (Exception e) { - e.printStackTrace(); + public void loadTrainingSet(Set trainingSetFiles) throws IOException { + loadMethods(trainingSetFiles); + prefilterInterfaces(); + Util.createSubclassAnnotations(methods, trainingCp); + methods = Util.sanityCheck(methods, new HashSet()); + Util.printStatistics("Training set complete", methods); } - } - public Set parseFile(String fileName){ - parse(fileName); - return methods; - } + public void resetMethods() { + for (Method m : methods) + m.setCategoryClassified(null); + } - @SuppressWarnings("unchecked") - private void loadMethodsFromJsonArray(JSONArray array, String type) { + /** + * Removes all interfaces from the given set of methods and returns the purged + * set. + * + * @param methods The set of methods from which to remove the interfaces. + * @return The purged set of methods. + */ + private void prefilterInterfaces() { + Set purgedMethods = new HashSet(methods.size()); + for (Method am : methods) { + AbstractSootFeature asf = new AbstractSootFeature(trainingCp) { + @Override + public Type appliesInternal(Method method) { + SootMethod sm = getSootMethod(method); + if (sm == null) + return Type.NOT_SUPPORTED; + + if (sm.isAbstract()) + return Type.FALSE; + else + return Type.TRUE; + } + }; + Type t = asf.applies(am); + if (t == Type.TRUE) { + purgedMethods.add(am); + } else + System.out.println("Purged method: " + am.getSignature()); - if (type.equals("methods")) { - Iterator iterator = array.iterator(); - while (iterator.hasNext()) { - JSONObject jsonObj = iterator.next(); + } + logger.info(methods.size() + " methods purged down to " + + purgedMethods.size() + "."); + this.methods = purgedMethods; + } - String methodName = (String) jsonObj.get(Constants.NAME); - String returnType = (String) jsonObj.get(Constants.RETURN_TYPE); - String discovery = (String) jsonObj.get(Constants.DISCOVERY); - String framework = (String) jsonObj.get(Constants.FRAMEWORK); - String link = (String) jsonObj.get(Constants.LINK); - String comment = (String) jsonObj.get(Constants.COMMENT); - String secLevel = (String) jsonObj.get(Constants.SECURITY_LEVEL); + public void loadMethods(Set trainingSetFiles) throws IOException { + + parse(trainingSetFiles); + Set methodsWithoutDuplicates = new HashSet(); + + for (Method am : methods) { + if (methodsWithoutDuplicates.contains(am)) { + // Merge the methods + for (Method amOrig : methodsWithoutDuplicates) + if (am.equals(amOrig)) { + // Merge the classification + amOrig.addCategoriesTrained(am.getCategoriesTrained()); + break; + } + } else { + methodsWithoutDuplicates.add(am); + } + } - JSONObject jsonObjDataIn = (JSONObject) jsonObj.get(Constants.DATA_IN); - JSONObject jsonObjDataOut = (JSONObject) jsonObj.get(Constants.DATA_OUT); + methods = methodsWithoutDuplicates; + logger.info( + "Collected " + methods.size() + " methods from the training set."); + } - List params = new ArrayList(); + protected void parse(Set files) { + for (String file : files) + parse(file); + } - if (jsonObj.get(Constants.PARAMETERS) != null) { - JSONArray parameters = (JSONArray) jsonObj.get(Constants.PARAMETERS); + public void parse(String fileName) { + try { + parseStream(new FileReader(fileName)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } - Iterator p = parameters.iterator(); + public void parseStream(InputStreamReader streamReader) { - while (p.hasNext()) { - params.add(p.next().toString()); - } + JSONParser parser = new JSONParser(); + Object obj = null; + try { + obj = parser.parse(streamReader); + } catch (IOException | ParseException e) { + e.printStackTrace(); } - Method m; - String temp = getNameOfClass(methodName) - .substring(getNameOfClass(methodName).lastIndexOf(".") + 1); - if (getNameOfMethod(methodName).equals(temp)) - m = new Method("", params, returnType, - getNameOfClass(methodName)); - else - m = new Method(getNameOfMethod(methodName), params, returnType, - getNameOfClass(methodName)); + JSONObject jsonObject = (JSONObject) obj; - // parse the relevantPart objects for dataIn and dataOut - boolean retDataIn = (boolean) jsonObjDataIn.get(Constants.RETURN_TYPE); - boolean retDataOut = (boolean) jsonObjDataOut.get(Constants.RETURN_TYPE); + // get the lists in the file (4 types of files) + JSONArray methodsList = (JSONArray) jsonObject.get("methods"); + // JSONArray cwesList = (JSONArray) jsonObject.get("cwes"); - m.getDataIn().setReturnValue(retDataIn); - m.getDataOut().setReturnValue(retDataOut); + // create all cwes + // if (cwesList != null) loadMethodsFromJsonArray(cwesList, "cwes"); + if (methodsList != null) loadMethodsFromJsonArray(methodsList, "methods"); + } - if (jsonObjDataIn.get(Constants.PARAMETERS) != null) { - JSONArray parameters1 = (JSONArray) jsonObjDataIn.get(Constants.PARAMETERS); + @SuppressWarnings("unchecked") + private void loadMethodsFromJsonArray(JSONArray array, String type) { + + if (type.equals("methods")) { + Iterator iterator = array.iterator(); + while (iterator.hasNext()) { + JSONObject jsonObj = iterator.next(); + + String methodName = (String) jsonObj.get(Constants.NAME); + String returnType = (String) jsonObj.get(Constants.RETURN_TYPE); + String discovery = (String) jsonObj.get(Constants.DISCOVERY); + String framework = (String) jsonObj.get(Constants.FRAMEWORK); + String link = (String) jsonObj.get(Constants.LINK); + String comment = (String) jsonObj.get(Constants.COMMENT); + String secLevel = (String) jsonObj.get(Constants.SECURITY_LEVEL); + + JSONObject jsonObjDataIn = (JSONObject) jsonObj.get(Constants.DATA_IN); + JSONObject jsonObjDataOut = (JSONObject) jsonObj.get(Constants.DATA_OUT); + + List params = new ArrayList(); + + if (jsonObj.get(Constants.PARAMETERS) != null) { + JSONArray parameters = (JSONArray) jsonObj.get(Constants.PARAMETERS); + + Iterator p = parameters.iterator(); + + while (p.hasNext()) { + params.add(p.next().toString()); + } + } + + Method m; + String temp = getNameOfClass(methodName) + .substring(getNameOfClass(methodName).lastIndexOf(".") + 1); + if (getNameOfMethod(methodName).equals(temp)) + m = new Method("", params, returnType, + getNameOfClass(methodName)); + else + m = new Method(getNameOfMethod(methodName), params, returnType, + getNameOfClass(methodName)); + + // parse the relevantPart objects for dataIn and dataOut + boolean retDataIn = (boolean) jsonObjDataIn.get(Constants.RETURN_TYPE); + boolean retDataOut = (boolean) jsonObjDataOut.get(Constants.RETURN_TYPE); + + m.getDataIn().setReturnValue(retDataIn); + m.getDataOut().setReturnValue(retDataOut); + + if (jsonObjDataIn.get(Constants.PARAMETERS) != null) { + JSONArray parameters1 = (JSONArray) jsonObjDataIn.get(Constants.PARAMETERS); + + Iterator p1 = parameters1.iterator(); + + while (p1.hasNext()) { + m.getDataIn().getParameterIndeces() + .add((Integer.parseInt(p1.next().toString()))); + } + } + + if (jsonObjDataOut.get(Constants.PARAMETERS) != null) { + JSONArray parameters2 = (JSONArray) jsonObjDataOut.get(Constants.PARAMETERS); + + Iterator p2 = parameters2.iterator(); + while (p2.hasNext()) { + m.getDataOut().getParameterIndeces() + .add((Integer.parseInt(p2.next().toString()))); + } + } + + Method.SecLevel securityLevel = Method.SecLevel.NEUTRAL; + if (secLevel == null) + securityLevel = Method.SecLevel.NEUTRAL; + else { + switch (secLevel) { + case Constants.AUTH_SAFE: + securityLevel = Method.SecLevel.HIGH; + break; + case Constants.AUTH_UNSAFE: + securityLevel = Method.SecLevel.LOW; + break; + default: + securityLevel = Method.SecLevel.NEUTRAL; + break; + } + } + + // add the other String values + m.setComment(comment); + m.setFramework(framework); + m.setLink(link); + m.setDiscovery(discovery); + m.setSecLevel(securityLevel); + + // link the cwes + if (jsonObj.get(Constants.CWE) != null) { + JSONArray cweList = (JSONArray) jsonObj.get(Constants.CWE); + Iterator p = cweList.iterator(); + while (p.hasNext()) { + String cweId = p.next().toString(); + Category cweCategory = Category.getCategoryForCWE(cweId); + if (cweCategory != null) { + m.addCategoryTrained(cweCategory); + cwes.add(cweId); + } else + System.err.println("CWE category does not exist: " + cweId); + } + } + + + // Note by Ingo Budde: + // I modified the following lines to get rid of soot-infoflow dependency. + // It seems that the SourceSinkDefinition is not used here. + + // SourceSinkDefinition ssd = new SourceSinkDefinition(m); + // Method method = (Method) ssd.getMethod(); + Method method = m; + + // parse the correct types + if (jsonObj.get(Constants.TYPE) != null) { + JSONArray types = (JSONArray) jsonObj.get(Constants.TYPE); + Iterator p = types.iterator(); + while (p.hasNext()) { + String t = p.next().toString(); + switch (t) { + case Constants.SOURCE: + m.addCategoryTrained(Category.SOURCE); + break; + case Constants.SINK: + m.addCategoryTrained(Category.SINK); + break; + case Constants.SANITIZER: + m.addCategoryTrained(Category.SANITIZER); + break; + case Constants.AUTHENTICATION: + switch (securityLevel) { + case HIGH: + m.addCategoryTrained(Category.AUTHENTICATION_TO_HIGH); + break; + case LOW: + m.addCategoryTrained(Category.AUTHENTICATION_TO_LOW); + break; + case NEUTRAL: + m.addCategoryTrained(Category.AUTHENTICATION_NEUTRAL); + break; + } + break; + default: + break; + } + } + } + methods.add(method); + } + } - Iterator p1 = parameters1.iterator(); + // if (type.equals("cwes")) { + // Iterator iterator2 = array.iterator(); + // JSONObject jsonObj2 = iterator2.next(); + // while (iterator2.hasNext()) { + // String i = (String) jsonObj2.get("id"); + // String n = (String) jsonObj2.get("name"); + // String s = (String) jsonObj2.get("short"); + // if (s == null) s = ""; + // String l = (String) jsonObj2.get("link"); + // CWE newCWE = new CWE(i, n, s, l); + // cwes.add(newCWE); + // jsonObj2 = iterator2.next(); + // } + // } + } - while (p1.hasNext()) { - m.getDataIn().getParameterIndeces() - .add((Integer.parseInt(p1.next().toString()))); - } - } + private String getNameOfMethod(String name) { + String[] names = name.split("\\."); + return names[names.length - 1]; + } - if (jsonObjDataOut.get(Constants.PARAMETERS) != null) { - JSONArray parameters2 = (JSONArray) jsonObjDataOut.get(Constants.PARAMETERS); + private String getNameOfClass(String name) { + return name.substring(0, name.lastIndexOf(".")); + } - Iterator p2 = parameters2.iterator(); - while (p2.hasNext()) { - m.getDataOut().getParameterIndeces() - .add((Integer.parseInt(p2.next().toString()))); - } - } + public Set cwe() { + return cwes; + } - Method.SecLevel securityLevel = Method.SecLevel.NEUTRAL; - if (secLevel == null) - securityLevel = Method.SecLevel.NEUTRAL; - else { - switch (secLevel) { - case Constants.AUTH_SAFE: - securityLevel = Method.SecLevel.HIGH; - break; - case Constants.AUTH_UNSAFE: - securityLevel = Method.SecLevel.LOW; - break; - default: - securityLevel = Method.SecLevel.NEUTRAL; - break; - } - } + private RelevantPart extractDataInOutObject(JSONObject dataObject) { - // add the other String values - m.setComment(comment); - m.setFramework(framework); - m.setLink(link); - m.setDiscovery(discovery); - m.setSecLevel(securityLevel); - - // link the cwes - if (jsonObj.get(Constants.CWE) != null) { - JSONArray cweList = (JSONArray) jsonObj.get(Constants.CWE); - Iterator p = cweList.iterator(); - while (p.hasNext()) { - String cweId = p.next().toString(); - Category cweCategory = Category.getCategoryForCWE(cweId); - if (cweCategory != null) { - m.addCategoryTrained(cweCategory); - cwes.add(cweId); - } else - System.err.println("CWE category does not exist: " + cweId); - } - } + JSONArray parameterArray = (JSONArray) dataObject.get(Constants.PARAMETERS); + List parameters = new ArrayList<>(); - // Note by Ingo Budde: - // I modified the following lines to get rid of soot-infoflow dependency. - // It seems that the SourceSinkDefinition is not used here. - - // SourceSinkDefinition ssd = new SourceSinkDefinition(m); - // Method method = (Method) ssd.getMethod(); - Method method = m; - - // parse the correct types - if (jsonObj.get(Constants.TYPE) != null) { - JSONArray types = (JSONArray) jsonObj.get(Constants.TYPE); - Iterator p = types.iterator(); - while (p.hasNext()) { - String t = p.next().toString(); - switch (t) { - case Constants.SOURCE: - m.addCategoryTrained(Category.SOURCE); - break; - case Constants.SINK: - m.addCategoryTrained(Category.SINK); - break; - case Constants.SANITIZER: - m.addCategoryTrained(Category.SANITIZER); - break; - case Constants.AUTHENTICATION: - switch (securityLevel) { - case HIGH: - m.addCategoryTrained(Category.AUTHENTICATION_TO_HIGH); - break; - case LOW: - m.addCategoryTrained(Category.AUTHENTICATION_TO_LOW); - break; - case NEUTRAL: - m.addCategoryTrained(Category.AUTHENTICATION_NEUTRAL); - break; - } - break; - default: - break; - } - } - } - methods.add(method); - } - } + for (Object param : parameterArray) { - // if (type.equals("cwes")) { - // Iterator iterator2 = array.iterator(); - // JSONObject jsonObj2 = iterator2.next(); - // while (iterator2.hasNext()) { - // String i = (String) jsonObj2.get("id"); - // String n = (String) jsonObj2.get("name"); - // String s = (String) jsonObj2.get("short"); - // if (s == null) s = ""; - // String l = (String) jsonObj2.get("link"); - // CWE newCWE = new CWE(i, n, s, l); - // cwes.add(newCWE); - // jsonObj2 = iterator2.next(); - // } - // } - } - - private String getNameOfMethod(String name) { - String[] names = name.split("\\."); - return names[names.length - 1]; - } - - private String getNameOfClass(String name) { - return name.substring(0, name.lastIndexOf(".")); - } - - public Set cwe() { - return cwes; - } - - private RelevantPart extractDataInOutObject(JSONObject dataObject) { - - JSONArray parameterArray = (JSONArray) dataObject.get(Constants.PARAMETERS); - - List parameters = new ArrayList<>(); - - for (Object param : parameterArray) { - - if (param instanceof Integer) - parameters.add((Integer) param); + if (param instanceof Integer) + parameters.add((Integer) param); + } + return new RelevantPart((boolean) dataObject.get(Constants.RETURN_TYPE), parameters); } - return new RelevantPart((boolean) dataObject.get(Constants.RETURN_TYPE), parameters); - } }