From 7d3a9d6d023c1400ea03168253251c1f7484a068 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 3 Apr 2020 15:30:51 -0400 Subject: [PATCH 1/8] begin refactoring delete orphan nodes to accomodate changes --- .../autoingest/DeleteOrphanCaseNodesTask.java | 181 ++++++++++++------ 1 file changed, 122 insertions(+), 59 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java index 16f0592548..949bf0e8f2 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java @@ -21,7 +21,13 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils; @@ -43,6 +49,26 @@ final class DeleteOrphanCaseNodesTask implements Runnable { private int nodesCount; private int casesCount; + + final static class OrphanCaseNodeEntry { + final String caseName; + final String nodePath; + + public OrphanCaseNodeEntry(String caseName, String nodePath) { + this.caseName = caseName; + this.nodePath = nodePath; + } + + public String getCaseName() { + return caseName; + } + + public String getNodePath() { + return nodePath; + } + } + + /** * Constucts an instance of a task for deleting case coordination service * nodes for which there is no longer a corresponding case. @@ -52,7 +78,74 @@ final class DeleteOrphanCaseNodesTask implements Runnable { DeleteOrphanCaseNodesTask(ProgressIndicator progress) { this.progress = progress; } + + + private CoordinationService getCoordinationService() { + progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc()); + logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc()); + CoordinationService coordinationService = null; + try { + coordinationService = CoordinationService.getInstance(); + } catch (CoordinationService.CoordinationServiceException ex) { + logger.log(Level.SEVERE, "Error connecting to the coordination service", ex); //NON-NLS + } + return coordinationService; + } + + + private List getNodePaths(CoordinationService coordinationService) { + progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes()); + logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes()); + List nodePaths = null; + try { + nodePaths = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); + // in the event that getNodeList returns null (but still successful) return empty list + if (nodePaths == null) + return new ArrayList(); + } catch (CoordinationService.CoordinationServiceException ex) { + logger.log(Level.SEVERE, "Error getting case znode list", ex); //NON-NLS + } catch (InterruptedException unused) { + logger.log(Level.WARNING, "Task cancelled while getting case znode list"); //NON-NLS + } + + return nodePaths; + } + + private void addIfExists(List paths, String path) { + if (path != null && !path.isEmpty()) + paths.add(path); + } + + private Map> getOrphanedNodes(List nodePaths) { + progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); + logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); + Map> nodePathsToDelete = new HashMap<>(); + for (String caseNodePath : nodePaths) { + if (isCaseNameNodePath(caseNodePath) || isCaseResourcesNodePath(caseNodePath) || isCaseAutoIngestLogNodePath(caseNodePath)) { + continue; + } + + final Path caseDirectoryPath = Paths.get(caseNodePath); + final File caseDirectory = caseDirectoryPath.toFile(); + if (!caseDirectory.exists()) { + String caseName = CoordinationServiceUtils.getCaseNameNodePath(caseDirectoryPath); + List paths = new ArrayList<>(); + + addIfExists(paths, CoordinationServiceUtils.getCaseNameNodePath(caseDirectoryPath)); + addIfExists(paths, CoordinationServiceUtils.getCaseResourcesNodePath(caseDirectoryPath)); + addIfExists(paths, CoordinationServiceUtils.getCaseAutoIngestLogNodePath(caseDirectoryPath)); + addIfExists(paths, CoordinationServiceUtils.getCaseDirectoryNodePath(caseDirectoryPath)); + nodePathsToDelete.put(caseName, paths); + + ++casesCount; + } + } + return nodePathsToDelete; + } + + + @Override @NbBundle.Messages({ "DeleteOrphanCaseNodesTask.progress.startMessage=Starting orphaned case znode cleanup", @@ -63,69 +156,21 @@ final class DeleteOrphanCaseNodesTask implements Runnable { public void run() { progress.start(Bundle.DeleteOrphanCaseNodesTask_progress_startMessage()); try { - progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc()); - logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc()); - CoordinationService coordinationService; - try { - coordinationService = CoordinationService.getInstance(); - } catch (CoordinationService.CoordinationServiceException ex) { - logger.log(Level.SEVERE, "Error connecting to the coordination service", ex); //NON-NLS + CoordinationService coordinationService = getCoordinationService(); + if (coordinationService == null) return; - } - progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes()); - logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes()); - List nodePaths; - try { - nodePaths = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); - } catch (CoordinationService.CoordinationServiceException ex) { - logger.log(Level.SEVERE, "Error getting case znode list", ex); //NON-NLS + List nodePaths = getNodePaths(coordinationService); + if (nodePaths == null) return; - } catch (InterruptedException unused) { - logger.log(Level.WARNING, "Task cancelled while getting case znode list"); //NON-NLS - return; - } - - progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); - logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); - for (String caseNodePath : nodePaths) { - if (isCaseNameNodePath(caseNodePath) || isCaseResourcesNodePath(caseNodePath) || isCaseAutoIngestLogNodePath(caseNodePath)) { - continue; - } - - final Path caseDirectoryPath = Paths.get(caseNodePath); - final File caseDirectory = caseDirectoryPath.toFile(); - if (!caseDirectory.exists()) { - String caseName = CoordinationServiceUtils.getCaseNameNodePath(caseDirectoryPath); - String nodePath = ""; // NON-NLS - try { - nodePath = CoordinationServiceUtils.getCaseNameNodePath(caseDirectoryPath); - deleteNode(coordinationService, caseName, nodePath); - - nodePath = CoordinationServiceUtils.getCaseResourcesNodePath(caseDirectoryPath); - deleteNode(coordinationService, caseName, nodePath); - - nodePath = CoordinationServiceUtils.getCaseAutoIngestLogNodePath(caseDirectoryPath); - deleteNode(coordinationService, caseName, nodePath); - - nodePath = CoordinationServiceUtils.getCaseDirectoryNodePath(caseDirectoryPath); - deleteNode(coordinationService, caseName, nodePath); - - ++casesCount; - - /* - * Back to looking for orphans... - */ - progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); - logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); - - } catch (InterruptedException unused) { - logger.log(Level.WARNING, String.format("Task cancelled while deleting orphaned znode %s for %s", nodePath, caseName)); //NON-NLS - return; - } - } - } + Map> orphanedNodes = getOrphanedNodes(nodePaths); + + boolean continueDelete = displayToUser(orphanedNodes); + + if (continueDelete) + deleteNodes(coordinationService, orphanedNodes); + } catch (Exception ex) { /* * This is an unexpected runtime exceptions firewall. It is here @@ -141,6 +186,24 @@ final class DeleteOrphanCaseNodesTask implements Runnable { progress.finish(); } } + + + private void deleteNodes(CoordinationService coordinationService, Map> orphanedNodes) { + String caseName = null; + String nodePath = null; + try { + for (Entry> caseNodePaths : orphanedNodes.entrySet()) { + caseName = caseNodePaths.getKey(); + for (String path : caseNodePaths.getValue()) { + nodePath = path; + deleteNode(coordinationService, caseName, nodePath); + } + } + } catch (InterruptedException unused) { + logger.log(Level.WARNING, String.format("Task cancelled while deleting orphaned znode %s for %s", nodePath, caseName)); //NON-NLS + return; + } + } /** * Attempts to delete a case coordination service node. From 73310566332a1394c374cbc29ebe03ec9bc434c0 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 3 Apr 2020 15:33:30 -0400 Subject: [PATCH 2/8] removed unnecessary code --- .../autoingest/DeleteOrphanCaseNodesTask.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java index 949bf0e8f2..d13761f9b8 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java @@ -50,25 +50,6 @@ final class DeleteOrphanCaseNodesTask implements Runnable { private int casesCount; - final static class OrphanCaseNodeEntry { - final String caseName; - final String nodePath; - - public OrphanCaseNodeEntry(String caseName, String nodePath) { - this.caseName = caseName; - this.nodePath = nodePath; - } - - public String getCaseName() { - return caseName; - } - - public String getNodePath() { - return nodePath; - } - } - - /** * Constucts an instance of a task for deleting case coordination service * nodes for which there is no longer a corresponding case. From c6a317ece00c0f6f764548cdb368819fa2ba4ed9 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 6 Apr 2020 09:13:39 -0400 Subject: [PATCH 3/8] added dialog for orphaned nodes --- .../experimental/autoingest/Bundle.properties | 4 + .../DeleteOrphanCaseNodesDialog.form | 123 ++++++++++++++ .../DeleteOrphanCaseNodesDialog.java | 156 ++++++++++++++++++ .../autoingest/DeleteOrphanCaseNodesTask.java | 38 ++++- 4 files changed, 317 insertions(+), 4 deletions(-) create mode 100644 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form create mode 100644 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index f3081bef89..4de3b58397 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -257,3 +257,7 @@ CasesDashboardTopComponent.refreshButton.text=Refresh AutoIngestCasesDeletionDialog.jLabel1.text=Progress CasesDashboardTopComponent.deleteOrphanCaseNodesButton.text=Delete Orphan Case Znodes CasesDashboardTopComponent.deleteOrphanManifestNodesButton.text=Delete Orphan Manifest Znodes +DeleteOrphanCaseNodesDialog.descriptionText.text=The following znodes are no longer have an associated case. Would you like to delete them? +DeleteOrphanCaseNodesDialog.okButton.text=OK +DeleteOrphanCaseNodesDialog.cancelButton.text=Cancel +DeleteOrphanCaseNodesDialog.titleText.text=Delete The Following Znodes? diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form new file mode 100644 index 0000000000..af67571b2d --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form @@ -0,0 +1,123 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java new file mode 100644 index 0000000000..76ef98d590 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java @@ -0,0 +1,156 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2020-2020 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * 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 org.sleuthkit.autopsy.experimental.autoingest; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * This dialog shows the system administrator the orphaned znodes to be deleted. + * If 'OK' is selected, isOkSelected() will return true. + */ +public class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { + private static final String NEW_LINE = System.getProperty("line.separator"); + private static final String DEFAULT_INDENT = " "; + private static final String COLON = ":"; + + private boolean okSelected = false; + + /** + * Creates new form DeleteOrphanCaseNodesDialog + */ + public DeleteOrphanCaseNodesDialog(java.awt.Frame parent, boolean modal, Map> znodes) { + super(parent, modal); + initComponents(); + additionalInit(znodes); + } + + private void additionalInit(Map> znodes) { + String textAreaText = ""; + if (znodes != null) { + textAreaText = znodes.entrySet().stream().map((kv) -> { + return Stream.concat( + Stream.of(kv.getKey() + COLON), + kv.getValue().stream().map((node) -> DEFAULT_INDENT + node)) + .collect(Collectors.joining(NEW_LINE)); + }) + .collect(Collectors.joining(NEW_LINE)); + } + + znodesTextArea.setText(textAreaText); + } + + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.JLabel descriptionText = new javax.swing.JLabel(); + javax.swing.JScrollPane jScrollPane = new javax.swing.JScrollPane(); + znodesTextArea = new javax.swing.JTextArea(); + javax.swing.JButton cancelButton = new javax.swing.JButton(); + javax.swing.JButton okButton = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle(org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.titleText.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(descriptionText, org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.descriptionText.text")); // NOI18N + descriptionText.setVerticalAlignment(javax.swing.SwingConstants.TOP); + + znodesTextArea.setEditable(false); + znodesTextArea.setColumns(20); + znodesTextArea.setLineWrap(true); + znodesTextArea.setRows(5); + jScrollPane.setViewportView(znodesTextArea); + + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.cancelButton.text")); // NOI18N + cancelButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.okButton.text")); // NOI18N + okButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(descriptionText, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(okButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(descriptionText) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 238, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(okButton)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed + okSelected = true; + dispose(); + }//GEN-LAST:event_okButtonActionPerformed + + private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed + dispose(); + }//GEN-LAST:event_cancelButtonActionPerformed + + /** + * If the system administrator selected OK. + * @return Whether or not 'OK' was selected by the system administrator. + */ + public boolean isOkSelected() { + return okSelected; + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JTextArea znodesTextArea; + // End of variables declaration//GEN-END:variables +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java index d13761f9b8..5521f46943 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019-2019 Basis Technology Corp. + * Copyright 2019-2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,11 +23,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import java.util.logging.Level; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils; @@ -61,6 +59,10 @@ final class DeleteOrphanCaseNodesTask implements Runnable { } + /** + * Retrieves an instance of the coordination service in order to fetch znodes and potentially delete. + * @return The coordination service or null on error. + */ private CoordinationService getCoordinationService() { progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc()); logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc()); @@ -74,6 +76,11 @@ final class DeleteOrphanCaseNodesTask implements Runnable { } + /** + * Retrieves node paths for cases. + * @param coordinationService The coordination service to use in order to fetch the node paths. + * @return The list of node paths for cases. + */ private List getNodePaths(CoordinationService coordinationService) { progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes()); logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes()); @@ -98,6 +105,11 @@ final class DeleteOrphanCaseNodesTask implements Runnable { paths.add(path); } + /** + * Determines orphaned znode paths. + * @param nodePaths The list of case node paths. + * @return The list of orphaned node paths. + */ private Map> getOrphanedNodes(List nodePaths) { progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); @@ -125,6 +137,16 @@ final class DeleteOrphanCaseNodesTask implements Runnable { return nodePathsToDelete; } + /** + * prompts the user with a list of orphaned znodes. + * @param orphanedNodes The orphaned znodes. + * @return True if the user would like to proceed deleting the znodes. + */ + private boolean promptUser(Map> orphanedNodes) { + DeleteOrphanCaseNodesDialog dialog = new DeleteOrphanCaseNodesDialog(null, true, orphanedNodes); + return dialog.isOkSelected(); + } + @Override @@ -147,7 +169,7 @@ final class DeleteOrphanCaseNodesTask implements Runnable { Map> orphanedNodes = getOrphanedNodes(nodePaths); - boolean continueDelete = displayToUser(orphanedNodes); + boolean continueDelete = promptUser(orphanedNodes); if (continueDelete) deleteNodes(coordinationService, orphanedNodes); @@ -169,6 +191,14 @@ final class DeleteOrphanCaseNodesTask implements Runnable { } + /** + * Deletes the orphaned znodes provided in the 'orphanedNodes' variable. + * @param coordinationService The coordination service to use for deletion. + * @param orphanedNodes A mapping of case to the orphaned znodes. + * + * @throws InterruptedException If the thread executing this task is + * interrupted during the delete operation. + */ private void deleteNodes(CoordinationService coordinationService, Map> orphanedNodes) { String caseName = null; String nodePath = null; From 664997021661cf2040ef62f1b234aeddf130bd3e Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 6 Apr 2020 16:21:27 -0400 Subject: [PATCH 4/8] updated dialog --- .../DeleteOrphanCaseNodesDialog.form | 5 +++- .../DeleteOrphanCaseNodesDialog.java | 27 ++++++++++++++----- .../autoingest/DeleteOrphanCaseNodesTask.java | 8 +++--- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form index af67571b2d..dd37628a82 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form @@ -6,6 +6,9 @@ + + + @@ -48,7 +51,7 @@ - + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java index 76ef98d590..451caecd86 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java @@ -22,14 +22,17 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.swing.JFrame; +import org.openide.windows.WindowManager; /** * This dialog shows the system administrator the orphaned znodes to be deleted. * If 'OK' is selected, isOkSelected() will return true. */ -public class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { +class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { private static final String NEW_LINE = System.getProperty("line.separator"); - private static final String DEFAULT_INDENT = " "; + private static final String CASE_SPACING = NEW_LINE + NEW_LINE; + private static final String DEFAULT_INDENT = " "; private static final String COLON = ":"; private boolean okSelected = false; @@ -37,12 +40,21 @@ public class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { /** * Creates new form DeleteOrphanCaseNodesDialog */ - public DeleteOrphanCaseNodesDialog(java.awt.Frame parent, boolean modal, Map> znodes) { - super(parent, modal); + DeleteOrphanCaseNodesDialog(Map> znodes) { + super((JFrame) WindowManager.getDefault().getMainWindow(), null, true); initComponents(); additionalInit(znodes); } + /** + * displays this dialog as child of main window. + */ + void display() { + this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + setVisible(true); + } + + private void additionalInit(Map> znodes) { String textAreaText = ""; if (znodes != null) { @@ -52,7 +64,7 @@ public class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { kv.getValue().stream().map((node) -> DEFAULT_INDENT + node)) .collect(Collectors.joining(NEW_LINE)); }) - .collect(Collectors.joining(NEW_LINE)); + .collect(Collectors.joining(CASE_SPACING)); } znodesTextArea.setText(textAreaText); @@ -76,6 +88,7 @@ public class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setTitle(org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.titleText.text")); // NOI18N + setMinimumSize(new java.awt.Dimension(535, 226)); org.openide.awt.Mnemonics.setLocalizedText(descriptionText, org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.descriptionText.text")); // NOI18N descriptionText.setVerticalAlignment(javax.swing.SwingConstants.TOP); @@ -122,7 +135,7 @@ public class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { .addContainerGap() .addComponent(descriptionText) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 238, Short.MAX_VALUE) + .addComponent(jScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 252, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cancelButton) @@ -146,7 +159,7 @@ public class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { * If the system administrator selected OK. * @return Whether or not 'OK' was selected by the system administrator. */ - public boolean isOkSelected() { + boolean isOkSelected() { return okSelected; } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java index 5521f46943..5facd5d6ff 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java @@ -130,8 +130,6 @@ final class DeleteOrphanCaseNodesTask implements Runnable { addIfExists(paths, CoordinationServiceUtils.getCaseAutoIngestLogNodePath(caseDirectoryPath)); addIfExists(paths, CoordinationServiceUtils.getCaseDirectoryNodePath(caseDirectoryPath)); nodePathsToDelete.put(caseName, paths); - - ++casesCount; } } return nodePathsToDelete; @@ -143,7 +141,8 @@ final class DeleteOrphanCaseNodesTask implements Runnable { * @return True if the user would like to proceed deleting the znodes. */ private boolean promptUser(Map> orphanedNodes) { - DeleteOrphanCaseNodesDialog dialog = new DeleteOrphanCaseNodesDialog(null, true, orphanedNodes); + DeleteOrphanCaseNodesDialog dialog = new DeleteOrphanCaseNodesDialog(orphanedNodes); + dialog.display(); return dialog.isOkSelected(); } @@ -168,6 +167,8 @@ final class DeleteOrphanCaseNodesTask implements Runnable { return; Map> orphanedNodes = getOrphanedNodes(nodePaths); + if (orphanedNodes == null || orphanedNodes.isEmpty()) + return; boolean continueDelete = promptUser(orphanedNodes); @@ -209,6 +210,7 @@ final class DeleteOrphanCaseNodesTask implements Runnable { nodePath = path; deleteNode(coordinationService, caseName, nodePath); } + ++casesCount; } } catch (InterruptedException unused) { logger.log(Level.WARNING, String.format("Task cancelled while deleting orphaned znode %s for %s", nodePath, caseName)); //NON-NLS From 7ff4702c2b486c57b2c0fce689d060b7a7602fae Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 7 Apr 2020 13:39:08 -0400 Subject: [PATCH 5/8] updated jdialog format --- .../experimental/autoingest/Bundle.properties | 3 +- .../autoingest/Bundle.properties-MERGED | 21 ++- .../DeleteOrphanCaseNodesDialog.form | 11 +- .../DeleteOrphanCaseNodesDialog.java | 69 ++++++---- .../autoingest/DeleteOrphanCaseNodesTask.java | 124 +++++++++++------- 5 files changed, 141 insertions(+), 87 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index 4de3b58397..2b25c96245 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -257,7 +257,8 @@ CasesDashboardTopComponent.refreshButton.text=Refresh AutoIngestCasesDeletionDialog.jLabel1.text=Progress CasesDashboardTopComponent.deleteOrphanCaseNodesButton.text=Delete Orphan Case Znodes CasesDashboardTopComponent.deleteOrphanManifestNodesButton.text=Delete Orphan Manifest Znodes -DeleteOrphanCaseNodesDialog.descriptionText.text=The following znodes are no longer have an associated case. Would you like to delete them? +DeleteOrphanCaseNodesDialog.descriptionText.text=The following cases have orphaned znodes. Would you like to delete them? DeleteOrphanCaseNodesDialog.okButton.text=OK DeleteOrphanCaseNodesDialog.cancelButton.text=Cancel DeleteOrphanCaseNodesDialog.titleText.text=Delete The Following Znodes? +DeleteOrphanCaseNodesDialog.lblNodeCount.text= diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties-MERGED b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties-MERGED index 46c6d587fc..adb7693b48 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties-MERGED +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties-MERGED @@ -89,10 +89,6 @@ AutoIngestControlPanel.runningTable.toolTipText=The Running table displays the c AutoIngestControlPanel.SharedConfigurationDisabled=Shared configuration disabled AutoIngestControlPanel.ShowLogFailed.Message=Case log file does not exist AutoIngestControlPanel.ShowLogFailed.Title=Unable to display case log -# {0} - case db status -# {1} - search svc Status -# {2} - coord svc Status -# {3} - msg broker status AutoIngestControlPanel.tbServicesStatusMessage.Message=Case databases {0}, keyword search {1}, coordination {2}, messaging {3} AutoIngestControlPanel.tbServicesStatusMessage.Message.Down=down AutoIngestControlPanel.tbServicesStatusMessage.Message.Unknown=unknown @@ -186,25 +182,23 @@ DeleteCaseTask.progress.acquiringManifestLocks=Acquiring exclusive manifest file DeleteCaseTask.progress.connectingToCoordSvc=Connecting to the coordination service... DeleteCaseTask.progress.deletingCaseDirCoordSvcNode=Deleting case directory znode... DeleteCaseTask.progress.deletingCaseNameCoordSvcNode=Deleting case name znode... -# {0} - data source path DeleteCaseTask.progress.deletingDataSource=Deleting data source {0}... DeleteCaseTask.progress.deletingJobLogLockNode=Deleting case auto ingest log znode... -# {0} - manifest file path DeleteCaseTask.progress.deletingManifest=Deleting manifest file {0}... -# {0} - manifest file path DeleteCaseTask.progress.deletingManifestFileNode=Deleting the manifest file znode for {0}... DeleteCaseTask.progress.deletingResourcesLockNode=Deleting case resources znode... DeleteCaseTask.progress.gettingManifestPaths=Getting manifest file paths... -# {0} - manifest file path DeleteCaseTask.progress.lockingManifest=Locking manifest file {0}... DeleteCaseTask.progress.openingCaseDatabase=Opening the case database... DeleteCaseTask.progress.openingCaseMetadataFile=Opening case metadata file... -# {0} - manifest file path DeleteCaseTask.progress.parsingManifest=Parsing manifest file {0}... -# {0} - manifest file path DeleteCaseTask.progress.releasingManifestLock=Releasing lock on the manifest file {0}... DeleteCaseTask.progress.startMessage=Starting deletion... DeleteOrphanCaseNodesAction.progressDisplayName=Cleanup Case Znodes +# {0} - item count +DeleteOrphanCaseNodesDialog.additionalInit.lblNodeCount.text=Znodes found: {0} +# {0} - item count +DeleteOrphanCaseNodesDialog.additionalInit.znodesTextArea.countMessage=ZNODES FOUND: {0} DeleteOrphanCaseNodesTask.progress.connectingToCoordSvc=Connecting to the coordination service # {0} - node path DeleteOrphanCaseNodesTask.progress.deletingOrphanedCaseNode=Deleting orphaned case znode {0} @@ -213,7 +207,6 @@ DeleteOrphanCaseNodesTask.progress.lookingForOrphanedCaseZnodes=Looking for orph DeleteOrphanCaseNodesTask.progress.startMessage=Starting orphaned case znode cleanup DeleteOrphanManifestNodesAction.progressDisplayName=Cleanup Manifest File Znodes DeleteOrphanManifestNodesTask.progress.connectingToCoordSvc=Connecting to the coordination service -# {0} - node path DeleteOrphanManifestNodesTask.progress.deletingOrphanedManifestNode=Deleting orphaned manifest file znode {0} DeleteOrphanManifestNodesTask.progress.gettingManifestNodes=Querying the coordination service for manifest file znodes DeleteOrphanManifestNodesTask.progress.lookingForOrphanedManifestFileZnodes=Looking for orphaned manifest file znodes @@ -222,7 +215,6 @@ HINT_CasesDashboardTopComponent=This is an adminstrative dashboard for multi-use OpenAutoIngestLogAction.deletedLogErrorMsg=The case auto ingest log has been deleted. OpenAutoIngestLogAction.logOpenFailedErrorMsg=Failed to open case auto ingest log. See application log for details. OpenAutoIngestLogAction.menuItemText=Open Auto Ingest Log File -# {0} - caseErrorMessage OpenCaseAction.errorMsg=Failed to open case: {0} OpenCaseAction.menuItemText=Open OpenIDE-Module-Long-Description=This module contains features that are being developed by Basis Technology and are not part of the default Autopsy distribution. You can enable this module to use the new features. The features should be stable, but their exact behavior and API are subject to change.\n\nWe make no guarantee that the API of this module will not change, so developers should be careful when relying on it. @@ -456,3 +448,8 @@ CasesDashboardTopComponent.refreshButton.text=Refresh AutoIngestCasesDeletionDialog.jLabel1.text=Progress CasesDashboardTopComponent.deleteOrphanCaseNodesButton.text=Delete Orphan Case Znodes CasesDashboardTopComponent.deleteOrphanManifestNodesButton.text=Delete Orphan Manifest Znodes +DeleteOrphanCaseNodesDialog.descriptionText.text=The following cases have orphaned znodes. Would you like to delete them? +DeleteOrphanCaseNodesDialog.okButton.text=OK +DeleteOrphanCaseNodesDialog.cancelButton.text=Cancel +DeleteOrphanCaseNodesDialog.titleText.text=Delete The Following Znodes? +DeleteOrphanCaseNodesDialog.lblNodeCount.text= diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form index dd37628a82..8b314a48d7 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.form @@ -35,7 +35,8 @@ - + + @@ -56,6 +57,7 @@ + @@ -122,5 +124,12 @@ + + + + + + + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java index 451caecd86..72ecfe5b46 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java @@ -18,34 +18,35 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.swing.JFrame; import org.openide.windows.WindowManager; +import org.openide.util.NbBundle.Messages; /** * This dialog shows the system administrator the orphaned znodes to be deleted. * If 'OK' is selected, isOkSelected() will return true. */ class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { + private static final String NEW_LINE = System.getProperty("line.separator"); - private static final String CASE_SPACING = NEW_LINE + NEW_LINE; - private static final String DEFAULT_INDENT = " "; - private static final String COLON = ":"; - + private boolean okSelected = false; /** * Creates new form DeleteOrphanCaseNodesDialog + * + * @param zNodeCases The list of cases with nodes to be deleted */ - DeleteOrphanCaseNodesDialog(Map> znodes) { + DeleteOrphanCaseNodesDialog(Collection zNodeCases) { super((JFrame) WindowManager.getDefault().getMainWindow(), null, true); initComponents(); - additionalInit(znodes); + additionalInit(zNodeCases); } - + /** * displays this dialog as child of main window. */ @@ -53,23 +54,26 @@ class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); setVisible(true); } - - - private void additionalInit(Map> znodes) { - String textAreaText = ""; - if (znodes != null) { - textAreaText = znodes.entrySet().stream().map((kv) -> { - return Stream.concat( - Stream.of(kv.getKey() + COLON), - kv.getValue().stream().map((node) -> DEFAULT_INDENT + node)) - .collect(Collectors.joining(NEW_LINE)); - }) - .collect(Collectors.joining(CASE_SPACING)); - } - + + @Messages({ + "# {0} - item count", + "DeleteOrphanCaseNodesDialog.additionalInit.lblNodeCount.text=Znodes found: {0}", + "# {0} - item count", + "DeleteOrphanCaseNodesDialog.additionalInit.znodesTextArea.countMessage=ZNODES FOUND: {0}" + }) + private void additionalInit(Collection zNodeCases) { + List casesList = (zNodeCases == null) ? new ArrayList<>() : new ArrayList<>(zNodeCases); + int count = casesList.size(); + casesList.sort(Comparator.comparing(String::toString)); + String textAreaText = Bundle.DeleteOrphanCaseNodesDialog_additionalInit_znodesTextArea_countMessage(count) + + NEW_LINE + + NEW_LINE + + String.join(NEW_LINE, casesList); + znodesTextArea.setText(textAreaText); + + lblNodeCount.setText(Bundle.DeleteOrphanCaseNodesDialog_additionalInit_lblNodeCount_text(count)); } - /** * This method is called from within the constructor to initialize the form. @@ -85,6 +89,7 @@ class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { znodesTextArea = new javax.swing.JTextArea(); javax.swing.JButton cancelButton = new javax.swing.JButton(); javax.swing.JButton okButton = new javax.swing.JButton(); + lblNodeCount = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setTitle(org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.titleText.text")); // NOI18N @@ -113,6 +118,8 @@ class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { } }); + org.openide.awt.Mnemonics.setLocalizedText(lblNodeCount, org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.lblNodeCount.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( @@ -123,7 +130,8 @@ class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { .addComponent(jScrollPane, javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(descriptionText, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) + .addComponent(lblNodeCount, javax.swing.GroupLayout.PREFERRED_SIZE, 310, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(okButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(cancelButton))) @@ -139,7 +147,8 @@ class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cancelButton) - .addComponent(okButton)) + .addComponent(okButton) + .addComponent(lblNodeCount)) .addContainerGap()) ); @@ -157,13 +166,15 @@ class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { /** * If the system administrator selected OK. - * @return Whether or not 'OK' was selected by the system administrator. + * + * @return Whether or not 'OK' was selected by the system administrator. */ boolean isOkSelected() { return okSelected; } - + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel lblNodeCount; private javax.swing.JTextArea znodesTextArea; // End of variables declaration//GEN-END:variables } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java index 5facd5d6ff..14e7cbe10e 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java @@ -19,14 +19,17 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.io.File; +import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; +import javax.swing.SwingUtilities; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils; import static org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils.isCaseAutoIngestLogNodePath; @@ -44,10 +47,9 @@ final class DeleteOrphanCaseNodesTask implements Runnable { private static final Logger logger = AutoIngestDashboardLogger.getLogger(); private final ProgressIndicator progress; - private int nodesCount; - private int casesCount; + private int nodesCount = 0; + private int casesCount = 0; - /** * Constucts an instance of a task for deleting case coordination service * nodes for which there is no longer a corresponding case. @@ -57,11 +59,12 @@ final class DeleteOrphanCaseNodesTask implements Runnable { DeleteOrphanCaseNodesTask(ProgressIndicator progress) { this.progress = progress; } - - + /** - * Retrieves an instance of the coordination service in order to fetch znodes and potentially delete. - * @return The coordination service or null on error. + * Retrieves an instance of the coordination service in order to fetch + * znodes and potentially delete. + * + * @return The coordination service or null on error. */ private CoordinationService getCoordinationService() { progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc()); @@ -74,12 +77,14 @@ final class DeleteOrphanCaseNodesTask implements Runnable { } return coordinationService; } - - + /** * Retrieves node paths for cases. - * @param coordinationService The coordination service to use in order to fetch the node paths. - * @return The list of node paths for cases. + * + * @param coordinationService The coordination service to use in order to + * fetch the node paths. + * + * @return The list of node paths for cases. */ private List getNodePaths(CoordinationService coordinationService) { progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes()); @@ -88,27 +93,30 @@ final class DeleteOrphanCaseNodesTask implements Runnable { try { nodePaths = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); // in the event that getNodeList returns null (but still successful) return empty list - if (nodePaths == null) + if (nodePaths == null) { return new ArrayList(); + } } catch (CoordinationService.CoordinationServiceException ex) { logger.log(Level.SEVERE, "Error getting case znode list", ex); //NON-NLS } catch (InterruptedException unused) { logger.log(Level.WARNING, "Task cancelled while getting case znode list"); //NON-NLS } - + return nodePaths; } - private void addIfExists(List paths, String path) { - if (path != null && !path.isEmpty()) + if (path != null && !path.isEmpty()) { paths.add(path); + } } - + /** * Determines orphaned znode paths. - * @param nodePaths The list of case node paths. - * @return The list of orphaned node paths. + * + * @param nodePaths The list of case node paths. + * + * @return The list of orphaned node paths. */ private Map> getOrphanedNodes(List nodePaths) { progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); @@ -124,7 +132,7 @@ final class DeleteOrphanCaseNodesTask implements Runnable { if (!caseDirectory.exists()) { String caseName = CoordinationServiceUtils.getCaseNameNodePath(caseDirectoryPath); List paths = new ArrayList<>(); - + addIfExists(paths, CoordinationServiceUtils.getCaseNameNodePath(caseDirectoryPath)); addIfExists(paths, CoordinationServiceUtils.getCaseResourcesNodePath(caseDirectoryPath)); addIfExists(paths, CoordinationServiceUtils.getCaseAutoIngestLogNodePath(caseDirectoryPath)); @@ -134,20 +142,49 @@ final class DeleteOrphanCaseNodesTask implements Runnable { } return nodePathsToDelete; } - + + /** + * Boxed boolean so that promptUser method can set a value on a final object + * from custom jdialog message. + */ + private class PromptResult { + + private boolean value = false; + + boolean getValue() { + return value; + } + + void setValue(boolean value) { + this.value = value; + } + + } + /** * prompts the user with a list of orphaned znodes. - * @param orphanedNodes The orphaned znodes. - * @return True if the user would like to proceed deleting the znodes. + * + * @param orphanedNodes The orphaned znode cases. + * + * @return True if the user would like to proceed deleting the znodes. */ - private boolean promptUser(Map> orphanedNodes) { - DeleteOrphanCaseNodesDialog dialog = new DeleteOrphanCaseNodesDialog(orphanedNodes); - dialog.display(); - return dialog.isOkSelected(); + private boolean promptUser(Collection orphanedNodes) { + final PromptResult dialogResult = new PromptResult(); + ; + try { + SwingUtilities.invokeAndWait(() -> { + DeleteOrphanCaseNodesDialog dialog = new DeleteOrphanCaseNodesDialog(orphanedNodes); + dialog.display(); + dialogResult.setValue(dialog.isOkSelected()); + }); + + return dialogResult.getValue(); + } catch (InterruptedException | InvocationTargetException e) { + logger.log(Level.WARNING, "Task cancelled while confirmingg case znodes to delete"); //NON-NLS + return false; + } } - - - + @Override @NbBundle.Messages({ "DeleteOrphanCaseNodesTask.progress.startMessage=Starting orphaned case znode cleanup", @@ -159,22 +196,22 @@ final class DeleteOrphanCaseNodesTask implements Runnable { progress.start(Bundle.DeleteOrphanCaseNodesTask_progress_startMessage()); try { CoordinationService coordinationService = getCoordinationService(); - if (coordinationService == null) + if (coordinationService == null) { return; + } List nodePaths = getNodePaths(coordinationService); - if (nodePaths == null) + if (nodePaths == null) { return; + } Map> orphanedNodes = getOrphanedNodes(nodePaths); - if (orphanedNodes == null || orphanedNodes.isEmpty()) - return; - - boolean continueDelete = promptUser(orphanedNodes); - - if (continueDelete) + boolean continueDelete = promptUser(orphanedNodes.keySet()); + + if (continueDelete) { deleteNodes(coordinationService, orphanedNodes); - + } + } catch (Exception ex) { /* * This is an unexpected runtime exceptions firewall. It is here @@ -190,13 +227,13 @@ final class DeleteOrphanCaseNodesTask implements Runnable { progress.finish(); } } - - + /** * Deletes the orphaned znodes provided in the 'orphanedNodes' variable. - * @param coordinationService The coordination service to use for deletion. - * @param orphanedNodes A mapping of case to the orphaned znodes. - * + * + * @param coordinationService The coordination service to use for deletion. + * @param orphanedNodes A mapping of case to the orphaned znodes. + * * @throws InterruptedException If the thread executing this task is * interrupted during the delete operation. */ @@ -214,7 +251,6 @@ final class DeleteOrphanCaseNodesTask implements Runnable { } } catch (InterruptedException unused) { logger.log(Level.WARNING, String.format("Task cancelled while deleting orphaned znode %s for %s", nodePath, caseName)); //NON-NLS - return; } } From bf18ee70cb7cb66f110c716f45ead0af08782333 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 7 Apr 2020 13:48:07 -0400 Subject: [PATCH 6/8] address codacy review --- .../experimental/autoingest/DeleteOrphanCaseNodesDialog.java | 1 + .../experimental/autoingest/DeleteOrphanCaseNodesTask.java | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java index 72ecfe5b46..3c8aacb86e 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesDialog.java @@ -31,6 +31,7 @@ import org.openide.util.NbBundle.Messages; * If 'OK' is selected, isOkSelected() will return true. */ class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog { + private static final long serialVersionUID = 1L; private static final String NEW_LINE = System.getProperty("line.separator"); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java index 14e7cbe10e..58ff05e00d 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java @@ -155,7 +155,7 @@ final class DeleteOrphanCaseNodesTask implements Runnable { return value; } - void setValue(boolean value) { + void isValue(boolean value) { this.value = value; } @@ -170,7 +170,6 @@ final class DeleteOrphanCaseNodesTask implements Runnable { */ private boolean promptUser(Collection orphanedNodes) { final PromptResult dialogResult = new PromptResult(); - ; try { SwingUtilities.invokeAndWait(() -> { DeleteOrphanCaseNodesDialog dialog = new DeleteOrphanCaseNodesDialog(orphanedNodes); From bd06d740140a2ef3119321c319a3933b1e542536 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 7 Apr 2020 14:02:24 -0400 Subject: [PATCH 7/8] fix typo --- .../experimental/autoingest/DeleteOrphanCaseNodesTask.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java index 58ff05e00d..bc2371104d 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java @@ -151,11 +151,11 @@ final class DeleteOrphanCaseNodesTask implements Runnable { private boolean value = false; - boolean getValue() { + boolean isValue() { return value; } - void isValue(boolean value) { + void setValue(boolean value) { this.value = value; } @@ -177,7 +177,7 @@ final class DeleteOrphanCaseNodesTask implements Runnable { dialogResult.setValue(dialog.isOkSelected()); }); - return dialogResult.getValue(); + return dialogResult.isValue(); } catch (InterruptedException | InvocationTargetException e) { logger.log(Level.WARNING, "Task cancelled while confirmingg case znodes to delete"); //NON-NLS return false; From 4d72ae14b0b9400cd5cdb9294bfc7edd099e7509 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 9 Apr 2020 08:08:25 -0400 Subject: [PATCH 8/8] changed spelling error --- .../experimental/autoingest/DeleteOrphanCaseNodesTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java index bc2371104d..63a3051d9b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DeleteOrphanCaseNodesTask.java @@ -179,7 +179,7 @@ final class DeleteOrphanCaseNodesTask implements Runnable { return dialogResult.isValue(); } catch (InterruptedException | InvocationTargetException e) { - logger.log(Level.WARNING, "Task cancelled while confirmingg case znodes to delete"); //NON-NLS + logger.log(Level.WARNING, "Task cancelled while confirming case znodes to delete"); //NON-NLS return false; } }