diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 25e17dd3eb..987b2ffe78 100755 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -244,6 +244,46 @@ org.netbeans.libs.junit4 + + org.netbeans.modules.jellytools.java + + + + org.netbeans.modules.jellytools.platform + + + + org.netbeans.modules.jemmy + + + + org.netbeans.modules.nbjunit + + + + + qa-functional + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.jellytools.java + + + + org.netbeans.modules.jellytools.platform + + + + org.netbeans.modules.jemmy + + + + org.netbeans.modules.nbjunit + + + @@ -269,6 +309,7 @@ org.sleuthkit.autopsy.events org.sleuthkit.autopsy.externalresults org.sleuthkit.autopsy.filesearch + org.sleuthkit.autopsy.guiutils org.sleuthkit.autopsy.ingest org.sleuthkit.autopsy.keywordsearchservice org.sleuthkit.autopsy.menuactions diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java b/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java deleted file mode 100755 index 795b636b35..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AutoIngestCasePanelInterface.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 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.casemodule; - -import javax.swing.JDialog; - -/** - * Interface for startup window implementations - */ -public interface AutoIngestCasePanelInterface { - - public void addWindowStateListener(JDialog parent); -} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 25b43a423a..60db8edaf8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -1,10 +1,10 @@ -CTL_AddImage=Add Data Source... +CTL_AddImage=Add Data Source CTL_AddImageButton=Add Data Source CTL_CaseCloseAct=Close Case -CTL_CaseNewAction=New Case... -CTL_CasePropertiesAction=Case Properties... +CTL_CaseNewAction=New Case +CTL_CasePropertiesAction=Case Properties CTL_CaseDeleteAction=Delete Case -CTL_OpenAction=Open Case... +CTL_CaseOpenAction=Open Case Menu/Case/OpenRecentCase=Open Recent Case CTL_CaseDeleteAction=Delete Case OpenIDE-Module-Name=Case @@ -210,11 +210,32 @@ CasePropertiesPanel.lbDbName.text=Database Name: CasePropertiesPanel.lbDbType.text=Case Type: CasePropertiesPanel.caseNumberLabel.text=Case Number: LocalDiskPanel.changeDatabasePathCheckbox.text=Update case to use VHD file upon completion -CueBannerPanel.openAutoIngestCaseButton.text= +CueBannerPanel.openMultiUserCaseButton.text= CueBannerPanel.openExistingCaseButton.text= CueBannerPanel.openRecentCaseButton.text= CueBannerPanel.createNewCaseButton.text= CueBannerPanel.createNewCaseLabel.text=Create New Case CueBannerPanel.openRecentCaseLabel.text=Open Recent Case CueBannerPanel.openExistingCaseLabel.text=Open Existing Case -CueBannerPanel.openAutoIngestCaseLabel.text=Open Auto Ingest Case \ No newline at end of file +CueBannerPanel.openMultiUserCaseLabel.text=Open Multi-User Case +ReviewModeCasePanel.cannotOpenCase=Cannot Open Case +ReviewModeCasePanel.casePathNotFound=Case path not found +ReviewModeCasePanel.caseIsLocked=Single-user case is locked. +ReviewModeCasePanel.CaseHeaderText=Case +ReviewModeCasePanel.CreatedTimeHeaderText=Created Time +ReviewModeCasePanel.StatusIconHeaderText=Status +ReviewModeCasePanel.OutputFolderHeaderText=Output Folder +ReviewModeCasePanel.LastAccessedTimeHeaderText=Last Accessed Time +ReviewModeCasePanel.MetadataFileHeaderText=Metadata File +OpenMultiUserCasePanel.jLabel1.text=Recent Cases +OpenMultiUserCasePanel.openButton.text=Open +OpenMultiUserCasePanel.cancelButton.text=Cancel +MultiUserCasesPanel.rbWeeks.text=Weeks +MultiUserCasesPanel.rbDays.text=Days +MultiUserCasesPanel.bnShowLog.toolTipText=Display case log file for selected case +MultiUserCasesPanel.bnShowLog.text=&Show Auto Ingest Case Log +MultiUserCasesPanel.rbAllCases.text=Everything +MultiUserCasesPanel.bnRefresh.text=&Refresh +MultiUserCasesPanel.bnOpen.text=&Open +MultiUserCasesPanel.rbGroupLabel.text=Show cases accessed in the last 10: +MultiUserCasesPanel.rbMonths.text=Months diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index e212a125e9..de333e790f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -1,9 +1,9 @@ CTL_AddImageButton=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u8ffd\u52a0 CTL_CaseCloseAct=\u30b1\u30fc\u30b9\u3092\u9589\u3058\u308b -CTL_CaseNewAction=\u65b0\u898f\u30b1\u30fc\u30b9... -CTL_CasePropertiesAction=\u30b1\u30fc\u30b9\u30d7\u30ed\u30d1\u30c6\u30a3... +CTL_CaseNewAction=\u65b0\u898f\u30b1\u30fc\u30b9 +CTL_CasePropertiesAction=\u30b1\u30fc\u30b9\u30d7\u30ed\u30d1\u30c6\u30a3 CTL_CaseDeleteAction=\u30b1\u30fc\u30b9\u3092\u524a\u9664 -CTL_OpenAction=\u30b1\u30fc\u30b9\u3092\u958b\u304f... +CTL_CaseOpenAction=\u30b1\u30fc\u30b9\u3092\u958b\u304f Menu/Case/OpenRecentCase=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f CTL_CaseDeleteAction=\u30b1\u30fc\u30b9\u3092\u524a\u9664 OpenIDE-Module-Name=\u30b1\u30fc\u30b9 @@ -194,3 +194,6 @@ CueBannerPanel.createNewCaseLabel.text=\u65b0\u898f\u30b1\u30fc\u30b9\u3092\u4f5 CueBannerPanel.openRecentCaseLabel.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f CueBannerPanel.openExistingCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f CueBannerPanel.openAutoIngestCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f +OpenMultiUserCasePanel.openButton.text=\u958b\u304f +OpenMultiUserCasePanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb +OpenMultiUserCasePanel.jLabel1.text=\u6700\u8fd1\u958b\u3044\u305f\u30d5\u30a1\u30a4\u30eb diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java index 3ef30f2594..66e983b1ce 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java @@ -33,7 +33,6 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -45,13 +44,16 @@ import org.sleuthkit.autopsy.coreutils.Logger; final class CaseDeleteAction extends CallableSystemAction { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(CaseDeleteAction.class.getName()); + private static final Logger LOGGER = Logger.getLogger(CaseDeleteAction.class.getName()); CaseDeleteAction() { putValue(Action.NAME, NbBundle.getMessage(CaseDeleteAction.class, "CTL_CaseDeleteAction")); this.setEnabled(false); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { - setEnabled(null != evt.getNewValue() && UserPreferences.getMode() != UserPreferences.SelectedMode.REVIEW); + /* + * A value of 'null' signifies that there is no case open. + */ + setEnabled(null != evt.getNewValue()); }); } @@ -93,7 +95,7 @@ final class CaseDeleteAction extends CallableSystemAction { try { get(); } catch (InterruptedException | ExecutionException ex) { - logger.log(Level.SEVERE, String.format("Failed to delete case %s at %s", caseName, caseDirectory), ex); + LOGGER.log(Level.SEVERE, String.format("Failed to delete case %s at %s", caseName, caseDirectory), ex); JOptionPane.showMessageDialog( null, Bundle.Case_deleteCaseFailureMessageBox_message(ex.getLocalizedMessage()), @@ -108,7 +110,7 @@ final class CaseDeleteAction extends CallableSystemAction { }.execute(); } } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, "Case delete action called with no current case", ex); + LOGGER.log(Level.SEVERE, "Case delete action called with no current case", ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index 533cab58c5..e4ed92d897 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -141,7 +141,7 @@ public final class CaseOpenAction extends CallableSystemAction implements Action @Override public String getName() { - return NbBundle.getMessage(CaseOpenAction.class, "CTL_OpenAction"); + return NbBundle.getMessage(CaseOpenAction.class, "CTL_CaseOpenAction"); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java new file mode 100755 index 0000000000..7a12b69cf7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenMultiUserAction.java @@ -0,0 +1,91 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JDialog; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionRegistration; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.actions.CallableSystemAction; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.core.UserPreferences; + +/** + * The action associated with the Open Multi-User Case menu item via the + * layer.xml file. + * + * This action should only be invoked in the event dispatch thread (EDT). + */ +@ActionID(category = "Case", id = "org.sleuthkit.autopsy.casemodule.CaseOpenMultiUserAction") +@ActionReference(path = "Menu/Case", position = 102) +@ActionRegistration(displayName = "#CTL_CaseOpenMultiUserAction", lazy = false) +@NbBundle.Messages({"CTL_CaseOpenMultiUserAction=Open Multi-User Case"}) +public final class CaseOpenMultiUserAction extends CallableSystemAction implements ActionListener { + + private static final long serialVersionUID = 1L; + private static JDialog multiUserCaseWindow; + + private static final String DISPLAY_NAME = Bundle.CTL_CaseOpenMultiUserAction(); + + public CaseOpenMultiUserAction() {} + + @Override + public boolean isEnabled() { + return UserPreferences.getIsMultiUserModeEnabled(); + } + + /** + * Pops up a case selection panel to allow the user to select a multi-user + * case to open. + * + * @param event The action event. + */ + @Override + public void actionPerformed(ActionEvent event) { + if(multiUserCaseWindow == null) { + multiUserCaseWindow = MultiUserCasesDialog.getInstance(); + } + multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + multiUserCaseWindow.setVisible(true); + } + + @Override + public void performAction() { + actionPerformed(null); + } + + @Override + public String getName() { + return DISPLAY_NAME; + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + public boolean asynchronous() { + return false; // run on edt + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form index 75819e41d0..0d6525db8b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form @@ -28,14 +28,14 @@ - + - + @@ -66,9 +66,9 @@ - + - + @@ -216,13 +216,13 @@ - + - + @@ -237,18 +237,18 @@ - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 2d7b17458e..2c81d100e4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -26,14 +26,11 @@ import java.awt.event.KeyEvent; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JDialog; -import javax.swing.JPanel; import javax.swing.KeyStroke; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.AutoIngestCasePanelInterface; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.coreutils.NetworkUtils; /* * The panel in the default Autopsy startup window. @@ -41,14 +38,11 @@ import org.sleuthkit.autopsy.coreutils.NetworkUtils; public class CueBannerPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); - private static final String REVIEW_MODE_TITLE = "Cases" + " (" + LOCAL_HOST_NAME + ")"; /* * This is field is static for the sake of the closeOpenRecentCasesWindow * method. */ private static JDialog recentCasesWindow; - private static JDialog autoIngestCasePanelWindow; public static void closeOpenRecentCasesWindow() { if (null != recentCasesWindow) { @@ -56,15 +50,9 @@ public class CueBannerPanel extends javax.swing.JPanel { } } - public static void closeAutoIngestCasesWindow() { - if (null != autoIngestCasePanelWindow) { - autoIngestCasePanelWindow.setVisible(false); - } - } - public CueBannerPanel() { initComponents(); - customizeComponents(); + initRecentCasesWindow(); enableComponents(); } @@ -75,7 +63,7 @@ public class CueBannerPanel extends javax.swing.JPanel { ImageIcon icon = new ImageIcon(cl.getResource(welcomeLogo)); autopsyLogo.setIcon(icon); } - customizeComponents(); + initRecentCasesWindow(); enableComponents(); } @@ -90,11 +78,6 @@ public class CueBannerPanel extends javax.swing.JPanel { public void refresh() { enableComponents(); } - - private void customizeComponents() { - initRecentCasesWindow(); - initAutoIngestCasesWindow(); - } private void initRecentCasesWindow() { recentCasesWindow = new JDialog( @@ -118,39 +101,15 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.pack(); recentCasesWindow.setResizable(false); } - - private void initAutoIngestCasesWindow() { - autoIngestCasePanelWindow = new JDialog( - WindowManager.getDefault().getMainWindow(), - REVIEW_MODE_TITLE, - Dialog.ModalityType.APPLICATION_MODAL); - autoIngestCasePanelWindow.getRootPane().registerKeyboardAction( - e -> { - autoIngestCasePanelWindow.setVisible(false); - }, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - OpenRecentCasePanel recentCasesPanel = OpenRecentCasePanel.getInstance(); - recentCasesPanel.setCloseButtonActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - autoIngestCasePanelWindow.setVisible(false); - } - }); - AutoIngestCasePanelInterface autoIngestCasePanel = Lookup.getDefault().lookup(AutoIngestCasePanelInterface.class); - autoIngestCasePanel.addWindowStateListener(autoIngestCasePanelWindow); - autoIngestCasePanelWindow.add((JPanel)autoIngestCasePanel); - autoIngestCasePanelWindow.pack(); - autoIngestCasePanelWindow.setResizable(false); - } private void enableComponents() { boolean enableOpenRecentCaseButton = (RecentCases.getInstance().getTotalRecentCases() > 0); openRecentCaseButton.setEnabled(enableOpenRecentCaseButton); openRecentCaseLabel.setEnabled(enableOpenRecentCaseButton); - boolean showOpenAutoIngestCaseButton = (UserPreferences.getMode() == UserPreferences.SelectedMode.REVIEW); - openAutoIngestCaseButton.setVisible(showOpenAutoIngestCaseButton); - openAutoIngestCaseLabel.setVisible(showOpenAutoIngestCaseButton); + boolean enableOpenMultiUserCaseButton = UserPreferences.getIsMultiUserModeEnabled(); + openMultiUserCaseButton.setEnabled(enableOpenMultiUserCaseButton); + openMultiUserCaseLabel.setEnabled(enableOpenMultiUserCaseButton); } /** @@ -172,8 +131,8 @@ public class CueBannerPanel extends javax.swing.JPanel { openExistingCaseLabel = new javax.swing.JLabel(); closeButton = new javax.swing.JButton(); jSeparator1 = new javax.swing.JSeparator(); - openAutoIngestCaseButton = new javax.swing.JButton(); - openAutoIngestCaseLabel = new javax.swing.JLabel(); + openMultiUserCaseButton = new javax.swing.JButton(); + openMultiUserCaseLabel = new javax.swing.JLabel(); autopsyLogo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/welcome_logo.png"))); // NOI18N autopsyLogo.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.autopsyLogo.text")); // NOI18N @@ -229,21 +188,21 @@ public class CueBannerPanel extends javax.swing.JPanel { jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); - openAutoIngestCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N - openAutoIngestCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openAutoIngestCaseButton.text")); // NOI18N - openAutoIngestCaseButton.setBorder(null); - openAutoIngestCaseButton.setBorderPainted(false); - openAutoIngestCaseButton.setContentAreaFilled(false); - openAutoIngestCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); - openAutoIngestCaseButton.setPreferredSize(new java.awt.Dimension(64, 64)); - openAutoIngestCaseButton.addActionListener(new java.awt.event.ActionListener() { + openMultiUserCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N + openMultiUserCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openMultiUserCaseButton.text")); // NOI18N + openMultiUserCaseButton.setBorder(null); + openMultiUserCaseButton.setBorderPainted(false); + openMultiUserCaseButton.setContentAreaFilled(false); + openMultiUserCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); + openMultiUserCaseButton.setPreferredSize(new java.awt.Dimension(64, 64)); + openMultiUserCaseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - openAutoIngestCaseButtonActionPerformed(evt); + openMultiUserCaseButtonActionPerformed(evt); } }); - openAutoIngestCaseLabel.setFont(openAutoIngestCaseLabel.getFont().deriveFont(openAutoIngestCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); - openAutoIngestCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openAutoIngestCaseLabel.text")); // NOI18N + openMultiUserCaseLabel.setFont(openMultiUserCaseLabel.getFont().deriveFont(openMultiUserCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); + openMultiUserCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openMultiUserCaseLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -261,13 +220,13 @@ public class CueBannerPanel extends javax.swing.JPanel { .addComponent(createNewCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openRecentCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openExistingCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(openAutoIngestCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(openMultiUserCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(createNewCaseLabel) .addComponent(openRecentCaseLabel) .addComponent(openExistingCaseLabel) - .addComponent(openAutoIngestCaseLabel))) + .addComponent(openMultiUserCaseLabel))) .addComponent(closeButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); @@ -290,9 +249,9 @@ public class CueBannerPanel extends javax.swing.JPanel { .addComponent(openExistingCaseLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(openAutoIngestCaseButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(openMultiUserCaseButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(openAutoIngestCaseLabel) + .addComponent(openMultiUserCaseLabel) .addGap(20, 20, 20)))) .addComponent(jSeparator1) .addComponent(autopsyLogo, javax.swing.GroupLayout.PREFERRED_SIZE, 257, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -316,10 +275,11 @@ public class CueBannerPanel extends javax.swing.JPanel { recentCasesWindow.setVisible(true); }//GEN-LAST:event_openRecentCaseButtonActionPerformed - private void openAutoIngestCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openAutoIngestCaseButtonActionPerformed - autoIngestCasePanelWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - autoIngestCasePanelWindow.setVisible(true); - }//GEN-LAST:event_openAutoIngestCaseButtonActionPerformed + private void openMultiUserCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMultiUserCaseButtonActionPerformed + MultiUserCasesDialog multiUserCaseWindow = MultiUserCasesDialog.getInstance(); + multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + multiUserCaseWindow.setVisible(true); + }//GEN-LAST:event_openMultiUserCaseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel autopsyLogo; @@ -327,8 +287,8 @@ public class CueBannerPanel extends javax.swing.JPanel { private javax.swing.JButton createNewCaseButton; private javax.swing.JLabel createNewCaseLabel; private javax.swing.JSeparator jSeparator1; - private javax.swing.JButton openAutoIngestCaseButton; - private javax.swing.JLabel openAutoIngestCaseLabel; + private javax.swing.JButton openMultiUserCaseButton; + private javax.swing.JLabel openMultiUserCaseLabel; private javax.swing.JButton openExistingCaseButton; private javax.swing.JLabel openExistingCaseLabel; private javax.swing.JButton openRecentCaseButton; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java new file mode 100755 index 0000000000..bedc09d799 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java @@ -0,0 +1,442 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coordinationservice.CaseNodeData; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * Handles locating and opening multi-user cases. + */ +final class MultiUserCaseManager { + + private static final Logger LOGGER = Logger.getLogger(MultiUserCaseManager.class.getName()); + private static final String ALERT_FILE_NAME = "autoingest.alert"; + private static MultiUserCaseManager instance; + private CoordinationService coordinationService; + + /** + * Gets the multi-user case manager. + * + * @return The multi-user case manager singleton. + * + * @throws MultiUserCaseManagerException + */ + synchronized static MultiUserCaseManager getInstance() throws MultiUserCaseManager.MultiUserCaseManagerException { + if (null == instance) { + instance = new MultiUserCaseManager(); + } + return instance; + } + + /** + * Constructs an object that handles locating and opening multi-user cases. + * + * @throws MultiUserCaseManagerException + */ + private MultiUserCaseManager() throws MultiUserCaseManagerException { + try { + coordinationService = CoordinationService.getInstance(); + } catch (CoordinationServiceException ex) { + throw new MultiUserCaseManager.MultiUserCaseManagerException("Failed to get the coordination service.", ex); + } + } + + /** + * Gets a list of the cases in the top level case folder + * + * @return List of cases. + * + * @throws CoordinationServiceException + */ + List getCases() throws CoordinationServiceException { + List cases = new ArrayList<>(); + List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); + for (String node : nodeList) { + Path casePath = Paths.get(node); + File caseFolder = casePath.toFile(); + if (caseFolder.exists()) { + /* + * Search for '*.aut' and 'autoingest.alert' files. + */ + File[] fileArray = caseFolder.listFiles(); + if (fileArray == null) { + continue; + } + String autFilePath = null; + boolean alertFileFound = false; + for (File file : fileArray) { + String name = file.getName().toLowerCase(); + if (autFilePath == null && name.endsWith(".aut")) { + autFilePath = file.getAbsolutePath(); + if (!alertFileFound) { + continue; + } + } + if (!alertFileFound && name.endsWith(ALERT_FILE_NAME)) { + alertFileFound = true; + } + if (autFilePath != null && alertFileFound) { + break; + } + } + + if (autFilePath != null) { + try { + CaseStatus caseStatus; + if (alertFileFound) { + /* + * When an alert file exists, ignore the node data + * and use the ALERT status. + */ + caseStatus = CaseStatus.ALERT; + } else { + byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, node); + if (rawData != null && rawData.length > 0) { + /* + * When node data exists, use the status stored + * in the node data. + */ + CaseNodeData caseNodeData = new CaseNodeData(rawData); + if (caseNodeData.getErrorsOccurred()) { + caseStatus = CaseStatus.ALERT; + } else { + caseStatus = CaseStatus.OK; + } + } else { + /* + * When no node data is available, use the 'OK' + * status to avoid confusing the end-user. + */ + caseStatus = CaseStatus.OK; + } + } + + CaseMetadata caseMetadata = new CaseMetadata(Paths.get(autFilePath)); + cases.add(new MultiUserCase(casePath, caseMetadata, caseStatus)); + } catch (CaseMetadata.CaseMetadataException | MultiUserCase.MultiUserCaseException ex) { + LOGGER.log(Level.SEVERE, String.format("Error reading case metadata file '%s'.", autFilePath), ex); + } catch (InterruptedException | CaseNodeData.InvalidDataException ex) { + LOGGER.log(Level.SEVERE, String.format("Error reading case node data for '%s'.", node), ex); + } + } + } + } + return cases; + } + + /** + * Opens a multi-user case. + * + * @param caseMetadataFilePath Path to the case metadata file. + * + * @throws CaseActionException + */ + synchronized void openCase(Path caseMetadataFilePath) throws CaseActionException { + /* + * Open the case. + */ + Case.openAsCurrentCase(caseMetadataFilePath.toString()); + } + + /** + * Exception type thrown when there is an error completing a multi-user case + * manager operation. + */ + static final class MultiUserCaseManagerException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing a multi-user case manager operation. + * + * @param message The exception message. + */ + private MultiUserCaseManagerException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing a multi-user case manager operation. + * + * @param message The exception message. + * @param cause A Throwable cause for the error. + */ + private MultiUserCaseManagerException(String message, Throwable cause) { + super(message, cause); + } + + } + + /** + * A representation of a multi-user case. + */ + static class MultiUserCase implements Comparable { + + private final Path caseDirectoryPath; + private final String caseDisplayName; + private final String metadataFileName; + private final Date createDate; + private final Date lastAccessedDate; + private CaseStatus status; + + /** + * Constructs a representation of a multi-user case + * + * @param caseDirectoryPath The case directory path. + * @param caseMetadata The case metadata. + * + * @throws MultiUserCaseException If no case metadata (.aut) file is + * found in the case directory. + */ + MultiUserCase(Path caseDirectoryPath, CaseMetadata caseMetadata, CaseStatus status) throws MultiUserCaseException { + this.caseDirectoryPath = caseDirectoryPath; + caseDisplayName = caseMetadata.getCaseDisplayName(); + metadataFileName = caseMetadata.getFilePath().getFileName().toString(); + this.status = status; + BasicFileAttributes fileAttrs = null; + try { + fileAttrs = Files.readAttributes(Paths.get(caseDirectoryPath.toString(), metadataFileName), BasicFileAttributes.class); + } catch (IOException ex) { + LOGGER.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, will use current time for case createDate/lastModfiedDate", caseDirectoryPath), ex); + } + if (null != fileAttrs) { + createDate = new Date(fileAttrs.creationTime().toMillis()); + lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); + } else { + createDate = new Date(); + lastAccessedDate = new Date(); + } + } + + /** + * Gets the case directory path. + * + * @return The case directory path. + */ + Path getCaseDirectoryPath() { + return this.caseDirectoryPath; + } + + /** + * Gets the case display name. This may differ from the name supplied to + * the directory or metadata file names if a case has been renamed. + * + * @return The case display name. + */ + String getCaseDisplayName() { + return this.caseDisplayName; + } + + /** + * Gets the creation date for the case, defined as the create time of + * the case metadata file. + * + * @return The case creation date. + */ + Date getCreationDate() { + return this.createDate; + } + + /** + * Gets the last accessed date for the case, defined as the last + * accessed time of the case metadata file. + * + * @return The last accessed date. + */ + Date getLastAccessedDate() { + return this.lastAccessedDate; + } + + /** + * Gets metadata (.aut) file name. + * + * @return The metadata file name. + */ + String getMetadataFileName() { + return this.metadataFileName; + } + + /** + * Gets the status of this case. + * + * @return See CaseStatus enum definition. + */ + CaseStatus getStatus() { + return status; + } + + /** + * Gets the case metadata from a case directory path. + * + * @param caseDirectoryPath The case directory path. + * + * @return Case metadata. + * + * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object + * cannot be constructed. + * @throws MultiUserCaseException If no case metadata (.aut) + * file is found in the case + * directory. + */ + private CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { + CaseMetadata caseMetadata = null; + + File directory = new File(caseDirectoryPath.toString()); + if (directory.isDirectory()) { + File autFile = null; + + /* + * Attempt to find an AUT file via a directory scan. + */ + for (File file : directory.listFiles()) { + if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { + autFile = file; + break; + } + } + + if (autFile == null || !autFile.isFile()) { + throw new MultiUserCaseException(String.format("No case metadata (.aut) file found in the case directory '%s'.", caseDirectoryPath.toString())); + } + + caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); + } + + return caseMetadata; + } + + /** + * Indicates whether or not some other object is "equal to" this + * MultiUserCase object. + * + * @param other The other object. + * + * @return True or false. + */ + @Override + public boolean equals(Object other) { + if (!(other instanceof MultiUserCase)) { + return false; + } + if (other == this) { + return true; + } + return this.caseDirectoryPath.toString().equals(((MultiUserCase) other).caseDirectoryPath.toString()); + } + + /** + * Returns a hash code value for this MultiUserCase object. + * + * @return The has code. + */ + @Override + public int hashCode() { + int hash = 7; + hash = 71 * hash + Objects.hashCode(this.caseDirectoryPath); + hash = 71 * hash + Objects.hashCode(this.createDate); + hash = 71 * hash + Objects.hashCode(this.caseDisplayName); + return hash; + } + + /** + * Compares this MultiUserCase object with another MultiUserCase object + * for order. + */ + @Override + public int compareTo(MultiUserCase other) { + return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); + } + + /** + * Comparator for a descending order sort on date created. + */ + static class LastAccessedDateDescendingComparator implements Comparator { + + /** + * Compares two MultiUserCase objects for order based on last + * accessed date (descending). + * + * @param object The first MultiUserCase object + * @param otherObject The second MultiUserCase object. + * + * @return A negative integer, zero, or a positive integer as the + * first argument is less than, equal to, or greater than + * the second. + */ + @Override + public int compare(MultiUserCase object, MultiUserCase otherObject) { + return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); + } + } + + /** + * Exception thrown when there is a problem creating a multi-user case. + */ + final class MultiUserCaseException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an exception to throw when there is a problem creating + * a multi-user case. + * + * @param message The exception message. + */ + private MultiUserCaseException(String message) { + super(message); + } + + /** + * Constructs an exception to throw when there is a problem creating + * a multi-user case. + * + * @param message The exception message. + * @param cause The cause of the exception, if it was an + * exception. + */ + private MultiUserCaseException(String message, Throwable cause) { + super(message, cause); + } + } + + } + + static enum CaseStatus { + OK, + ALERT + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java new file mode 100755 index 0000000000..8c90aeccb4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesDialog.java @@ -0,0 +1,89 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.casemodule; + +import java.awt.Dialog; +import java.awt.event.KeyEvent; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.KeyStroke; +import org.openide.windows.WindowManager; + +/** + * This class extends a JDialog and maintains the MultiUserCasesPanel. + */ +final class MultiUserCasesDialog extends JDialog { + + private static final long serialVersionUID = 1L; + private static final String REVIEW_MODE_TITLE = "Open Multi-User Case"; + private static MultiUserCasesPanel multiUserCasesPanel; + private static MultiUserCasesDialog instance; + + /** + * Gets the instance of the MultiuserCasesDialog. + * + * @return The instance. + */ + static public MultiUserCasesDialog getInstance() { + if(instance == null) { + instance = new MultiUserCasesDialog(); + instance.init(); + } + return instance; + } + + /** + * Constructs a MultiUserCasesDialog object. + */ + private MultiUserCasesDialog() { + super(WindowManager.getDefault().getMainWindow(), + REVIEW_MODE_TITLE, + Dialog.ModalityType.APPLICATION_MODAL); + } + + /** + * Initializes the multi-user cases panel. + */ + private void init() { + getRootPane().registerKeyboardAction( + e -> { + setVisible(false); + }, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + + multiUserCasesPanel = new MultiUserCasesPanel(this); + add(multiUserCasesPanel); + pack(); + setResizable(false); + } + + /** + * Set the dialog visibility. When setting it to visible, the contents will + * refresh. + * + * @param value True or false. + */ + @Override + public void setVisible(boolean value) { + if(value) { + multiUserCasesPanel.refresh(); + } + super.setVisible(value); + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form similarity index 83% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form index cb0f275809..18d99fa0dc 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form @@ -45,7 +45,7 @@ - + @@ -82,7 +82,7 @@ - + @@ -99,11 +99,9 @@ - - @@ -118,7 +116,7 @@ - + @@ -153,7 +151,7 @@ - + @@ -165,10 +163,10 @@ - + - + @@ -182,7 +180,7 @@ - + @@ -196,7 +194,7 @@ - + @@ -209,7 +207,7 @@ - + @@ -222,7 +220,7 @@ - + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java similarity index 64% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java rename to Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index 2bcd335916..d0676e1966 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCasePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -16,52 +16,42 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.casemodule; import java.awt.Cursor; import java.awt.Desktop; -import java.awt.EventQueue; -import java.awt.event.ActionEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import javax.swing.JDialog; import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.SwingWorker; +import javax.swing.RowSorter; +import javax.swing.SortOrder; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; -import org.openide.util.NbBundle; -import org.openide.util.lookup.ServiceProvider; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.CaseActionCancelledException; -import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; +import javax.swing.table.TableRowSorter; +import org.sleuthkit.autopsy.casemodule.MultiUserCaseManager.MultiUserCase; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.guiutils.LongDateCellRenderer; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.casemodule.AutoIngestCasePanelInterface; -import org.sleuthkit.autopsy.casemodule.CueBannerPanel; -import org.sleuthkit.autopsy.coreutils.NetworkUtils; -import org.sleuthkit.autopsy.experimental.configuration.StartupWindow; +import org.sleuthkit.autopsy.guiutils.GrayableCellRenderer; +import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; /** * A panel that allows a user to open cases created by auto ingest. */ -@ServiceProvider(service = AutoIngestCasePanelInterface.class) -public final class AutoIngestCasePanel extends JPanel implements AutoIngestCasePanelInterface { +final class MultiUserCasesPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(AutoIngestCasePanel.class.getName()); - private static final AutoIngestCase.LastAccessedDateDescendingComparator reverseDateModifiedComparator = new AutoIngestCase.LastAccessedDateDescendingComparator(); + private static final Logger LOGGER = Logger.getLogger(MultiUserCasesPanel.class.getName()); + private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; + private static final MultiUserCaseManager.MultiUserCase.LastAccessedDateDescendingComparator REVERSE_DATE_MODIFIED_COMPARATOR = new MultiUserCaseManager.MultiUserCase.LastAccessedDateDescendingComparator(); private static final int CASE_COL_MIN_WIDTH = 30; private static final int CASE_COL_MAX_WIDTH = 2000; private static final int CASE_COL_PREFERRED_WIDTH = 300; @@ -71,9 +61,6 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP private static final int STATUS_COL_MIN_WIDTH = 55; private static final int STATUS_COL_MAX_WIDTH = 250; private static final int STATUS_COL_PREFERRED_WIDTH = 60; - private static final int MILLIS_TO_WAIT_BEFORE_STARTING = 500; - private static final int MILLIS_TO_WAIT_BETWEEN_UPDATES = 300000; - private ScheduledThreadPoolExecutor casesTableRefreshExecutor; /* * The JTable table model for the cases table presented by this view is @@ -82,11 +69,12 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * TODO (RC): Consider unifying this stuff in an enum as in * AutoIngestDashboard to make it less error prone. */ - private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.CaseHeaderText"); - private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); - private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); - private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); - private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); + private static final String CASE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CaseHeaderText"); + private static final String CREATEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); + private static final String COMPLETEDTIME_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.LastAccessedTimeHeaderText"); + private static final String STATUS_ICON_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); + private static final String OUTPUT_FOLDER_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); + private static final String METADATA_FILE_HEADER = org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.MetadataFileHeaderText"); enum COLUMN_HEADERS { @@ -94,51 +82,20 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP CREATEDTIME, COMPLETEDTIME, STATUS_ICON, - OUTPUTFOLDER + OUTPUTFOLDER, + METADATA_FILE } - private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER}; + private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER, METADATA_FILE_HEADER}; private DefaultTableModel caseTableModel; private Path currentlySelectedCase = null; - - public AutoIngestCasePanel() { - init(null); - } - - @Override - public void addWindowStateListener(JDialog parent) { - /* - * Add a window state listener that starts and stops refreshing of the - * cases table. - */ - parent.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - stopCasesTableRefreshes(); - } - - @Override - public void windowActivated(WindowEvent e) { - startCasesTableRefreshes(); - } - - @Override - public void windowClosed(WindowEvent e) { - stopCasesTableRefreshes(); - } - }); - } + private JDialog parentDialog; /** * Constructs a panel that allows a user to open cases created by automated * ingest. - * - * @param parent The parent dialog for this panel. */ - public AutoIngestCasePanel(JDialog parent) { - init(parent); - } - - public void init(JDialog parent) { + MultiUserCasesPanel(JDialog parentDialog) { + this.parentDialog = parentDialog; caseTableModel = new DefaultTableModel(columnNames, 0) { private static final long serialVersionUID = 1L; @@ -146,6 +103,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP public boolean isCellEditable(int row, int column) { return false; } + @Override public Class getColumnClass(int col) { if (this.getColumnName(col).equals(CREATEDTIME_HEADER) || this.getColumnName(col).equals(COMPLETEDTIME_HEADER)) { @@ -184,13 +142,15 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP theColumn.setWidth(TIME_COL_PREFERRED_WIDTH); theColumn = casesTable.getColumn(STATUS_ICON_HEADER); - theColumn.setCellRenderer(new CaseStatusIconCellRenderer()); + theColumn.setCellRenderer(new StatusIconCellRenderer()); theColumn.setMinWidth(STATUS_COL_MIN_WIDTH); theColumn.setMaxWidth(STATUS_COL_MAX_WIDTH); theColumn.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); theColumn.setWidth(STATUS_COL_PREFERRED_WIDTH); casesTable.removeColumn(casesTable.getColumn(OUTPUT_FOLDER_HEADER)); + casesTable.removeColumn(casesTable.getColumn(METADATA_FILE_HEADER)); + casesTable.setRowSorter(new RowSorter<>(caseTableModel)); /* * Listen for row selection changes and set button state for the current @@ -203,75 +163,39 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP } setButtons(); }); - - /* - * Add a window state listener that starts and stops refreshing of the - * cases table. - */ - if (parent != null) { - parent.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - stopCasesTableRefreshes(); - } - - @Override - public void windowActivated(WindowEvent e) { - startCasesTableRefreshes(); - } - - @Override - public void windowClosed(WindowEvent e) { - stopCasesTableRefreshes(); - } - }); - } - } - - /** - * Start doing periodic refreshes of the cases table. - */ - private void startCasesTableRefreshes() { - if (null == casesTableRefreshExecutor) { - casesTableRefreshExecutor = new ScheduledThreadPoolExecutor(1); - this.casesTableRefreshExecutor.scheduleAtFixedRate(() -> { - refreshCasesTable(); - }, MILLIS_TO_WAIT_BEFORE_STARTING, MILLIS_TO_WAIT_BETWEEN_UPDATES, TimeUnit.MILLISECONDS); - } - } - - /** - * Stop doing periodic refreshes of the cases table. - */ - private void stopCasesTableRefreshes() { - if (null != casesTableRefreshExecutor) { - casesTableRefreshExecutor.shutdown(); - } - this.casesTableRefreshExecutor = null; - } - - /* - * Updates the view presented by the panel. - */ - public void updateView() { - Thread thread = new Thread(() -> { - refreshCasesTable(); - }); - thread.start(); } /** * Gets the list of cases known to the review mode cases manager and * refreshes the cases table. */ - private void refreshCasesTable() { + void refresh() { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { currentlySelectedCase = getSelectedCase(); - AutoIngestCaseManager manager = AutoIngestCaseManager.getInstance(); - List theModel = manager.getCases(); - EventQueue.invokeLater(new CaseTableRefreshTask(theModel)); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Unexpected exception in refreshCasesTable", ex); //NON-NLS + MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); + List cases = manager.getCases(); + cases.sort(REVERSE_DATE_MODIFIED_COMPARATOR); + caseTableModel.setRowCount(0); + long now = new Date().getTime(); + for (MultiUserCase autoIngestCase : cases) { + if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { + caseTableModel.addRow(new Object[]{ + autoIngestCase.getCaseDisplayName(), + autoIngestCase.getCreationDate(), + autoIngestCase.getLastAccessedDate(), + (MultiUserCaseManager.CaseStatus.OK != autoIngestCase.getStatus()) ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, + autoIngestCase.getCaseDirectoryPath().toString(), + autoIngestCase.getMetadataFileName()}); + } + } + setSelectedCase(currentlySelectedCase); + setButtons(); + } catch (MultiUserCaseManager.MultiUserCaseManagerException | CoordinationService.CoordinationServiceException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS + } finally { + setCursor(null); } } @@ -320,103 +244,108 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * in the cases table. */ private void setButtons() { - boolean enabled = casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); - bnOpen.setEnabled(enabled); - bnShowLog.setEnabled(enabled); + boolean openEnabled = casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); + bnOpen.setEnabled(openEnabled); + + Path pathToLog = getSelectedCaseLogFilePath(); + boolean showLogEnabled = openEnabled && pathToLog != null && pathToLog.toFile().exists(); + bnShowLog.setEnabled(showLogEnabled); } /** - * Opens a case. + * Retrieves the log file path for the selected case in the cases table. + * + * @return The case log path. + */ + private Path getSelectedCaseLogFilePath() { + Path retValue = null; + + int selectedRow = casesTable.getSelectedRow(); + int rowCount = casesTable.getRowCount(); + if (selectedRow >= 0 && selectedRow < rowCount) { + String caseDirectory = (String) caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + retValue = Paths.get(caseDirectory, LOG_FILE_NAME); + } + + return retValue; + } + + /** + * Open a case. * * @param caseMetadataFilePath The path to the case metadata file. */ private void openCase(Path caseMetadataFilePath) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - new SwingWorker() { - - @Override - protected Void doInBackground() throws Exception { - AutoIngestCaseManager.getInstance().openCase(caseMetadataFilePath); - stopCasesTableRefreshes(); - StartupWindowProvider.getInstance().close(); - CueBannerPanel.closeAutoIngestCasesWindow(); - return null; + try { + StartupWindowProvider.getInstance().close(); + if (parentDialog != null) { + parentDialog.setVisible(false); } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { - logger.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS - MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); - } - StartupWindowProvider.getInstance().open(); - } finally { - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } + MultiUserCaseManager.getInstance().openCase(caseMetadataFilePath); + } catch (CaseActionException | MultiUserCaseManager.MultiUserCaseManagerException ex) { + if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { + LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS + MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); } - }.execute(); + StartupWindowProvider.getInstance().open(); + } finally { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } } /** - * A task that refreshes the cases table using a list of auto ingest cases. + * Indicates whether or not a time satisfies a time filter defined by this + * panel's time filter radio buttons. + * + * @param currentTime The current date and time in milliseconds from the + * Unix epoch. + * @param inputTime The date and time to be tested as milliseconds from + * the Unix epoch. */ - private class CaseTableRefreshTask implements Runnable { + private boolean passesTimeFilter(long currentTime, long inputTime) { + long numberOfUnits = 10; + long multiplier = 1; + if (rbAllCases.isSelected()) { + return true; + } else if (rbMonths.isSelected()) { + multiplier = 31; + } else if (rbWeeks.isSelected()) { + multiplier = 7; + } else if (rbDays.isSelected()) { + multiplier = 1; + } + return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); + } - private final List cases; + /** + * RowSorter which makes columns whose type is Date to be sorted first in + * Descending order then in Ascending order + */ + private static class RowSorter extends TableRowSorter { - CaseTableRefreshTask(List cases) { - setButtons(); - this.cases = cases; + RowSorter(M tModel) { + super(tModel); } - /** - * @inheritDoc - */ @Override - public void run() { - cases.sort(reverseDateModifiedComparator); - caseTableModel.setRowCount(0); - long now = new Date().getTime(); - for (AutoIngestCase autoIngestCase : cases) { - if (passesTimeFilter(now, autoIngestCase.getLastAccessedDate().getTime())) { - caseTableModel.addRow(new Object[]{ - autoIngestCase.getCaseName(), - autoIngestCase.getCreationDate(), - autoIngestCase.getLastAccessedDate(), - (AutoIngestCase.CaseStatus.OK != autoIngestCase.getStatus()), - autoIngestCase.getCaseDirectoryPath().toString()}); + public void toggleSortOrder(int column) { + if (!this.getModel().getColumnClass(column).equals(Date.class)) { + super.toggleSortOrder(column); //if it isn't a date column perform the regular sorting + } else { + ArrayList sortKeys = new ArrayList<>(getSortKeys()); + if (sortKeys.isEmpty() || sortKeys.get(0).getColumn() != column) { //sort descending + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.DESCENDING)); + } else if (sortKeys.get(0).getSortOrder() == SortOrder.ASCENDING) { + sortKeys.removeIf(key -> key.getColumn() == column); + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.DESCENDING)); + } else { + sortKeys.removeIf(key -> key.getColumn() == column); + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.ASCENDING)); } + setSortKeys(sortKeys); } - setSelectedCase(currentlySelectedCase); } - - /** - * Indicates whether or not a time satisfies a time filter defined by - * this panel's time filter radio buttons. - * - * @param currentTime The current date and time in milliseconds from the - * Unix epoch. - * @param inputTime The date and time to be tested as milliseconds - * from the Unix epoch. - */ - private boolean passesTimeFilter(long currentTime, long inputTime) { - long numberOfUnits = 10; - long multiplier = 1; - if (rbAllCases.isSelected()) { - return true; - } else if (rbMonths.isSelected()) { - multiplier = 31; - } else if (rbWeeks.isSelected()) { - multiplier = 7; - } else if (rbDays.isSelected()) { - multiplier = 1; - } - return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); - } - } /** @@ -443,7 +372,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP setName("Completed Cases"); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnOpen.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnOpen.text")); // NOI18N bnOpen.setEnabled(false); bnOpen.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -451,9 +380,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP } }); - casesTable.setAutoCreateRowSorter(true); casesTable.setModel(caseTableModel); - casesTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); casesTable.setRowHeight(20); casesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); casesTable.addMouseListener(new java.awt.event.MouseAdapter() { @@ -463,7 +390,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); scrollPaneTable.setViewportView(casesTable); - org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnRefresh.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnRefresh.text")); // NOI18N bnRefresh.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnRefreshActionPerformed(evt); @@ -472,7 +399,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP rbGroupHistoryLength.add(rbAllCases); rbAllCases.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbAllCases.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbAllCases.text")); // NOI18N rbAllCases.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbAllCasesItemStateChanged(evt); @@ -494,8 +421,8 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP .addComponent(rbAllCases)) ); - org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnShowLog.text")); // NOI18N - bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.bnShowLog.toolTipText")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.text")); // NOI18N + bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.toolTipText")); // NOI18N bnShowLog.setEnabled(false); bnShowLog.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -504,7 +431,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbDays); - org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbDays.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbDays.text")); // NOI18N rbDays.setName(""); // NOI18N rbDays.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { @@ -513,7 +440,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbWeeks); - org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbWeeks.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbWeeks.text")); // NOI18N rbWeeks.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbWeeksItemStateChanged(evt); @@ -521,7 +448,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupHistoryLength.add(rbMonths); - org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbMonths.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbMonths.text")); // NOI18N rbMonths.addItemListener(new java.awt.event.ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent evt) { rbMonthsItemStateChanged(evt); @@ -529,7 +456,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP }); rbGroupLabel.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "AutoIngestCasePanel.rbGroupLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbGroupLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -556,7 +483,7 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(bnRefresh) .addGap(4, 4, 4)) - .addComponent(scrollPaneTable, javax.swing.GroupLayout.DEFAULT_SIZE, 1007, Short.MAX_VALUE)) + .addComponent(scrollPaneTable)) .addContainerGap()) ); layout.setVerticalGroup( @@ -588,10 +515,12 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP */ private void bnOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenActionPerformed int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, - COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), - caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); - openCase(caseMetadataFilePath); + String caseDirectory = (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + Path caseMetadataFilePath = Paths.get(caseDirectory, (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.METADATA_FILE.ordinal())); + + new Thread(() -> { + openCase(caseMetadataFilePath); + }).start(); }//GEN-LAST:event_bnOpenActionPerformed /** @@ -599,53 +528,50 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP * * @param evt -- The event that caused this to be called */ - private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bnRefreshActionPerformed - {//GEN-HEADEREND:event_bnRefreshActionPerformed - updateView(); - }//GEN-LAST:event_bnRefreshActionPerformed + private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) { + refresh(); + } - private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbDaysItemStateChanged + private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) { if (rbDays.isSelected()) { - updateView(); + refresh(); } - }//GEN-LAST:event_rbDaysItemStateChanged + } private void rbAllCasesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbAllCasesItemStateChanged if (rbAllCases.isSelected()) { - updateView(); + refresh(); } }//GEN-LAST:event_rbAllCasesItemStateChanged private void rbMonthsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbMonthsItemStateChanged if (rbMonths.isSelected()) { - updateView(); + refresh(); } }//GEN-LAST:event_rbMonthsItemStateChanged private void rbWeeksItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbWeeksItemStateChanged if (rbWeeks.isSelected()) { - updateView(); + refresh(); } }//GEN-LAST:event_rbWeeksItemStateChanged private void bnShowLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowLogActionPerformed - int selectedRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - int rowCount = casesTable.getRowCount(); - if (selectedRow >= 0 && selectedRow < rowCount) { - String thePath = (String) caseTableModel.getValueAt(selectedRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); - Path pathToLog = AutoIngestJobLogger.getLogPath(Paths.get(thePath)); + Path pathToLog = getSelectedCaseLogFilePath(); + if (pathToLog != null) { try { if (pathToLog.toFile().exists()) { Desktop.getDesktop().edit(pathToLog.toFile()); + } else { - JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.cannotFindLog"), - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotFindLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); } } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); + LOGGER.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); JOptionPane.showMessageDialog(this, - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.cannotOpenLog"), - org.openide.util.NbBundle.getMessage(AutoIngestCasePanel.class, "DisplayLogDialog.unableToShowLogFile"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotOpenLog"), + org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.PLAIN_MESSAGE); } } @@ -654,9 +580,8 @@ public final class AutoIngestCasePanel extends JPanel implements AutoIngestCaseP private void casesTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_casesTableMouseClicked if (evt.getClickCount() == 2) { int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow, - COLUMN_HEADERS.OUTPUTFOLDER.ordinal()), - caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension()); + String caseDirectory = (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); + Path caseMetadataFilePath = Paths.get(caseDirectory, (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.METADATA_FILE.ordinal())); openCase(caseMetadataFilePath); } }//GEN-LAST:event_casesTableMouseClicked diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index fad0196288..7c7d22066e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -34,7 +34,6 @@ import java.time.LocalDate; import java.util.HashMap; import java.util.Map; import java.util.Set; -import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; @@ -1251,13 +1250,13 @@ public abstract class AbstractSqlEamDb implements EamDb { } /** - * Remove a reference set and all hashes contained in it. + * Remove a reference set and all entries contained in it. * @param referenceSetID * @throws EamDbException */ @Override public void deleteReferenceSet(int referenceSetID) throws EamDbException{ - deleteReferenceSetFiles(referenceSetID); + deleteReferenceSetEntries(referenceSetID); deleteReferenceSetEntry(referenceSetID); } @@ -1277,7 +1276,7 @@ public abstract class AbstractSqlEamDb implements EamDb { preparedStatement.setInt(1, referenceSetID); preparedStatement.executeUpdate(); } catch (SQLException ex) { - throw new EamDbException("Error deleting reference set", ex); // NON-NLS + throw new EamDbException("Error deleting reference set " + referenceSetID, ex); // NON-NLS } finally { EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeConnection(conn); @@ -1285,16 +1284,18 @@ public abstract class AbstractSqlEamDb implements EamDb { } /** - * Remove all entries for this reference set from the reference_file table + * Remove all entries for this reference set from the reference tables + * (Currently only removes entries from the reference_file table) * @param referenceSetID * @throws EamDbException */ - private void deleteReferenceSetFiles(int referenceSetID) throws EamDbException{ + private void deleteReferenceSetEntries(int referenceSetID) throws EamDbException{ Connection conn = connect(); PreparedStatement preparedStatement = null; String sql = "DELETE FROM %s WHERE reference_set_id=?"; + // When other reference types are added, this will need to loop over all the tables String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); try { @@ -1302,7 +1303,7 @@ public abstract class AbstractSqlEamDb implements EamDb { preparedStatement.setInt(1, referenceSetID); preparedStatement.executeUpdate(); } catch (SQLException ex) { - throw new EamDbException("Error deleting files from reference set", ex); // NON-NLS + throw new EamDbException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS } finally { EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeConnection(conn); @@ -1310,31 +1311,46 @@ public abstract class AbstractSqlEamDb implements EamDb { } /** - * Check whether the given reference set exists in the central repository. + * Check whether a reference set with the given parameters exists in the central repository. + * Used to check whether reference sets saved in the settings are still present. * @param referenceSetID - * @param hashSetName + * @param setName * @param version * @return true if a matching entry exists in the central repository * @throws EamDbException */ @Override - public boolean referenceSetIsValid(int referenceSetID, String hashSetName, String version) throws EamDbException{ + public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws EamDbException{ EamGlobalSet refSet = this.getReferenceSetByID(referenceSetID); if(refSet == null){ return false; } - return(refSet.getSetName().equals(hashSetName) && refSet.getVersion().equals(version)); + return(refSet.getSetName().equals(setName) && refSet.getVersion().equals(version)); } - + /** - * Check if the given hash is in a specific reference set + * Check if the given file hash is in this reference set. + * Only searches the reference_files table. * @param hash * @param referenceSetID * @return true if the hash is found in the reference set + * @throws EamDbException */ @Override - public boolean isHashInReferenceSet(String hash, int referenceSetID) throws EamDbException{ + public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException{ + return isValueInReferenceSet(hash, referenceSetID, CorrelationAttribute.FILES_TYPE_ID); + } + + /** + * Check if the given value is in a specific reference set + * @param value + * @param referenceSetID + * @param correlationTypeID + * @return true if the value is found in the reference set + */ + @Override + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException{ Connection conn = connect(); @@ -1343,17 +1359,17 @@ public abstract class AbstractSqlEamDb implements EamDb { ResultSet resultSet = null; String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?"; - String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); + String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID)); try { preparedStatement = conn.prepareStatement(String.format(sql, fileTableName)); - preparedStatement.setString(1, hash); + preparedStatement.setString(1, value); preparedStatement.setInt(2, referenceSetID); resultSet = preparedStatement.executeQuery(); resultSet.next(); matchingInstances = resultSet.getLong(1); } catch (SQLException ex) { - throw new EamDbException("Error determining if file is in reference set.", ex); // NON-NLS + throw new EamDbException("Error determining if value (" + value + ") is in reference set " + referenceSetID, ex); // NON-NLS } finally { EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeResultSet(resultSet); @@ -1372,7 +1388,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * @return Global known status of the artifact */ @Override - public boolean isArtifactlKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { + public boolean isArtifactKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { // TEMP: Only support file correlation type if (aType.getId() != CorrelationAttribute.FILES_TYPE_ID) { @@ -1521,30 +1537,6 @@ public abstract class AbstractSqlEamDb implements EamDb { EamGlobalSet globalSet = getReferenceSetByID(referenceSetID); return (getOrganizationByID(globalSet.getOrgID())); } - - /** - * Add a new reference set - * - * @param orgID - * @param setName - * @param version - * @param importDate - * @return the reference set ID of the newly created set - * @throws EamDbException - */ - @Override - public int newReferenceSet(int orgID, String setName, String version, TskData.FileKnown knownStatus, - boolean isReadOnly) throws EamDbException { - EamDb dbManager = EamDb.getInstance(); - EamGlobalSet eamGlobalSet = new EamGlobalSet( - orgID, - setName, - version, - knownStatus, - isReadOnly, - LocalDate.now()); - return dbManager.newReferencelSet(eamGlobalSet); - } /** * Update an existing organization. @@ -1618,7 +1610,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * @throws EamDbException */ @Override - public int newReferencelSet(EamGlobalSet eamGlobalSet) throws EamDbException { + public int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException { Connection conn = connect(); PreparedStatement preparedStatement1 = null; @@ -1757,14 +1749,15 @@ public abstract class AbstractSqlEamDb implements EamDb { } /** - * Check whether a reference set with the given name/version is in the central repo - * @param hashSetName + * Check whether a reference set with the given name/version is in the central repo. + * Used to check for name collisions when creating reference sets. + * @param referenceSetName * @param version * @return true if a matching set is found * @throws EamDbException */ @Override - public boolean referenceSetExists(String hashSetName, String version) throws EamDbException{ + public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException{ Connection conn = connect(); PreparedStatement preparedStatement1 = null; @@ -1773,13 +1766,14 @@ public abstract class AbstractSqlEamDb implements EamDb { try { preparedStatement1 = conn.prepareStatement(sql1); - preparedStatement1.setString(1, hashSetName); + preparedStatement1.setString(1, referenceSetName); preparedStatement1.setString(2, version); resultSet = preparedStatement1.executeQuery(); return (resultSet.next()); } catch (SQLException ex) { - throw new EamDbException("Error getting reference instances by type and value.", ex); // NON-NLS + throw new EamDbException("Error testing whether reference set exists (name: " + referenceSetName + + " version: " + version, ex); // NON-NLS } finally { EamDbUtil.closePreparedStatement(preparedStatement1); EamDbUtil.closeResultSet(resultSet); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java index dc0a87ea07..1011f837cc 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java @@ -362,38 +362,51 @@ public interface EamDb { List getListCasesHavingArtifactInstancesKnownBad(CorrelationAttribute.Type aType, String value) throws EamDbException; /** - * Remove a reference set and all hashes contained in it. + * Remove a reference set and all values contained in it. * @param referenceSetID * @throws EamDbException */ public void deleteReferenceSet(int referenceSetID) throws EamDbException; /** - * Check whether the given reference set exists in the central repository. + * Check whether a reference set with the given parameters exists in the central repository. + * Used to check whether reference sets saved in the settings are still present. * @param referenceSetID - * @param hashSetName + * @param referenceSetName * @param version * @return true if a matching entry exists in the central repository * @throws EamDbException */ - public boolean referenceSetIsValid(int referenceSetID, String hashSetName, String version) throws EamDbException; + public boolean referenceSetIsValid(int referenceSetID, String referenceSetName, String version) throws EamDbException; /** - * Check whether a reference set with the given name/version is in the central repo - * @param hashSetName + * Check whether a reference set with the given name/version is in the central repo. + * Used to check for name collisions when creating reference sets. + * @param referenceSetName * @param version * @return true if a matching set is found * @throws EamDbException */ - public boolean referenceSetExists(String hashSetName, String version) throws EamDbException; + public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException; /** - * Check if the given hash is in a specific reference set + * Check if the given file hash is in this reference set. + * Only searches the reference_files table. * @param hash * @param referenceSetID * @return true if the hash is found in the reference set + * @throws EamDbException */ - public boolean isHashInReferenceSet(String hash, int referenceSetID) throws EamDbException; + public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException; + + /** + * Check if the given value is in a specific reference set + * @param value + * @param referenceSetID + * @param correlationTypeID + * @return true if the hash is found in the reference set + */ + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException; /** * Is the artifact known as bad according to the reference entries? @@ -403,7 +416,7 @@ public interface EamDb { * * @return Global known status of the artifact */ - boolean isArtifactlKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException; + boolean isArtifactKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException; /** * Add a new organization @@ -472,20 +485,7 @@ public interface EamDb { * * @throws EamDbException */ - int newReferencelSet(EamGlobalSet eamGlobalSet) throws EamDbException; - - /** - * Add a new reference set - * - * @param orgID - * @param setName - * @param version - * @param importDate - * @return the reference set ID of the newly created set - * @throws EamDbException - */ - int newReferenceSet(int orgID, String setName, String version, TskData.FileKnown knownStatus, - boolean isReadOnly) throws EamDbException; + int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException; /** * Get a global set by ID diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java index e4292dc6ca..23a4c257ae 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.centralrepository.datamodel; import java.time.LocalDate; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.datamodel.TskData; /** @@ -61,6 +60,26 @@ public class EamGlobalSet { LocalDate importDate) { this(-1, orgID, setName, version, knownStatus, isReadOnly, importDate); } + + /** + * Create a new EamGlobalSet object. + * This is intended to be used when creating a new global set as the + * globalSetID will be unknown to start. + * importDate will be automatically set to the current time. + * @param orgID + * @param setName + * @param version + * @param knownStatus + * @param isReadOnly + */ + public EamGlobalSet( + int orgID, + String setName, + String version, + TskData.FileKnown knownStatus, + boolean isReadOnly) { + this(-1, orgID, setName, version, knownStatus, isReadOnly, LocalDate.now()); + } /** * @return the globalSetID @@ -145,17 +164,6 @@ public class EamGlobalSet { public void setFileKnownStatus(TskData.FileKnown fileKnownStatus) { this.fileKnownStatus = fileKnownStatus; } - - /** - * Return the FileKnown status as a KnownFilesType - * @return KNOWN or KNOWN_BAD - */ - public HashDbManager.HashDb.KnownFilesType getKnownStatus(){ - if(fileKnownStatus.equals(TskData.FileKnown.BAD)){ - return HashDbManager.HashDb.KnownFilesType.KNOWN_BAD; - } - return HashDbManager.HashDb.KnownFilesType.KNOWN; - } /** * @return the importDate diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java index 45a0388561..719a58385b 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java @@ -636,7 +636,7 @@ public class SqliteEamDb extends AbstractSqlEamDb { } /** - * Remove a reference set and all hashes contained in it. + * Remove a reference set and all values contained in it. * @param referenceSetID * @throws EamDbException */ @@ -657,27 +657,28 @@ public class SqliteEamDb extends AbstractSqlEamDb { * @return true if the hash is found in the reference set */ @Override - public boolean isHashInReferenceSet(String hash, int referenceSetID) throws EamDbException{ + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException { try{ acquireSharedLock(); - return super.isHashInReferenceSet(hash, referenceSetID); + return super.isValueInReferenceSet(value, referenceSetID, correlationTypeID); } finally { releaseSharedLock(); } } /** - * Check whether a reference set with the given name/version is in the central repo - * @param hashSetName + * Check whether a reference set with the given name/version is in the central repo. + * Used to check for name collisions when creating reference sets. + * @param referenceSetName * @param version * @return true if a matching set is found * @throws EamDbException */ @Override - public boolean referenceSetExists(String hashSetName, String version) throws EamDbException { + public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException { try{ acquireSharedLock(); - return super.referenceSetExists(hashSetName, version); + return super.referenceSetExists(referenceSetName, version); } finally { releaseSharedLock(); } @@ -692,10 +693,10 @@ public class SqliteEamDb extends AbstractSqlEamDb { * @return Global known status of the artifact */ @Override - public boolean isArtifactlKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { + public boolean isArtifactKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException { try{ acquireSharedLock(); - return super.isArtifactlKnownBadByReference(aType, value); + return super.isArtifactKnownBadByReference(aType, value); } finally { releaseSharedLock(); } @@ -785,10 +786,10 @@ public class SqliteEamDb extends AbstractSqlEamDb { * @throws EamDbException */ @Override - public int newReferencelSet(EamGlobalSet eamGlobalSet) throws EamDbException { + public int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException { try{ acquireExclusiveLock(); - return super.newReferencelSet(eamGlobalSet); + return super.newReferenceSet(eamGlobalSet); } finally { releaseExclusiveLock(); } diff --git a/Core/src/org/sleuthkit/autopsy/coordinationservice/CaseNodeData.java b/Core/src/org/sleuthkit/autopsy/coordinationservice/CaseNodeData.java new file mode 100755 index 0000000000..0b220e04b2 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/coordinationservice/CaseNodeData.java @@ -0,0 +1,141 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.coordinationservice; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; + +/** + * An object that converts case data for a case directory coordination service + * node to and from byte arrays. + */ +public final class CaseNodeData { + + private static final int CURRENT_VERSION = 0; + + private int version; + private boolean errorsOccurred; + + /** + * Gets the current version of the case directory coordination service node + * data. + * + * @return The version number. + */ + public static int getCurrentVersion() { + return CaseNodeData.CURRENT_VERSION; + } + + /** + * Uses coordination service node data to construct an object that converts + * case data for a case directory coordination service node to and from byte + * arrays. + * + * @param nodeData The raw bytes received from the coordination service. + * + * @throws InvalidDataException If the node data buffer is smaller than + * expected. + */ + public CaseNodeData(byte[] nodeData) throws InvalidDataException { + if(nodeData == null || nodeData.length == 0) { + this.version = CURRENT_VERSION; + this.errorsOccurred = false; + } else { + /* + * Get fields from node data. + */ + ByteBuffer buffer = ByteBuffer.wrap(nodeData); + try { + if (buffer.hasRemaining()) { + this.version = buffer.getInt(); + + /* + * Flags bit format: 76543210 + * 0-6 --> reserved for future use + * 7 --> errorsOccurred + */ + byte flags = buffer.get(); + this.errorsOccurred = (flags < 0); + } + } catch (BufferUnderflowException ex) { + throw new InvalidDataException("Node data is incomplete", ex); + } + } + } + + /** + * Gets whether or not any errors occurred during the processing of the job. + * + * @return True or false. + */ + public boolean getErrorsOccurred() { + return this.errorsOccurred; + } + + /** + * Sets whether or not any errors occurred during the processing of job. + * + * @param errorsOccurred True or false. + */ + public void setErrorsOccurred(boolean errorsOccurred) { + this.errorsOccurred = errorsOccurred; + } + + /** + * Gets the node data version number. + * + * @return The version number. + */ + public int getVersion() { + return this.version; + } + + /** + * Gets the node data as a byte array that can be sent to the coordination + * service. + * + * @return The node data as a byte array. + */ + public byte[] toArray() { + ByteBuffer buffer = ByteBuffer.allocate(5); + + buffer.putInt(this.version); + buffer.put((byte)(this.errorsOccurred ? 0x80 : 0)); + + // Prepare the array + byte[] array = new byte[buffer.position()]; + buffer.rewind(); + buffer.get(array, 0, array.length); + + return array; + } + + public final static class InvalidDataException extends Exception { + + private static final long serialVersionUID = 1L; + + private InvalidDataException(String message) { + super(message); + } + + private InvalidDataException(String message, Throwable cause) { + super(message, cause); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java index 0b660acd2a..83250f719d 100755 --- a/Core/src/org/sleuthkit/autopsy/core/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/core/Installer.java @@ -29,15 +29,15 @@ import java.util.logging.Handler; import java.util.logging.Level; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; -import javax.swing.SwingWorker; -import org.openide.LifecycleManager; import org.openide.modules.ModuleInstall; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.actions.IngestRunningCheck; import org.sleuthkit.autopsy.casemodule.Case; +import static org.sleuthkit.autopsy.core.UserPreferences.SETTINGS_PROPERTIES; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; /** @@ -206,6 +206,9 @@ public class Installer extends ModuleInstall { // Prevent the Autopsy UI from shrinking on high DPI displays System.setProperty("sun.java2d.dpiaware", "false"); System.setProperty("prism.allowhidpi", "false"); + + // Update existing configuration in case of unsupported settings + updateConfig(); packageInstallers = new ArrayList<>(); packageInstallers.add(org.sleuthkit.autopsy.coreutils.Installer.getDefault()); @@ -214,6 +217,21 @@ public class Installer extends ModuleInstall { packageInstallers.add(org.sleuthkit.autopsy.ingest.Installer.getDefault()); packageInstallers.add(org.sleuthkit.autopsy.centralrepository.eventlisteners.Installer.getDefault()); } + + /** + * If the mode in the configuration file is 'REVIEW' (2, now invalid), this + * method will set it to 'STANDALONE' (0) and disable auto ingest. + */ + private void updateConfig() { + String mode = ModuleSettings.getConfigSetting(SETTINGS_PROPERTIES, "AutopsyMode"); + if(mode != null) { + int ordinal = Integer.parseInt(mode); + if(ordinal > 1) { + UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); + ModuleSettings.setConfigSetting(UserPreferences.SETTINGS_PROPERTIES, "JoinAutoModeCluster", Boolean.toString(false)); + } + } + } /** * Check if JavaFx initialized diff --git a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java index df63b0fa1f..86f68e1df5 100755 --- a/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java +++ b/Core/src/org/sleuthkit/autopsy/core/UserPreferences.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import java.util.prefs.BackingStoreException; import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo; import java.util.prefs.PreferenceChangeListener; import java.util.prefs.Preferences; -import org.openide.util.Exceptions; import org.openide.util.NbPreferences; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; @@ -76,8 +75,7 @@ public final class UserPreferences { public enum SelectedMode { STANDALONE, - AUTOINGEST, - REVIEW + AUTOINGEST }; /** diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index 95cfcd481e..fb5618c6e6 100755 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -51,7 +51,7 @@ - + @@ -157,7 +157,7 @@ - + @@ -165,11 +165,11 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java index c196adae4c..f32d82148e 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/BlackboardResultViewer.java @@ -24,7 +24,10 @@ import org.sleuthkit.datamodel.BlackboardArtifact; /** * Additional functionality of viewers supporting black board results such as * the directory tree + * + *@deprecated No longer used. */ +@Deprecated public interface BlackboardResultViewer { public static final String FINISHED_DISPLAY_EVT = "FINISHED_DISPLAY_EVT"; //NON-NLS diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java similarity index 73% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java rename to Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java index fe53871dd5..e14b5c5897 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/TimeStampUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/TimeStampUtils.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.coreutils; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -24,32 +24,32 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Utility methods for working with strings with the time-stamp suffixes used by - * auto ingest. + * Utility methods for working with time stamps of the form + * 'yyyy_MM_dd_HH_mm_ss'. */ public final class TimeStampUtils { /* * Sample time stamp suffix: 2015_02_02_12_10_31 */ - private static final Pattern timeStampPattern = Pattern.compile("\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}$"); + private static final Pattern TIME_STAMP_PATTERN = Pattern.compile("\\d{4}_\\d{2}_\\d{2}_\\d{2}_\\d{2}_\\d{2}$"); private static final int LENGTH_OF_DATE_TIME_STAMP = 20; // length of the above time stamp - private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss"); + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss"); /** - * Checks whether a string ends with an auto ingest time stamp. + * Checks whether a string ends with a time stamp. * * @param inputString The string to check. * * @return True or false. */ public static boolean endsWithTimeStamp(String inputString) { - Matcher m = timeStampPattern.matcher(inputString); + Matcher m = TIME_STAMP_PATTERN.matcher(inputString); return m.find(); } /** - * Gets the fixed length of the auto-ingest time stamp suffix. + * Gets the fixed length of the time stamp suffix. * * @return The length. */ @@ -58,16 +58,16 @@ public final class TimeStampUtils { } /** - * Creates an auto ingest time stamp suffix using the current time. + * Creates a time stamp suffix using the current time. * * @return The suffix. */ public static String createTimeStamp() { - return dateFormat.format(Calendar.getInstance().getTime()); + return DATE_FORMAT.format(Calendar.getInstance().getTime()); } /** - * Removes an auto ingest timestamp suffix, if it present. + * Removes the time stamp suffix from a string, if present. * * @param inputString The string to trim. * @@ -82,7 +82,7 @@ public final class TimeStampUtils { } /** - * Gets the auto ingest time stamp suffix from a string, if it is present. + * Gets the time stamp suffix from a string, if present. * * @param inputString the name to check for a timestamp * diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AutoIngestDataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AutoIngestDataSourceProcessor.java index 11c0559795..163d164376 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AutoIngestDataSourceProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AutoIngestDataSourceProcessor.java @@ -43,9 +43,7 @@ public interface AutoIngestDataSourceProcessor extends DataSourceProcessor { * or less means the data source is not supported by the * DataSourceProcessor. Value of 100 indicates high certainty in * being able to process the data source. - * - * @throws - * org.sleuthkit.autopsy.corecomponentinterfaces.AutomatedIngestDataSourceProcessor.AutomatedIngestDataSourceProcessorException + * @throws org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException */ int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException; @@ -65,9 +63,7 @@ public interface AutoIngestDataSourceProcessor extends DataSourceProcessor { * background task to report progress. * @param callBack Callback that will be used by the background task * to return results. - * - * @throws - * org.sleuthkit.autopsy.corecomponentinterfaces.AutomatedIngestDataSourceProcessor.AutomatedIngestDataSourceProcessorException + * @throws org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException */ void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index aa8f1f3a90..647c6f70d3 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -59,8 +59,6 @@ DirectoryTreeFilterNode.action.collapseAll.text=Collapse All DirectoryTreeFilterNode.action.openFileSrcByAttr.text=Open File Search by Attributes DirectoryTreeFilterNode.action.runIngestMods.text=Run Ingest Modules DirectoryTreeTopComponent.action.viewArtContent.text=View Artifact Content -DirectoryTreeTopComponent.moduleErr=Module Error -DirectoryTreeTopComponent.moduleErr.msg=A module caused an error listening to DirectoryTreeTopComponent updates. See log to determine which module. Some data could be incomplete. DirectoryTreeTopComponent.showRejectedCheckBox.text=Show Rejected Results ExplorerNodeActionVisitor.action.imgDetails.title=Image Details ExplorerNodeActionVisitor.action.extUnallocToSingleFiles=Extract Unallocated Space to Single Files diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle_ja.properties index 2fb64c5bea..6f208c3300 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle_ja.properties @@ -56,8 +56,6 @@ DataResultFilterNode.action.viewInDir.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\ DirectoryTreeFilterNode.action.openFileSrcByAttr.text=\u5c5e\u6027\u306b\u3088\u308b\u30d5\u30a1\u30a4\u30eb\u691c\u7d22\u3092\u958b\u304f DirectoryTreeFilterNode.action.runIngestMods.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u5b9f\u884c DirectoryTreeTopComponent.action.viewArtContent.text=\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u8868\u793a -DirectoryTreeTopComponent.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc -DirectoryTreeTopComponent.moduleErr.msg=DirectoryTreeTopComponent\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3092\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u4e0d\u5b8c\u5168\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 ExplorerNodeActionVisitor.action.imgDetails.title=\u30a4\u30e1\u30fc\u30b8\u8a73\u7d30 ExplorerNodeActionVisitor.action.extUnallocToSingleFiles=\u672a\u5272\u308a\u5f53\u3066\u9818\u57df\u5185\u306e\u30c7\u30fc\u30bf\u3092\u30b7\u30f3\u30b0\u30eb\u30d5\u30a1\u30a4\u30eb\u306b\u62bd\u51fa ExplorerNodeActionVisitor.action.fileSystemDetails.title=\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u8a73\u7d30 @@ -87,4 +85,4 @@ ExtractUnallocAction.done.notifyMsg.completedExtract.msg=\u30d5\u30a1\u30a4\u30e ExtractUnallocAction.done.errMsg.title=\u62bd\u51fa\u30a8\u30e9\u30fc ExtractUnallocAction.done.errMsg.msg=\u672a\u5272\u308a\u5f53\u3066\u9818\u57df\u3092\u62bd\u51fa\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a{0} DirectoryTreeFilterNode.action.collapseAll.text=\u3059\u3079\u3066\u30b3\u30e9\u30d7\u30b9 -ExtractAction.done.notifyMsg.extractErr=\u4e0b\u8a18\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u62bd\u51fa\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0} \ No newline at end of file +ExtractAction.done.notifyMsg.extractErr=\u4e0b\u8a18\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u62bd\u51fa\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 03c265daee..9738f1f4a6 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -27,7 +27,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -56,13 +55,11 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.CoreComponentControl; import org.sleuthkit.autopsy.corecomponentinterfaces.DataExplorer; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.TableFilterNode; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ArtifactNodeSelectionInfo; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.CreditCards; @@ -99,7 +96,7 @@ import org.sleuthkit.datamodel.TskCoreException; @Messages({ "DirectoryTreeTopComponent.resultsView.title=Listing" }) -public final class DirectoryTreeTopComponent extends TopComponent implements DataExplorer, ExplorerManager.Provider, BlackboardResultViewer { +public final class DirectoryTreeTopComponent extends TopComponent implements DataExplorer, ExplorerManager.Provider { private final transient ExplorerManager em = new ExplorerManager(); private static DirectoryTreeTopComponent instance; @@ -851,7 +848,6 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat return false; } - @Override public void viewArtifact(final BlackboardArtifact art) { int typeID = art.getArtifactTypeID(); String typeName = art.getArtifactTypeName(); @@ -1064,28 +1060,14 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat // Another thread is needed because we have to wait for dataResult to populate } - @Override public void viewArtifactContent(BlackboardArtifact art) { new ViewContextAction( NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.action.viewArtContent.text"), new BlackboardArtifactNode(art)).actionPerformed(null); } - @Override public void addOnFinishedListener(PropertyChangeListener l) { DirectoryTreeTopComponent.this.addPropertyChangeListener(l); } - void fireViewerComplete() { - - try { - firePropertyChange(BlackboardResultViewer.FINISHED_DISPLAY_EVT, 0, 1); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "DirectoryTreeTopComponent listener threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "DirectoryTreeTopComponent.moduleErr"), - NbBundle.getMessage(this.getClass(), - "DirectoryTreeTopComponent.moduleErr.msg"), - MessageNotifyUtil.MessageType.ERROR); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form index e00c4a966f..50706d661f 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.form @@ -3,7 +3,7 @@
- + @@ -32,19 +32,24 @@ + + + + + - + - + @@ -55,7 +60,7 @@ - + @@ -81,13 +86,18 @@ - + + + + + + @@ -103,7 +113,7 @@ - + @@ -114,7 +124,7 @@ - + @@ -137,6 +147,11 @@ + + + + + @@ -149,42 +164,35 @@ - - - - - - - - - - - + + + + - + - + - - - + + + - + @@ -224,6 +232,15 @@ + + + + + + + + + @@ -237,6 +254,15 @@ + + + + + + + + + @@ -250,6 +276,15 @@ + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java index b2497baed8..f87c6b4e33 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerGlobalSettingsPanel.java @@ -93,13 +93,17 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme editRuleButton = new javax.swing.JButton(); deleteRuleButton = new javax.swing.JButton(); - setPreferredSize(new java.awt.Dimension(750, 500)); + setPreferredSize(new java.awt.Dimension(701, 453)); + + jPanel1.setPreferredSize(new java.awt.Dimension(701, 453)); org.openide.awt.Mnemonics.setLocalizedText(externalViewerTitleLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text")); // NOI18N - jSplitPane1.setDividerLocation(350); + jSplitPane1.setDividerLocation(365); jSplitPane1.setDividerSize(1); + exePanel.setPreferredSize(new java.awt.Dimension(311, 224)); + org.openide.awt.Mnemonics.setLocalizedText(exePathLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.exePathLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(exePathNameLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.exePathNameLabel.text")); // NOI18N @@ -113,7 +117,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addGroup(exePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(exePathLabel) .addComponent(exePathNameLabel)) - .addContainerGap(159, Short.MAX_VALUE)) + .addContainerGap(47, Short.MAX_VALUE)) ); exePanelLayout.setVerticalGroup( exePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -122,17 +126,22 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addComponent(exePathLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(exePathNameLabel) - .addContainerGap(408, Short.MAX_VALUE)) + .addContainerGap(361, Short.MAX_VALUE)) ); jSplitPane1.setRightComponent(exePanel); + rulesPanel.setPreferredSize(new java.awt.Dimension(365, 406)); + org.openide.awt.Mnemonics.setLocalizedText(ruleListLabel, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.ruleListLabel.text")); // NOI18N rulesScrollPane.setViewportView(rulesList); newRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newRuleButton, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.newRuleButton.text")); // NOI18N + newRuleButton.setMaximumSize(new java.awt.Dimension(111, 25)); + newRuleButton.setMinimumSize(new java.awt.Dimension(111, 25)); + newRuleButton.setPreferredSize(new java.awt.Dimension(111, 25)); newRuleButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { newRuleButtonActionPerformed(evt); @@ -141,6 +150,9 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme editRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/edit16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(editRuleButton, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.editRuleButton.text")); // NOI18N + editRuleButton.setMaximumSize(new java.awt.Dimension(111, 25)); + editRuleButton.setMinimumSize(new java.awt.Dimension(111, 25)); + editRuleButton.setPreferredSize(new java.awt.Dimension(111, 25)); editRuleButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { editRuleButtonActionPerformed(evt); @@ -149,6 +161,9 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme deleteRuleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(deleteRuleButton, org.openide.util.NbBundle.getMessage(ExternalViewerGlobalSettingsPanel.class, "ExternalViewerGlobalSettingsPanel.deleteRuleButton.text")); // NOI18N + deleteRuleButton.setMaximumSize(new java.awt.Dimension(111, 25)); + deleteRuleButton.setMinimumSize(new java.awt.Dimension(111, 25)); + deleteRuleButton.setPreferredSize(new java.awt.Dimension(111, 25)); deleteRuleButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { deleteRuleButtonActionPerformed(evt); @@ -162,20 +177,16 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addGroup(rulesPanelLayout.createSequentialGroup() .addContainerGap() .addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(rulesPanelLayout.createSequentialGroup() - .addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(ruleListLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(rulesPanelLayout.createSequentialGroup() - .addComponent(rulesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 311, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) - .addGroup(rulesPanelLayout.createSequentialGroup() - .addComponent(newRuleButton) + .addComponent(ruleListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(rulesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, rulesPanelLayout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(newRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(editRuleButton) + .addComponent(editRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteRuleButton) - .addGap(0, 0, Short.MAX_VALUE)))) + .addComponent(deleteRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) ); rulesPanelLayout.setVerticalGroup( rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -183,12 +194,12 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addContainerGap() .addComponent(ruleListLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 328, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(rulesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newRuleButton) - .addComponent(editRuleButton) - .addComponent(deleteRuleButton)) + .addComponent(newRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(editRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteRuleButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); @@ -202,12 +213,12 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(externalViewerTitleLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 777, Short.MAX_VALUE) + .addComponent(externalViewerTitleLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 681, Short.MAX_VALUE) .addContainerGap()) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 777, Short.MAX_VALUE) + .addComponent(jScrollPane1) .addContainerGap())) ); jPanel1Layout.setVerticalGroup( @@ -215,7 +226,7 @@ final class ExternalViewerGlobalSettingsPanel extends javax.swing.JPanel impleme .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addComponent(externalViewerTitleLabel) - .addContainerGap(475, Short.MAX_VALUE)) + .addContainerGap(428, Short.MAX_VALUE)) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addGap(32, 32, 32) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java similarity index 91% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java index b9040b674b..af37f3f2e3 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CenteredGrayableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/CenteredGrayableCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; import static javax.swing.SwingConstants.CENTER; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java similarity index 92% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java index 6bac0a996b..6aab063952 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DurationCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,8 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; +import java.awt.Color; import java.awt.Component; import java.time.Duration; import javax.swing.JTable; @@ -28,11 +29,11 @@ import static javax.swing.SwingConstants.CENTER; * string with days, hours, minutes, and seconds components. It center-aligns * cell content and grays out the cell if the table is disabled. */ -class DurationCellRenderer extends GrayableCellRenderer { +public class DurationCellRenderer extends GrayableCellRenderer { private static final long serialVersionUID = 1L; - DurationCellRenderer() { + public DurationCellRenderer() { setHorizontalAlignment(CENTER); } @@ -71,4 +72,5 @@ class DurationCellRenderer extends GrayableCellRenderer { grayCellIfTableNotEnabled(table, isSelected); return this; } + } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/GrayableCellRenderer.java similarity index 88% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/GrayableCellRenderer.java index 60d3b77ccd..6fbf9d5133 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/GrayableCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/GrayableCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; import java.awt.Color; import java.awt.Component; @@ -28,11 +28,11 @@ import javax.swing.table.DefaultTableCellRenderer; * A JTable cell renderer that left-aligns cell content and grays out the cell * if the table is disabled. */ -class GrayableCellRenderer extends DefaultTableCellRenderer { +public class GrayableCellRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 1L; - GrayableCellRenderer() { + public GrayableCellRenderer() { setHorizontalAlignment(LEFT); } @@ -45,7 +45,7 @@ class GrayableCellRenderer extends DefaultTableCellRenderer { return this; } - void grayCellIfTableNotEnabled(JTable table, boolean isSelected) { + public void grayCellIfTableNotEnabled(JTable table, boolean isSelected) { if (table.isEnabled()) { /* * The table is enabled, make the foreground and background the diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java similarity index 91% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java index cfa2cedb14..373e4e2501 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/LongDateCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/LongDateCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; import java.awt.Component; import java.text.SimpleDateFormat; @@ -28,7 +28,7 @@ import static javax.swing.SwingConstants.CENTER; * center-aligned, long-format date string. It also grays out the cell if the * table is disabled. */ -class LongDateCellRenderer extends GrayableCellRenderer { +public class LongDateCellRenderer extends GrayableCellRenderer { private static final long serialVersionUID = 1L; private static final String FORMAT_STRING = "yyyy/MM/dd HH:mm:ss"; //NON-NLS diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java similarity index 96% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java rename to Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java index 713d177c0a..d9fabe7854 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ShortDateCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/ShortDateCellRenderer.java @@ -16,8 +16,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.experimental.autoingest; +package org.sleuthkit.autopsy.guiutils; +import java.awt.Color; import java.awt.Component; import java.text.SimpleDateFormat; import javax.swing.JTable; @@ -46,4 +47,5 @@ class ShortDateCellRenderer extends GrayableCellRenderer { grayCellIfTableNotEnabled(table, isSelected); return this; } + } diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java new file mode 100755 index 0000000000..b7ee58e4d4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/guiutils/StatusIconCellRenderer.java @@ -0,0 +1,74 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015-2017 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.guiutils; + +import java.awt.Component; +import javax.swing.ImageIcon; +import javax.swing.JTable; +import static javax.swing.SwingConstants.CENTER; +import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle.Messages; + +/** + * A JTable cell renderer that represents a status as a center-aligned icon, and + * grays out the cell if the table is disabled. The statuses represented are OK, + * WARNING, and ERROR. + */ +public class StatusIconCellRenderer extends GrayableCellRenderer { + + private static final long serialVersionUID = 1L; + static final ImageIcon OK_ICON = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/tick.png", false)); + static final ImageIcon WARNING_ICON = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/warning16.png", false)); + static final ImageIcon ERROR_ICON = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/cross-script.png", false)); + + @Messages({ + "StatusIconCellRenderer.tooltiptext.ok=OK", + "StatusIconCellRenderer.tooltiptext.warning=A warning occurred", + "StatusIconCellRenderer.tooltiptext.error=An error occurred" + }) + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + setHorizontalAlignment(CENTER); + if ((value instanceof Status)) { + switch((Status) value) { + case OK: + setIcon(OK_ICON); + setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.ok")); + break; + case WARNING: + setIcon(WARNING_ICON); + setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.warning")); + break; + case ERROR: + setIcon(ERROR_ICON); + setToolTipText(org.openide.util.NbBundle.getMessage(StatusIconCellRenderer.class, "StatusIconCellRenderer.tooltiptext.error")); + break; + } + } + grayCellIfTableNotEnabled(table, isSelected); + + return this; + } + + public enum Status { + OK, + WARNING, + ERROR + } +} diff --git a/Core/src/org/sleuthkit/autopsy/images/tick.png b/Core/src/org/sleuthkit/autopsy/images/tick.png new file mode 100755 index 0000000000..a7d7a96be3 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/tick.png differ diff --git a/Core/src/org/sleuthkit/autopsy/images/warning16.png b/Core/src/org/sleuthkit/autopsy/images/warning16.png new file mode 100755 index 0000000000..f5ba881738 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/warning16.png differ diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java index 0a8222bca0..2659ce400a 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMessageDetailsPanel.java @@ -21,14 +21,11 @@ package org.sleuthkit.autopsy.ingest; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import javax.swing.JMenuItem; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; -import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.ingest.IngestMessagePanel.IngestMessageGroup; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -40,7 +37,8 @@ import org.sleuthkit.datamodel.TskException; */ class IngestMessageDetailsPanel extends javax.swing.JPanel { - private IngestMessageMainPanel mainPanel; + private final IngestMessageMainPanel mainPanel; + private final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance(); /** * Creates new form IngestMessageDetailsPanel @@ -69,18 +67,6 @@ class IngestMessageDetailsPanel extends javax.swing.JPanel { styleSheet.addRule("td {white-space:pre-wrap;overflow:hidden;}"); //NON-NLS styleSheet.addRule("th {font-weight:bold;}"); //NON-NLS - BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class); - v.addOnFinishedListener(new PropertyChangeListener() { - - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(BlackboardResultViewer.FINISHED_DISPLAY_EVT)) { - artifactViewerFinished(); - } - } - - }); - //right click messageDetailsPane.setComponentPopupMenu(rightClickMenu); ActionListener actList = new ActionListener() { @@ -193,11 +179,27 @@ class IngestMessageDetailsPanel extends javax.swing.JPanel { }// //GEN-END:initComponents private void viewContentButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewContentButtonActionPerformed - viewContent(evt); + messageDetailsPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + final IngestMessageGroup messageGroup = mainPanel.getMessagePanel().getSelectedMessage(); + if (messageGroup != null) { + BlackboardArtifact art = messageGroup.getData(); + if (art != null) { + dtc.viewArtifactContent(art); + } + } + messageDetailsPane.setCursor(null); }//GEN-LAST:event_viewContentButtonActionPerformed private void viewArtifactButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewArtifactButtonActionPerformed - viewArtifact(evt); + messageDetailsPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + final IngestMessageGroup messageGroup = mainPanel.getMessagePanel().getSelectedMessage(); + if (messageGroup != null) { + BlackboardArtifact art = messageGroup.getData(); + if (art != null) { + dtc.viewArtifact(art); + } + } + messageDetailsPane.setCursor(null); }//GEN-LAST:event_viewArtifactButtonActionPerformed private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed @@ -216,46 +218,6 @@ class IngestMessageDetailsPanel extends javax.swing.JPanel { private javax.swing.JButton viewContentButton; // End of variables declaration//GEN-END:variables - private void viewArtifact(java.awt.event.ActionEvent evt) { - artifactViewerInvoked(); - - final IngestMessageGroup messageGroup = mainPanel.getMessagePanel().getSelectedMessage(); - if (messageGroup != null) { - BlackboardArtifact art = messageGroup.getData(); - if (art != null) { - BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class); - v.viewArtifact(art); - } - } - - } - - private void viewContent(java.awt.event.ActionEvent evt) { - artifactViewerInvoked(); - - final IngestMessageGroup messageGroup = mainPanel.getMessagePanel().getSelectedMessage(); - if (messageGroup != null) { - BlackboardArtifact art = messageGroup.getData(); - if (art != null) { - BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class); - v.viewArtifactContent(art); - } - } - } - - private void artifactViewerInvoked() { - //viewArtifactButton.setEnabled(false); - //viewContentButton.setEnabled(false); - messageDetailsPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - - } - - private void artifactViewerFinished() { - //viewArtifactButton.setEnabled(true); - //viewContentButton.setEnabled(true); - messageDetailsPane.setCursor(null); - } - /** * Display the details of a given message * diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java index 1c761e8578..40f3d1c298 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestOptionsPanel.java @@ -140,9 +140,35 @@ public class IngestOptionsPanel extends IngestModuleGlobalSettingsPanel implemen @Override public void addPropertyChangeListener(PropertyChangeListener l) { - filterPanel.addPropertyChangeListener(l); - settingsPanel.addPropertyChangeListener(l); - profilePanel.addPropertyChangeListener(l); + super.addPropertyChangeListener(l); + /* + * There is at least one look and feel library that follows the bad + * practice of calling overrideable methods in a constructor, e.g.: + * + * at + * javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83) + * at + * javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63) + * at javax.swing.JComponent.setUI(JComponent.java:666) at + * javax.swing.JPanel.setUI(JPanel.java:153) at + * javax.swing.JPanel.updateUI(JPanel.java:126) at + * javax.swing.JPanel.(JPanel.java:86) at + * javax.swing.JPanel.(JPanel.java:109) at + * javax.swing.JPanel.(JPanel.java:117) + * + * When this happens, the following child components of this JPanel + * subclass have not been constructed yet, since this panel's + * constructor has not been called yet. + */ + if (null != filterPanel) { + filterPanel.addPropertyChangeListener(l); + } + if (null != settingsPanel) { + settingsPanel.addPropertyChangeListener(l); + } + if (null != profilePanel) { + profilePanel.addPropertyChangeListener(l); + } } @Override diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 249ded2020..8040893fcf 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -177,7 +177,29 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { @Override public void addPropertyChangeListener(PropertyChangeListener l) { - ingestSettingsPanel.addPropertyChangeListener(l); + super.addPropertyChangeListener(l); + /* + * There is at least one look and feel library that follows the bad + * practice of calling overrideable methods in a constructor, e.g.: + * + * at + * javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83) + * at + * javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63) + * at javax.swing.JComponent.setUI(JComponent.java:666) at + * javax.swing.JPanel.setUI(JPanel.java:153) at + * javax.swing.JPanel.updateUI(JPanel.java:126) at + * javax.swing.JPanel.(JPanel.java:86) at + * javax.swing.JPanel.(JPanel.java:109) at + * javax.swing.JPanel.(JPanel.java:117) + * + * When this happens, the following child components of this JPanel + * subclass have not been constructed yet, since this panel's + * constructor has not been called yet. + */ + if (null != ingestSettingsPanel) { + ingestSettingsPanel.addPropertyChangeListener(l); + } } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel jPanel1; diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java index 582c5c04c4..7d4328da59 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2014 Basis Technology Corp. + * Copyright 2013-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,66 +19,57 @@ package org.sleuthkit.autopsy.modules.embeddedfileextractor; import java.io.File; -import java.util.logging.Level; +import java.nio.file.Paths; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult; import org.sleuthkit.autopsy.ingest.IngestJobContext; -import org.sleuthkit.autopsy.ingest.IngestMessage; -import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; -import org.sleuthkit.autopsy.modules.embeddedfileextractor.ImageExtractor.SupportedImageExtractionFormats; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; import net.sf.sevenzipjbinding.SevenZipNativeInitializationException; +import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter; /** - * Embedded File Extractor ingest module extracts embedded files from supported - * archives and documents, adds extracted embedded DerivedFiles, reschedules - * extracted DerivedFiles for ingest. + * A file level ingest module that extracts embedded files from supported + * archive and document formats. */ @NbBundle.Messages({ "CannotCreateOutputFolder=Unable to create output folder.", "CannotRunFileTypeDetection=Unable to run file type detection.", "UnableToInitializeLibraries=Unable to initialize 7Zip libraries." }) -public final class EmbeddedFileExtractorIngestModule implements FileIngestModule { +public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAdapter { - private static final Logger logger = Logger.getLogger(EmbeddedFileExtractorIngestModule.class.getName()); - private final IngestServices services = IngestServices.getInstance(); static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // "iso"}; NON-NLS - - private IngestJobContext context; - private long jobId; - private final static IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); - private String moduleDirRelative; private String moduleDirAbsolute; - - private boolean archivextraction; - private boolean imageExtraction; private ImageExtractor imageExtractor; private SevenZipExtractor archiveExtractor; - SupportedImageExtractionFormats abstractFileExtractionFormat; - FileTypeDetector fileTypeDetector; + private FileTypeDetector fileTypeDetector; + /** + * Constructs a file level ingest module that extracts embedded files from + * supported archive and document formats. + */ EmbeddedFileExtractorIngestModule() { } @Override public void startUp(IngestJobContext context) throws IngestModuleException { - this.context = context; - jobId = context.getJobId(); - + /* + * Construct absolute and relative paths to the output directory. The + * relative path is relative to the case folder, and will be used in the + * case database for extracted (derived) file paths. The absolute path + * is used to write the extracted (derived) files to local storage. + */ final Case currentCase = Case.getCurrentCase(); + moduleDirRelative = Paths.get(currentCase.getModuleOutputDirectoryRelativePath(), EmbeddedFileExtractorModuleFactory.getModuleName()).toString(); + moduleDirAbsolute = Paths.get(currentCase.getModuleDirectory(), EmbeddedFileExtractorModuleFactory.getModuleName()).toString(); - moduleDirRelative = currentCase.getModuleOutputDirectoryRelativePath() + File.separator + EmbeddedFileExtractorModuleFactory.getModuleName(); //relative to the case, to store in db - moduleDirAbsolute = currentCase.getModuleDirectory() + File.separator + EmbeddedFileExtractorModuleFactory.getModuleName(); //absolute, to extract to - - // initialize the folder where the embedded files are extracted. + /* + * Create the output directory. + */ File extractionDirectory = new File(moduleDirAbsolute); if (!extractionDirectory.exists()) { try { @@ -88,71 +79,77 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule } } - // initialize the filetypedetector + /* + * Construct a file type detector. + */ try { fileTypeDetector = new FileTypeDetector(); } catch (FileTypeDetector.FileTypeDetectorInitException ex) { throw new IngestModuleException(Bundle.CannotRunFileTypeDetection(), ex); } - // initialize the extraction modules. + /* + * Construct a 7Zip file extractor for processing archive files. + */ try { this.archiveExtractor = new SevenZipExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); } catch (SevenZipNativeInitializationException ex) { throw new IngestModuleException(Bundle.UnableToInitializeLibraries(), ex); } + /* + * Construct an embedded images extractor for processing Microsoft + * Office documents. + */ this.imageExtractor = new ImageExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); } @Override public ProcessResult process(AbstractFile abstractFile) { - // skip the unallocated blocks - if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) || - (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) { + /* + * Skip unallocated space files. + */ + if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) + || (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) { return ProcessResult.OK; } - // skip known files + /* + * Skip known files. + */ if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) { return ProcessResult.OK; } - // check if the file is supported by either of the two embedded file extractors. - this.archivextraction = archiveExtractor.isSevenZipExtractionSupported(abstractFile); - this.imageExtraction = imageExtractor.isImageExtractionSupported(abstractFile); - - if (!abstractFile.isFile() && (!this.archivextraction || !this.imageExtraction)) { + /* + * Skip directories, etc. + */ + if (!abstractFile.isFile()) { return ProcessResult.OK; } - // call the archive extractor if archiveExtraction flag is set. - if (this.archivextraction) { + /* + * Attempt embedded file extraction for the file if it is a supported + * type/format. + */ + if (archiveExtractor.isSevenZipExtractionSupported(abstractFile)) { archiveExtractor.unpack(abstractFile); - } - - // calling the image extractor if imageExtraction flag set. - if (this.imageExtraction) { + } else if (imageExtractor.isImageExtractionSupported(abstractFile)) { imageExtractor.extractImage(abstractFile); } - return ProcessResult.OK; } - @Override - public void shutDown() { - // We don't need the value, but for cleanliness and consistency - refCounter.decrementAndGet(jobId); + /** + * Creates a unique name for a file by concatentating the file name and the + * file object id. + * + * @param file The file. + * + * @return The unique file name. + */ + static String getUniqueName(AbstractFile file) { + return file.getName() + "_" + file.getId(); } - /** - * Get local relative path to the unpacked archive root - * - * @param archiveFile - * - * @return - */ - static String getUniqueName(AbstractFile archiveFile) { - return archiveFile.getName() + "_" + archiveFile.getId(); - } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorModuleFactory.java index 1cf8ae462b..57534287a4 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorModuleFactory.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,8 +27,8 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; /** - * A factory for creating archive extractor file ingest modules and the user - * interface panels used to configure the settings for instances of the modules. + * A factory for creating file level ingest module that extracts embedded files + * from supported archive and document formats. */ @NbBundle.Messages({ "EmbeddedFileExtractorIngestModule.ArchiveExtractor.moduleName=Embedded File Extractor", @@ -65,4 +65,5 @@ public class EmbeddedFileExtractorModuleFactory extends IngestModuleFactoryAdapt public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) { return new EmbeddedFileExtractorIngestModule(); } + } diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form index 162aef8994..f8ffc03428 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.form @@ -1,6 +1,11 @@ + + + + + @@ -16,12 +21,12 @@ - + - + @@ -29,7 +34,7 @@ - + @@ -37,36 +42,45 @@ - - - + + + - + - + + + + - + + + + + + + @@ -76,23 +90,26 @@ - + - + + + + + - + - + - + - @@ -101,14 +118,14 @@ - - - + + + - + - + @@ -142,6 +159,15 @@ + + + + + + + + + @@ -166,6 +192,11 @@ + + + + + @@ -198,16 +229,16 @@ - + - - - + + + - + @@ -221,6 +252,12 @@ + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java index 1d5470b4df..85cf916f2c 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchSettingsPanel.java @@ -154,11 +154,18 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel removeExtButton = new javax.swing.JButton(); extHeaderLabel = new javax.swing.JLabel(); - jPanel1.setPreferredSize(new java.awt.Dimension(687, 450)); + setPreferredSize(new java.awt.Dimension(718, 430)); - jSplitPane1.setDividerLocation(430); + jPanel1.setPreferredSize(new java.awt.Dimension(718, 430)); + + jScrollPane1.setRequestFocusEnabled(false); + + jSplitPane1.setDividerLocation(365); jSplitPane1.setDividerSize(1); + mimePanel.setPreferredSize(new java.awt.Dimension(369, 424)); + mimePanel.setRequestFocusEnabled(false); + jLabel1.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.jLabel1.text")); // NOI18N mimeTable.setModel(mimeTableModel); @@ -166,6 +173,9 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel newTypeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N newTypeButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.newTypeButton.text")); // NOI18N + newTypeButton.setMaximumSize(new java.awt.Dimension(111, 25)); + newTypeButton.setMinimumSize(new java.awt.Dimension(111, 25)); + newTypeButton.setPreferredSize(new java.awt.Dimension(111, 25)); newTypeButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { newTypeButtonActionPerformed(evt); @@ -188,16 +198,18 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel .addGroup(mimePanelLayout.createSequentialGroup() .addContainerGap() .addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGroup(mimePanelLayout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(jLabel1) + .addGap(286, 286, 286)) .addGroup(mimePanelLayout.createSequentialGroup() .addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel1) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 349, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(mimePanelLayout.createSequentialGroup() - .addComponent(newTypeButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(newTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(10, 10, 10) .addComponent(removeTypeButton))) - .addGap(0, 191, Short.MAX_VALUE))) - .addContainerGap()) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); mimePanelLayout.setVerticalGroup( mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -205,18 +217,22 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel .addContainerGap() .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 348, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(mimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newTypeButton) + .addComponent(newTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(removeTypeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); jSplitPane1.setLeftComponent(mimePanel); + extensionPanel.setPreferredSize(new java.awt.Dimension(344, 424)); + newExtButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N newExtButton.setText(org.openide.util.NbBundle.getMessage(FileExtMismatchSettingsPanel.class, "FileExtMismatchSettingsPanel.newExtButton.text")); // NOI18N + newExtButton.setMaximumSize(new java.awt.Dimension(111, 25)); + newExtButton.setMinimumSize(new java.awt.Dimension(111, 25)); newExtButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { newExtButtonActionPerformed(evt); @@ -248,7 +264,7 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel .addGroup(extensionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(extHeaderLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 324, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(extensionPanelLayout.createSequentialGroup() - .addComponent(newExtButton) + .addComponent(newExtButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(removeExtButton))) .addGap(0, 0, Short.MAX_VALUE))) @@ -260,10 +276,10 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel .addContainerGap() .addComponent(extHeaderLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 348, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(extensionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newExtButton) + .addComponent(newExtButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(removeExtButton)) .addContainerGap()) ); @@ -277,27 +293,27 @@ final class FileExtMismatchSettingsPanel extends IngestModuleGlobalSettingsPanel jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 797, Short.MAX_VALUE) - .addContainerGap()) + .addGap(0, 0, 0) + .addComponent(jScrollPane1) + .addGap(0, 0, 0)) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 504, Short.MAX_VALUE) - .addContainerGap()) + .addGap(0, 0, 0) + .addComponent(jScrollPane1) + .addGap(0, 0, 0)) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 817, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 526, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java old mode 100755 new mode 100644 index 3e78db6daa..5ec70ce3b9 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java @@ -32,10 +32,10 @@ import org.openide.util.Utilities; import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; +import static org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.TskCoreException; -import static org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; /** * Instances of this Action allow users to content to a hash database. @@ -106,10 +106,10 @@ final class AddContentToHashDbAction extends AbstractAction implements Presenter // Get the current set of updateable hash databases and add each // one to the menu as a separate menu item. Selecting a hash database // adds the selected files to the selected database. - final List hashDatabases = HashDbManager.getInstance().getUpdateableHashDatabases(); + final List hashDatabases = HashDbManager.getInstance().getUpdateableHashSets(); if (!hashDatabases.isEmpty()) { - for (final HashDatabase database : hashDatabases) { - JMenuItem databaseItem = add(database.getDisplayName()); + for (final HashDb database : hashDatabases) { + JMenuItem databaseItem = add(database.getHashSetName()); databaseItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -134,7 +134,7 @@ final class AddContentToHashDbAction extends AbstractAction implements Presenter newHashSetItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - HashDatabase hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); + HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); if (null != hashDb) { addFilesToHashSet(selectedFiles, hashDb); } @@ -143,7 +143,7 @@ final class AddContentToHashDbAction extends AbstractAction implements Presenter add(newHashSetItem); } - private void addFilesToHashSet(final Collection files, HashDatabase hashSet) { + private void addFilesToHashSet(final Collection files, HashDb hashSet) { for (AbstractFile file : files) { String md5Hash = file.getMd5Hash(); if (null != md5Hash) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java index d403da1def..8087144d65 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java @@ -31,8 +31,8 @@ import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.datamodel.HashEntry; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; /** * @@ -40,7 +40,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; */ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { - HashDatabase hashDb; + HashDb hashDb; Pattern md5Pattern = Pattern.compile("^[a-fA-F0-9]{32}$"); List hashes = new ArrayList<>(); List invalidHashes = new ArrayList<>(); @@ -49,7 +49,7 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { * Displays a dialog that allows a user to add hash values to the selected * database. */ - AddHashValuesToDatabaseDialog(HashDatabase hashDb) { + AddHashValuesToDatabaseDialog(HashDb hashDb) { super((JFrame) WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.JDialog.Title", hashDb.getDisplayName()), true); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java index 77483e1d42..f712a965fd 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseProgressDialog.java @@ -31,9 +31,9 @@ import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingWorker; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.datamodel.HashEntry; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; /** * @@ -43,7 +43,7 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { private final AddHashValuesToDatabaseDialog parentRef; private boolean disposeParent = false; - private final HashDatabase hashDb; + private final HashDb hashDb; private final List hashes; private final List invalidHashes; private final Pattern md5Pattern; @@ -58,7 +58,7 @@ public class AddHashValuesToDatabaseProgressDialog extends javax.swing.JDialog { * @param hashDb * @param text */ - AddHashValuesToDatabaseProgressDialog(AddHashValuesToDatabaseDialog parent, HashDatabase hashDb, String text) { + AddHashValuesToDatabaseProgressDialog(AddHashValuesToDatabaseDialog parent, HashDb hashDb, String text) { super(parent); initComponents(); display(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java old mode 100755 new mode 100644 index 9360e45aed..0ecb3a5ad4 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -34,13 +34,14 @@ import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet; import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskCoreException; @@ -54,7 +55,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private static final String DEFAULT_FILE_NAME = NbBundle .getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.defaultFileName"); private JFileChooser fileChooser = null; - private HashDatabase newHashDb = null; + private HashDb newHashDb = null; private final static String LAST_FILE_PATH_KEY = "HashDbCreate_Path"; private EamOrganization selectedOrg = null; private List orgs = null; @@ -77,7 +78,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { * * @return A HashDb object or null. */ - HashDatabase getHashDatabase() { + HashDb getHashDatabase() { return newHashDb; } @@ -474,9 +475,10 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { String errorMessage = NbBundle .getMessage(this.getClass(), "HashDbCreateDatabaseDialog.errMsg.hashDbCreationErr"); + if(fileTypeRadioButton.isSelected()){ try { - newHashDb = HashDbManager.getInstance().addNewFileTypeHashDatabase(hashSetNameTextField.getText(), fileChooser.getSelectedFile().getCanonicalPath(), true, sendIngestMessagesCheckbox.isSelected(), type); + newHashDb = HashDbManager.getInstance().addNewHashDatabaseNoSave(hashSetNameTextField.getText(), fileChooser.getSelectedFile().getCanonicalPath(), true, sendIngestMessagesCheckbox.isSelected(), type); } catch (IOException ex) { Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex); JOptionPane.showMessageDialog(this, @@ -519,10 +521,10 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } try{ - int crIndex = EamDb.getInstance().newReferenceSet(selectedOrg.getOrgID(), hashSetNameTextField.getText(), - EamDb.getDefaultVersion(), fileKnown, false); + int referenceSetID = EamDb.getInstance().newReferenceSet(new EamGlobalSet(selectedOrg.getOrgID(), hashSetNameTextField.getText(), + EamDb.getDefaultVersion(), fileKnown, false)); newHashDb = HashDbManager.getInstance().addExistingCentralRepoHashSet(hashSetNameTextField.getText(), - EamDb.getDefaultVersion(), crIndex, + EamDb.getDefaultVersion(), referenceSetID, true, sendIngestMessagesCheckbox.isSelected(), type, false); } catch (EamDbException | TskCoreException ex){ Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error creating new reference set", ex); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index 6bfb8f77b4..d32fc3cf9c 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -41,7 +41,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class allow a user to select an existing hash database and @@ -52,7 +52,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private JFileChooser fileChooser = new JFileChooser(); private String selectedFilePath = ""; - private HashDatabase selectedHashDb = null; + private HashDb selectedHashDb = null; private final static String LAST_FILE_PATH_KEY = "HashDbImport_Path"; private EamOrganization selectedOrg = null; private List orgs = null; @@ -77,7 +77,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { * * @return A HashDb object or null. */ - HashDatabase getHashDatabase() { + HashDb getHashDatabase() { return selectedHashDb; } @@ -518,7 +518,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { if(fileTypeRadioButton.isSelected()){ try { - selectedHashDb = HashDbManager.getInstance().addExistingFileTypeHashDatabase(hashSetNameTextField.getText(), selectedFilePath, true, sendIngestMessagesCheckbox.isSelected(), type); + selectedHashDb = HashDbManager.getInstance().addExistingHashDatabaseNoSave(hashSetNameTextField.getText(), selectedFilePath, true, sendIngestMessagesCheckbox.isSelected(), type); } catch (HashDbManagerException ex) { Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex); JOptionPane.showMessageDialog(this, diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java old mode 100755 new mode 100644 index bfef98036f..16bcb1d2e9 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -63,8 +63,8 @@ public class HashDbIngestModule implements FileIngestModule { private final SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); private final HashDbManager hashDbManager = HashDbManager.getInstance(); private final HashLookupModuleSettings settings; - private List knownBadHashSets = new ArrayList<>(); - private List knownHashSets = new ArrayList<>(); + private List knownBadHashSets = new ArrayList<>(); + private List knownHashSets = new ArrayList<>(); private long jobId; private static final HashMap totalsForIngestJobs = new HashMap<>(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); @@ -96,8 +96,8 @@ public class HashDbIngestModule implements FileIngestModule { if (!hashDbManager.verifyAllDatabasesLoadedCorrectly()) { throw new IngestModuleException("Could not load all hash databases"); } - updateEnabledHashSets(hashDbManager.getNotableFileHashDatabases(), knownBadHashSets); - updateEnabledHashSets(hashDbManager.getKnownFileHashDatabases(), knownHashSets); + updateEnabledHashSets(hashDbManager.getKnownBadFileHashSets(), knownBadHashSets); + updateEnabledHashSets(hashDbManager.getKnownFileHashSets(), knownHashSets); if (refCounter.incrementAndGet(jobId) == 1) { // initialize job totals @@ -126,9 +126,9 @@ public class HashDbIngestModule implements FileIngestModule { * @param allHashSets List of all hashsets from DB manager * @param enabledHashSets List of enabled ones to return. */ - private void updateEnabledHashSets(List allHashSets, List enabledHashSets) { + private void updateEnabledHashSets(List allHashSets, List enabledHashSets) { enabledHashSets.clear(); - for (HashDatabase db : allHashSets) { + for (HashDb db : allHashSets) { if (settings.isHashSetEnabled(db)) { try { if (db.isValid()) { @@ -196,7 +196,7 @@ public class HashDbIngestModule implements FileIngestModule { // look up in notable first boolean foundBad = false; ProcessResult ret = ProcessResult.OK; - for (HashDatabase db : knownBadHashSets) { + for (HashDb db : knownBadHashSets) { try { long lookupstart = System.currentTimeMillis(); HashHitInfo hashInfo = db.lookupMD5(file); @@ -257,7 +257,7 @@ public class HashDbIngestModule implements FileIngestModule { // Any hit is sufficient to classify it as known, and there is no need to create // a hit artifact or send a message to the application inbox. if (!foundBad) { - for (HashDatabase db : knownHashSets) { + for (HashDb db : knownHashSets) { try { long lookupstart = System.currentTimeMillis(); if (db.lookupMD5Quick(file)) { @@ -359,7 +359,7 @@ public class HashDbIngestModule implements FileIngestModule { } private static synchronized void postSummary(long jobId, - List knownBadHashSets, List knownHashSets) { + List knownBadHashSets, List knownHashSets) { IngestJobTotals jobTotals = getTotalsForIngestJobs(jobId); totalsForIngestJobs.remove(jobId); @@ -384,8 +384,8 @@ public class HashDbIngestModule implements FileIngestModule { detailsSb.append("

") //NON-NLS .append(NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.complete.databasesUsed")) .append("

\n
    "); //NON-NLS - for (HashDatabase db : knownBadHashSets) { - detailsSb.append("
  • ").append(db.getDisplayName()).append("
  • \n"); //NON-NLS + for (HashDb db : knownBadHashSets) { + detailsSb.append("
  • ").append(db.getHashSetName()).append("
  • \n"); //NON-NLS } detailsSb.append("
"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java old mode 100755 new mode 100644 index 975f36b993..5d7a776090 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -65,7 +65,7 @@ public class HashDbManager implements PropertyChangeListener { private static final String HASH_DATABASE_FILE_EXTENSON = "kdb"; //NON-NLS private static HashDbManager instance = null; - private List hashSets = new ArrayList<>(); + private List hashSets = new ArrayList<>(); private Set hashSetNames = new HashSet<>(); private Set hashSetPaths = new HashSet<>(); PropertyChangeSupport changeSupport = new PropertyChangeSupport(HashDbManager.class); @@ -153,7 +153,6 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - @Deprecated public synchronized HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { HashDb hashDb = null; hashDb = this.addExistingHashDatabaseNoSave(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); @@ -161,12 +160,7 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - @Deprecated synchronized HashDb addExistingHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { - return (HashDb)addExistingFileTypeHashDatabase(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); - } - - synchronized HashDatabase addExistingFileTypeHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { HashDb hashDb = null; try { if (!new File(path).exists()) { @@ -181,7 +175,7 @@ public class HashDbManager implements PropertyChangeListener { throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName)); } - hashDb = addFileTypeHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); + hashDb = addHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); } catch (TskCoreException ex) { throw new HashDbManagerException(ex.getMessage()); } @@ -206,7 +200,6 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - @Deprecated public synchronized HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { @@ -218,14 +211,8 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - @Deprecated public synchronized HashDb addNewHashDatabaseNoSave(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { - return (HashDb)addNewFileTypeHashDatabase(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType); - } - - public synchronized HashDatabase addNewFileTypeHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, - HashDb.KnownFilesType knownFilesType) throws HashDbManagerException { HashDb hashDb = null; try { File file = new File(path); @@ -245,16 +232,16 @@ public class HashDbManager implements PropertyChangeListener { throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName)); } - hashDb = addFileTypeHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); + hashDb = addHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); } catch (TskCoreException ex) { throw new HashDbManagerException(ex.getMessage()); } return hashDb; } - private HashDb addFileTypeHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException { + private SleuthkitHashSet addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException { // Wrap an object around the handle. - HashDb hashDb = new HashDb(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); + SleuthkitHashSet hashDb = new SleuthkitHashSet(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType); // Get the indentity data before updating the collections since the // accessor methods may throw. @@ -287,7 +274,7 @@ public class HashDbManager implements PropertyChangeListener { return hashDb; } - public CentralRepoHashDb addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID, + CentralRepoHashSet addExistingCentralRepoHashSet(String hashSetName, String version, int referenceSetID, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType, boolean readOnly) throws TskCoreException{ @@ -295,7 +282,7 @@ public class HashDbManager implements PropertyChangeListener { throw new TskCoreException("Could not load central repository database " + hashSetName + " - central repository is not enabled"); } - CentralRepoHashDb db = new CentralRepoHashDb(hashSetName, version, referenceSetID, searchDuringIngest, + CentralRepoHashSet db = new CentralRepoHashSet(hashSetName, version, referenceSetID, searchDuringIngest, sendIngestMessages, knownFilesType, readOnly); if(! db.isValid()){ @@ -319,7 +306,7 @@ public class HashDbManager implements PropertyChangeListener { } - synchronized void indexHashDatabase(HashDb hashDb) { + synchronized void indexHashDatabase(SleuthkitHashSet hashDb) { hashDb.addPropertyChangeListener(this); HashDbIndexer creator = new HashDbIndexer(hashDb); creator.execute(); @@ -327,8 +314,8 @@ public class HashDbManager implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent event) { - if (event.getPropertyName().equals(HashDb.Event.INDEXING_DONE.name())) { - HashDb hashDb = (HashDb) event.getNewValue(); + if (event.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.name())) { + SleuthkitHashSet hashDb = (SleuthkitHashSet) event.getNewValue(); if (null != hashDb) { try { String indexPath = hashDb.getIndexPath(); @@ -350,12 +337,12 @@ public class HashDbManager implements PropertyChangeListener { * * @throws HashDbManagerException */ - public synchronized void removeHashDatabase(HashDatabase hashDb) throws HashDbManagerException { + public synchronized void removeHashDatabase(HashDb hashDb) throws HashDbManagerException { this.removeHashDatabaseNoSave(hashDb); this.save(); } - public synchronized void removeHashDatabaseNoSave(HashDatabase hashDatabase) throws HashDbManagerException { + public synchronized void removeHashDatabaseNoSave(HashDb hashDb) throws HashDbManagerException { // Don't remove a database if ingest is running boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); if (ingestIsRunning) { @@ -365,36 +352,36 @@ public class HashDbManager implements PropertyChangeListener { // and remove its hash set name from the hash set used to ensure unique // hash set names are used, before undertaking These operations will succeed and constitute // a mostly effective removal, even if the subsequent operations fail. - String hashSetName = hashDatabase.getHashSetName(); + String hashSetName = hashDb.getHashSetName(); hashSetNames.remove(hashSetName); - hashSets.remove(hashDatabase); + hashSets.remove(hashDb); // Now undertake the operations that could throw. - // Indexing is only relevanet for file type hashsets - if(hashDatabase instanceof HashDb){ - HashDb hashDb = (HashDb)hashDatabase; + // Indexing is only relevanet for sleuthkit hashsets + if(hashDb instanceof SleuthkitHashSet){ + SleuthkitHashSet hashDatabase = (SleuthkitHashSet)hashDb; try { - if(hashDb.hasIndex()){ - hashSetPaths.remove(hashDb.getIndexPath()); + if(hashDatabase.hasIndex()){ + hashSetPaths.remove(hashDatabase.getIndexPath()); } } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDatabase.getHashSetName() + " hash database when removing the database", ex); //NON-NLS } try { - if (!hashDb.hasIndexOnly()) { - hashSetPaths.remove(hashDb.getDatabasePath()); + if (!hashDatabase.hasIndexOnly()) { + hashSetPaths.remove(hashDatabase.getDatabasePath()); } } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting database path of " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting database path of " + hashDatabase.getHashSetName() + " hash database when removing the database", ex); //NON-NLS } - } - try { - hashDatabase.close(); - } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDatabase.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + try { + hashDatabase.close(); + } catch (TskCoreException ex) { + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS + } } // Let any external listeners know that a set has been deleted @@ -418,56 +405,24 @@ public class HashDbManager implements PropertyChangeListener { throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg")); } } - + /** * Gets all of the hash databases used to classify files as known or known - * bad. + * bad. Will add any new central repository databases to the list before + * returning it. * * @return A list, possibly empty, of hash databases. */ - @Deprecated public synchronized List getAllHashSets() { - return getAllFileTypeHashSets(); - } - - /** - * Gets all of the file type hash databases used to classify files as known or known - * bad. - * - * @return A list, possibly empty, of hash databases. - */ - public synchronized List getAllFileTypeHashSets() { - List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((thisSet) -> (thisSet instanceof HashDb)).forEach((thisSet) -> { - hashDbs.add((HashDb)thisSet); - }); - return hashDbs; - } - - /** - * Gets all of the hash databases used to classify files as known or known - * bad. - * - * @return A list, possibly empty, of hash databases. - */ - public synchronized List getAllHashDatabases(){ - List hashDbs = new ArrayList<>(); - hashDbs.addAll(this.hashSets); - return hashDbs; - } - - /** - * Adds any new central repository databases to the list of hashes - * before returning a copy of the hash set list - * @return A list, possibly empty, of hash databases. - */ - public synchronized List refreshAndGetAllHashDatabases(){ try{ updateHashSetsFromCentralRepository(); } catch (TskCoreException ex){ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS } - return getAllHashDatabases(); + + List hashDbs = new ArrayList<>(); + hashDbs.addAll(this.hashSets); + return hashDbs; } /** @@ -475,49 +430,31 @@ public class HashDbManager implements PropertyChangeListener { * * @return A list, possibly empty, of hash databases. */ - @Deprecated public synchronized List getKnownFileHashSets() { List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((thisSet) -> ((thisSet instanceof HashDb) && (thisSet.getKnownFilesType() == HashDb.KnownFilesType.KNOWN))).forEach((thisSet) -> { - hashDbs.add((HashDb)thisSet); - }); - return hashDbs; - } - - /** - * Gets all of the hash databases used to classify files as known. - * - * @return A list, possibly empty, of hash databases. - */ - public synchronized List getKnownFileHashDatabases() { - List hashDbs = new ArrayList<>(); + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN)).forEach((db) -> { hashDbs.add(db); }); return hashDbs; - } + } /** * Gets all of the hash databases used to classify files as notable. * * @return A list, possibly empty, of hash databases. */ - @Deprecated public synchronized List getKnownBadFileHashSets() { List hashDbs = new ArrayList<>(); - this.hashSets.stream().filter((thisSet) -> ((thisSet instanceof HashDb) && (thisSet.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD))).forEach((thisSet) -> { - hashDbs.add((HashDb)thisSet); - }); - return hashDbs; - } - - /** - * Gets all of the hash databases used to classify files as notable. - * - * @return A list, possibly empty, of hash databases. - */ - public synchronized List getNotableFileHashDatabases() { - List hashDbs = new ArrayList<>(); + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } this.hashSets.stream().filter((db) -> (db.getKnownFilesType() == HashDb.KnownFilesType.KNOWN_BAD)).forEach((db) -> { hashDbs.add(db); }); @@ -529,28 +466,18 @@ public class HashDbManager implements PropertyChangeListener { * * @return A list, possibly empty, of hash databases. */ - @Deprecated public synchronized List getUpdateableHashSets() { - List updateableDbs = new ArrayList<>(); - List updateableHashSets = getUpdateableHashSets(this.hashSets); - updateableHashSets.stream().filter((db) -> (db instanceof HashDb)).forEach((db) -> { - updateableDbs.add((HashDb)db); - }); - return updateableDbs; - } - - /** - * Gets all of the hash databases that accept updates. - * - * @return A list, possibly empty, of hash databases. - */ - public synchronized List getUpdateableHashDatabases(){ return getUpdateableHashSets(this.hashSets); } - private List getUpdateableHashSets(List hashDbs) { - ArrayList updateableDbs = new ArrayList<>(); - for (HashDatabase db : hashDbs) { + private List getUpdateableHashSets(List hashDbs) { + ArrayList updateableDbs = new ArrayList<>(); + try{ + updateHashSetsFromCentralRepository(); + } catch (TskCoreException ex){ + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS + } + for (HashDb db : hashDbs) { try { if (db.isUpdateable()) { updateableDbs.add(db); @@ -572,9 +499,9 @@ public class HashDbManager implements PropertyChangeListener { // Defaults for fields not stored in the central repository: // searchDuringIngest: false // sendIngestMessages: true if the hash set is notable - boolean sendIngestMessages = globalSet.getKnownStatus().equals(HashDb.KnownFilesType.KNOWN_BAD); + boolean sendIngestMessages = convertFileKnown(globalSet.getFileKnownStatus()).equals(HashDb.KnownFilesType.KNOWN_BAD); crHashSets.add(new HashDbInfo(globalSet.getSetName(), globalSet.getVersion(), - globalSet.getGlobalSetID(), globalSet.getKnownStatus(), globalSet.isReadOnly(), false, sendIngestMessages)); + globalSet.getGlobalSetID(), convertFileKnown(globalSet.getFileKnownStatus()), globalSet.isReadOnly(), false, sendIngestMessages)); } } catch (EamDbException ex){ Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading central repository hash sets", ex); //NON-NLS @@ -582,6 +509,13 @@ public class HashDbManager implements PropertyChangeListener { } return crHashSets; } + + private static HashDb.KnownFilesType convertFileKnown(TskData.FileKnown fileKnown){ + if(fileKnown.equals(TskData.FileKnown.BAD)){ + return HashDb.KnownFilesType.KNOWN_BAD; + } + return HashDb.KnownFilesType.KNOWN; + } /** * Restores the last saved hash sets configuration. This supports @@ -595,12 +529,14 @@ public class HashDbManager implements PropertyChangeListener { loadHashsetsConfiguration(); } - private void closeHashDatabases(List hashDatabases) { - for (HashDatabase database : hashDatabases) { - try { - database.close(); - } catch (TskCoreException ex) { - Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash database", ex); //NON-NLS + private void closeHashDatabases(List hashDatabases) { + for (HashDb database : hashDatabases) { + if(database instanceof SleuthkitHashSet){ + try { + ((SleuthkitHashSet)database).close(); + } catch (TskCoreException ex) { + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash database", ex); //NON-NLS + } } } hashDatabases.clear(); @@ -631,7 +567,7 @@ public class HashDbManager implements PropertyChangeListener { if(hashDbInfo.isFileDatabaseType()){ String dbPath = this.getValidFilePath(hashDbInfo.getHashSetName(), hashDbInfo.getPath()); if (dbPath != null) { - addFileTypeHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType()); + addHashDatabase(SleuthkitJNI.openHashDatabase(dbPath), hashDbInfo.getHashSetName(), hashDbInfo.getSearchDuringIngest(), hashDbInfo.getSendIngestMessages(), hashDbInfo.getKnownFilesType()); } else { logger.log(Level.WARNING, Bundle.HashDbManager_noDbPath_message(hashDbInfo.getHashSetName())); allDatabasesLoadedCorrectly = false; @@ -687,7 +623,7 @@ public class HashDbManager implements PropertyChangeListener { } } - void updateHashSetsFromCentralRepository() throws TskCoreException { + private void updateHashSetsFromCentralRepository() throws TskCoreException { if(EamDb.isEnabled()){ List crHashDbInfoList = getCentralRepoHashSetsFromDatabase(); for(HashDbInfo hashDbInfo : crHashDbInfoList) { @@ -702,7 +638,7 @@ public class HashDbManager implements PropertyChangeListener { } private boolean hashDbInfoIsNew(HashDbInfo dbInfo){ - for(HashDatabase db:this.hashSets){ + for(HashDb db:this.hashSets){ if(dbInfo.matches(db)){ return false; } @@ -757,87 +693,8 @@ public class HashDbManager implements PropertyChangeListener { return filePath; } - public static interface HashDatabase { - enum DatabaseType{ - FILE, - CENTRAL_REPOSITORY - }; + public static abstract class HashDb { - public String getHashSetName(); - - public String getDisplayName(); - - public String getDatabasePath() throws TskCoreException; - - public HashDb.KnownFilesType getKnownFilesType(); - - public boolean getSearchDuringIngest(); - - void setSearchDuringIngest(boolean useForIngest); - - public boolean getSendIngestMessages(); - - void setSendIngestMessages(boolean showInboxMessages); - - /** - * Indicates whether the hash database accepts updates. - * - * @return True if the database accepts updates, false otherwise. - * - * @throws org.sleuthkit.datamodel.TskCoreException - */ - public boolean isUpdateable() throws TskCoreException; - - /** - * Adds hashes of content (if calculated) to the hash database. - * - * @param content The content for which the calculated hashes, if any, - * are to be added to the hash database. - * - * @throws TskCoreException - */ - public void addHashes(Content content) throws TskCoreException; - - public void addHashes(Content content, String comment) throws TskCoreException; - - public void addHashes(List hashes) throws TskCoreException; - - public boolean lookupMD5Quick(Content content) throws TskCoreException; - - public HashHitInfo lookupMD5(Content content) throws TskCoreException; - - /** - * Returns whether this database can be enabled. - * For file type, this is the same as checking that it has an index - * @return true if is valid, false otherwise - * @throws TskCoreException - */ - public boolean isValid() throws TskCoreException; - - public int getHandle(); - - public void firePropertyChange(String propertyName, Object oldValue, Object newValue); - - public void addPropertyChangeListener(PropertyChangeListener pcl); - - public void removePropertyChangeListener(PropertyChangeListener pcl); - - void close() throws TskCoreException; - - @Override - public String toString(); - - DatabaseType getDatabaseType(); - - - } - - /** - * Instances of this class represent hash databases used to classify files - * as known or know bad. - */ - public static class HashDb implements HashDatabase{ - /** * Indicates how files with hashes stored in a particular hash database * object should be classified. @@ -864,6 +721,79 @@ public class HashDbManager implements PropertyChangeListener { INDEXING_DONE } + + public abstract String getHashSetName(); + + abstract String getDisplayName(); + + public abstract String getDatabasePath() throws TskCoreException; + + public abstract HashDb.KnownFilesType getKnownFilesType(); + + public abstract boolean getSearchDuringIngest(); + + abstract void setSearchDuringIngest(boolean useForIngest); + + public abstract boolean getSendIngestMessages(); + + abstract void setSendIngestMessages(boolean showInboxMessages); + + /** + * Indicates whether the hash database accepts updates. + * + * @return True if the database accepts updates, false otherwise. + * + * @throws org.sleuthkit.datamodel.TskCoreException + */ + public abstract boolean isUpdateable() throws TskCoreException; + + /** + * Adds hashes of content (if calculated) to the hash database. + * + * @param content The content for which the calculated hashes, if any, + * are to be added to the hash database. + * + * @throws TskCoreException + */ + public abstract void addHashes(Content content) throws TskCoreException; + + public abstract void addHashes(Content content, String comment) throws TskCoreException; + + public abstract void addHashes(List hashes) throws TskCoreException; + + public abstract boolean lookupMD5Quick(Content content) throws TskCoreException; + + public abstract HashHitInfo lookupMD5(Content content) throws TskCoreException; + + /** + * Returns whether this database can be enabled. + * For file type, this is the same as checking that it has an index + * @return true if is valid, false otherwise + * @throws TskCoreException + */ + abstract boolean isValid() throws TskCoreException; + + public abstract String getIndexPath() throws TskCoreException; + + public abstract boolean hasIndexOnly() throws TskCoreException; + + public abstract void firePropertyChange(String propertyName, Object oldValue, Object newValue); + + public abstract void addPropertyChangeListener(PropertyChangeListener pcl); + + public abstract void removePropertyChangeListener(PropertyChangeListener pcl); + + @Override + public abstract String toString(); + + } + + /** + * Instances of this class represent hash databases used to classify files + * as known or know bad. + */ + class SleuthkitHashSet extends HashDb{ + private static final long serialVersionUID = 1L; private final int handle; private final String hashSetName; @@ -873,7 +803,7 @@ public class HashDbManager implements PropertyChangeListener { private boolean indexing; private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); - private HashDb(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) { + private SleuthkitHashSet(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) { this.handle = handle; this.hashSetName = hashSetName; this.searchDuringIngest = useForIngest; @@ -903,8 +833,7 @@ public class HashDbManager implements PropertyChangeListener { propertyChangeSupport.removePropertyChangeListener(pcl); } - @Override - public int getHandle(){ + int getHandle(){ return handle; } @@ -914,7 +843,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public String getDisplayName(){ + String getDisplayName(){ return getHashSetName(); } @@ -926,12 +855,8 @@ public class HashDbManager implements PropertyChangeListener { public void setIndexing(boolean indexing){ this.indexing = indexing; } - - @Override - public DatabaseType getDatabaseType(){ - return DatabaseType.FILE; - } + @Override public String getIndexPath() throws TskCoreException { return SleuthkitJNI.getHashDatabaseIndexPath(handle); } @@ -947,7 +872,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public void setSearchDuringIngest(boolean useForIngest) { + void setSearchDuringIngest(boolean useForIngest) { this.searchDuringIngest = useForIngest; } @@ -957,7 +882,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public void setSendIngestMessages(boolean showInboxMessages) { + void setSendIngestMessages(boolean showInboxMessages) { this.sendIngestMessages = showInboxMessages; } @@ -1072,23 +997,24 @@ public class HashDbManager implements PropertyChangeListener { * @throws TskCoreException */ @Override - public boolean isValid() throws TskCoreException { + boolean isValid() throws TskCoreException { return hasIndex(); } - public boolean hasIndex() throws TskCoreException { + boolean hasIndex() throws TskCoreException { return SleuthkitJNI.hashDatabaseHasLookupIndex(handle); } + @Override public boolean hasIndexOnly() throws TskCoreException { return SleuthkitJNI.hashDatabaseIsIndexOnly(handle); } - public boolean canBeReIndexed() throws TskCoreException { + boolean canBeReIndexed() throws TskCoreException { return SleuthkitJNI.hashDatabaseCanBeReindexed(handle); } - public boolean isIndexing() { + boolean isIndexing() { return indexing; } @@ -1097,8 +1023,7 @@ public class HashDbManager implements PropertyChangeListener { this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } - @Override - public void close() throws TskCoreException { + private void close() throws TskCoreException { SleuthkitJNI.closeHashDatabase(handle); } @@ -1126,7 +1051,7 @@ public class HashDbManager implements PropertyChangeListener { if (getClass() != obj.getClass()) { return false; } - final HashDb other = (HashDb) obj; + final SleuthkitHashSet other = (SleuthkitHashSet) obj; if (!Objects.equals(this.hashSetName, other.hashSetName)) { return false; } @@ -1141,7 +1066,7 @@ public class HashDbManager implements PropertyChangeListener { * Instances of this class represent hash databases used to classify files * as known or know bad. */ - public static class CentralRepoHashDb implements HashDatabase{ + class CentralRepoHashSet extends HashDb{ private static final long serialVersionUID = 1L; private final String hashSetName; @@ -1155,7 +1080,7 @@ public class HashDbManager implements PropertyChangeListener { private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); @Messages({"HashDbManager.CentralRepoHashDb.orgError=Error loading organization"}) - private CentralRepoHashDb(String hashSetName, String version, int referenceSetID, + private CentralRepoHashSet(String hashSetName, String version, int referenceSetID, boolean useForIngest, boolean sendHitMessages, HashDb.KnownFilesType knownFilesType, boolean readOnly) throws TskCoreException{ @@ -1170,7 +1095,7 @@ public class HashDbManager implements PropertyChangeListener { try{ orgName = EamDb.getInstance().getReferenceSetOrganization(referenceSetID).getName(); } catch (EamDbException ex){ - Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error looking up central repository organization", ex); //NON-NLS + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error looking up central repository organization for reference set " + referenceSetID, ex); //NON-NLS orgName = Bundle.HashDbManager_CentralRepoHashDb_orgError(); } } @@ -1197,8 +1122,8 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public int getHandle(){ - return 0; + public boolean hasIndexOnly() throws TskCoreException{ + return true; } @Override @@ -1215,15 +1140,15 @@ public class HashDbManager implements PropertyChangeListener { } } - public String getVersion(){ + String getVersion(){ return version; } - public String getOrgName(){ + String getOrgName(){ return orgName; } - public int getReferenceSetID(){ + int getReferenceSetID(){ return referenceSetID; } @@ -1231,12 +1156,8 @@ public class HashDbManager implements PropertyChangeListener { public String getDatabasePath() throws TskCoreException { return ""; } - - @Override - public DatabaseType getDatabaseType(){ - return DatabaseType.CENTRAL_REPOSITORY; - } + @Override public String getIndexPath() throws TskCoreException { return ""; } @@ -1252,7 +1173,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public void setSearchDuringIngest(boolean useForIngest) { + void setSearchDuringIngest(boolean useForIngest) { this.searchDuringIngest = useForIngest; } @@ -1262,7 +1183,7 @@ public class HashDbManager implements PropertyChangeListener { } @Override - public void setSendIngestMessages(boolean showInboxMessages) { + void setSendIngestMessages(boolean showInboxMessages) { this.sendIngestMessages = showInboxMessages; } @@ -1349,7 +1270,7 @@ public class HashDbManager implements PropertyChangeListener { EamDb.getInstance().bulkInsertReferenceTypeEntries(globalFileInstances, EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); } catch (EamDbException ex){ - throw new TskCoreException("Error adding hashes", ex); + throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex); } } @@ -1370,9 +1291,10 @@ public class HashDbManager implements PropertyChangeListener { AbstractFile file = (AbstractFile) content; if (null != file.getMd5Hash()) { try{ - return EamDb.getInstance().isHashInReferenceSet(file.getMd5Hash(), this.referenceSetID); + return EamDb.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID); } catch (EamDbException ex){ - Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash " + + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); } } @@ -1398,12 +1320,13 @@ public class HashDbManager implements PropertyChangeListener { AbstractFile file = (AbstractFile) content; if (null != file.getMd5Hash()) { try{ - if(EamDb.getInstance().isHashInReferenceSet(file.getMd5Hash(), this.referenceSetID)){ + if(EamDb.getInstance().isFileHashInReferenceSet(file.getMd5Hash(), this.referenceSetID)){ // Make a bare-bones HashHitInfo for now result = new HashHitInfo(file.getMd5Hash(), "", ""); } } catch (EamDbException ex){ - Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup", ex); //NON-NLS + Logger.getLogger(SleuthkitHashSet.class.getName()).log(Level.SEVERE, "Error performing central reposiotry hash lookup for hash " + + file.getMd5Hash() + " in reference set " + referenceSetID, ex); //NON-NLS throw new TskCoreException("Error performing central reposiotry hash lookup", ex); } } @@ -1415,17 +1338,16 @@ public class HashDbManager implements PropertyChangeListener { * Returns whether this database can be enabled. * * @return true if is valid, false otherwise - * @throws TskCoreException */ @Override - public boolean isValid() { + boolean isValid() { if(! EamDb.isEnabled()) { return false; } try{ return EamDb.getInstance().referenceSetIsValid(this.referenceSetID, this.hashSetName, this.version); } catch (EamDbException ex){ - Logger.getLogger(CentralRepoHashDb.class.getName()).log(Level.SEVERE, "Error validating hash database " + hashSetName, ex); //NON-NLS + Logger.getLogger(CentralRepoHashSet.class.getName()).log(Level.SEVERE, "Error validating hash database " + hashSetName, ex); //NON-NLS return false; } } @@ -1434,11 +1356,6 @@ public class HashDbManager implements PropertyChangeListener { public void firePropertyChange(String propertyName, Object oldValue, Object newValue){ this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } - - @Override - public void close() throws TskCoreException { - - } @Override public String toString(){ @@ -1464,7 +1381,7 @@ public class HashDbManager implements PropertyChangeListener { if (getClass() != obj.getClass()) { return false; } - final CentralRepoHashDb other = (CentralRepoHashDb) obj; + final CentralRepoHashSet other = (CentralRepoHashSet) obj; if (!Objects.equals(this.hashSetName, other.hashSetName)) { return false; } @@ -1484,9 +1401,9 @@ public class HashDbManager implements PropertyChangeListener { private class HashDbIndexer extends SwingWorker { private ProgressHandle progress = null; - private HashDb hashDb = null; + private SleuthkitHashSet hashDb = null; - HashDbIndexer(HashDb hashDb) { + HashDbIndexer(SleuthkitHashSet hashDb) { this.hashDb = hashDb; } @@ -1500,7 +1417,7 @@ public class HashDbManager implements PropertyChangeListener { try { SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.getHandle()); } catch (TskCoreException ex) { - Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex); //NON-NLS + Logger.getLogger(HashDbIndexer.class.getName()).log(Level.SEVERE, "Error indexing hash set " + hashDb.getHashSetName(), ex); //NON-NLS JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), "HashDbManager.dlgMsg.errorIndexingHashSet", @@ -1530,7 +1447,7 @@ public class HashDbManager implements PropertyChangeListener { } try { - hashDb.firePropertyChange(HashDb.Event.INDEXING_DONE.toString(), null, hashDb); + hashDb.firePropertyChange(SleuthkitHashSet.Event.INDEXING_DONE.toString(), null, hashDb); hashDb.firePropertyChange(HashDbManager.SetEvt.DB_INDEXED.toString(), null, hashDb.getHashSetName()); } catch (Exception e) { logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java index 19a1d5ee21..2fb515832b 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleFactory.java @@ -60,7 +60,7 @@ public class HashLookupModuleFactory extends IngestModuleFactoryAdapter { @Override public IngestModuleIngestJobSettings getDefaultIngestJobSettings() { // All available hash sets are enabled and always calculate hashes is true by default. - return new HashLookupModuleSettings(true, HashDbManager.getInstance().refreshAndGetAllHashDatabases()); + return new HashLookupModuleSettings(true, HashDbManager.getInstance().getAllHashSets()); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java index 9923c7f21b..04d6d0f143 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java @@ -26,8 +26,8 @@ import java.io.IOException; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettings.HashDbInfo; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Ingest job settings for the hash lookup module. @@ -42,7 +42,7 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { private boolean shouldCalculateHashes = true; private List databaseInfoList; - HashLookupModuleSettings(boolean shouldCalculateHashes, List hashDbList){ + HashLookupModuleSettings(boolean shouldCalculateHashes, List hashDbList){ this.shouldCalculateHashes = shouldCalculateHashes; try{ databaseInfoList = HashLookupSettings.convertHashSetList(hashDbList); @@ -76,12 +76,12 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { * @param disabledHashSets A list of disabled hash sets. */ HashLookupModuleSettings(boolean shouldCalculateHashes, - List enabledHashSets, - List disabledHashSets) { + List enabledHashSets, + List disabledHashSets) { this.shouldCalculateHashes = shouldCalculateHashes; databaseInfoList = new ArrayList<>(); - for(HashDatabase db:enabledHashSets){ + for(HashDb db:enabledHashSets){ try{ HashDbInfo dbInfo = new HashDbInfo(db); dbInfo.setSearchDuringIngest(true); @@ -90,7 +90,7 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { Logger.getLogger(HashLookupModuleSettings.class.getName()).log(Level.SEVERE, "Error creating hash database settings for " + db.getHashSetName(), ex); //NON-NLS } } - for(HashDatabase db:disabledHashSets){ + for(HashDb db:disabledHashSets){ try{ HashDbInfo dbInfo = new HashDbInfo(db); dbInfo.setSearchDuringIngest(false); @@ -128,15 +128,15 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { * * @return True if the hash set is enabled, false otherwise. */ - boolean isHashSetEnabled(HashDatabase db) { + boolean isHashSetEnabled(HashDb db) { for(HashDbInfo dbInfo:databaseInfoList){ if(dbInfo.matches(db)){ return dbInfo.getSearchDuringIngest(); } } - // We didn't find it, so use the default value - return db.getDefaultSearchDuringIngest(); + // We didn't find it, so use whatever default value is in the HashDb object + return db.getSearchDuringIngest(); } /** @@ -150,7 +150,7 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings { } try{ - databaseInfoList = HashLookupSettings.convertHashSetList(HashDbManager.getInstance().getAllHashDatabases()); + databaseInfoList = HashLookupSettings.convertHashSetList(HashDbManager.getInstance().getAllHashSets()); } catch (HashLookupSettings.HashLookupSettingsException ex){ Logger.getLogger(HashLookupModuleSettings.class.getName()).log(Level.SEVERE, "Error updating hash database settings.", ex); //NON-NLS return; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java old mode 100755 new mode 100644 index 1e83fb77c6..63d7a25bfc --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -30,8 +30,8 @@ import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** @@ -53,18 +53,13 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } private void initializeHashSetModels(HashLookupModuleSettings settings) { - try{ - hashDbManager.updateHashSetsFromCentralRepository(); - } catch (TskCoreException ex){ - Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error updating central repository hash sets", ex); //NON-NLS - } - initializeHashSetModels(settings, hashDbManager.getKnownFileHashDatabases(), knownHashSetModels); - initializeHashSetModels(settings, hashDbManager.getNotableFileHashDatabases(), knownBadHashSetModels); + initializeHashSetModels(settings, validSetsOnly(hashDbManager.getKnownFileHashSets()), knownHashSetModels); + initializeHashSetModels(settings, validSetsOnly(hashDbManager.getKnownBadFileHashSets()), knownBadHashSetModels); } - private void initializeHashSetModels(HashLookupModuleSettings settings, List hashDbs, List hashSetModels) { + private void initializeHashSetModels(HashLookupModuleSettings settings, List hashDbs, List hashSetModels) { hashSetModels.clear(); - for (HashDatabase db : hashDbs) { + for (HashDb db : hashDbs) { hashSetModels.add(new HashSetModel(db, settings.isHashSetEnabled(db), isHashDbValid(db))); } } @@ -105,15 +100,15 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe @Override public IngestModuleIngestJobSettings getSettings() { - List enabledHashSets = new ArrayList<>(); - List disabledHashSets = new ArrayList<>(); + List enabledHashSets = new ArrayList<>(); + List disabledHashSets = new ArrayList<>(); addHashSets(knownHashSetModels, enabledHashSets, disabledHashSets); addHashSets(knownBadHashSetModels, enabledHashSets, disabledHashSets); return new HashLookupModuleSettings(alwaysCalcHashesCheckbox.isSelected(), enabledHashSets, disabledHashSets); } - private void addHashSets(List hashSetModels, List enabledHashSets, List disabledHashSets) { + private void addHashSets(List hashSetModels, List enabledHashSets, List disabledHashSets) { for (HashSetModel model : hashSetModels) { if (model.isEnabled() && model.isValid()) { enabledHashSets.add(model.getDatabase()); @@ -130,19 +125,33 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } private void updateHashSetModels() { - updateHashSetModels(hashDbManager.getKnownFileHashDatabases(), knownHashSetModels); - updateHashSetModels(hashDbManager.getNotableFileHashDatabases(), knownBadHashSetModels); + updateHashSetModels(validSetsOnly(hashDbManager.getKnownFileHashSets()), knownHashSetModels); + updateHashSetModels(validSetsOnly(hashDbManager.getKnownBadFileHashSets()), knownBadHashSetModels); + } + + private List validSetsOnly(List hashDbs){ + List validDbs = new ArrayList<>(); + for(HashDb db:hashDbs){ + try{ + if(db.isValid()){ + validDbs.add(db); + } + } catch (TskCoreException ex){ + Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error checking validity for hash set (name = " + db.getHashSetName() + ")", ex); //NON-NLS + } + } + return validDbs; } - void updateHashSetModels(List hashDbs, List hashSetModels) { + void updateHashSetModels(List hashDbs, List hashSetModels) { - List hashDatabases = new ArrayList<>(hashDbs); + List hashDatabases = new ArrayList<>(hashDbs); // Update the hash sets and detect deletions. List deletedHashSetModels = new ArrayList<>(); for (HashSetModel model : hashSetModels) { boolean foundDatabase = false; - for(HashDatabase db : hashDatabases){ + for(HashDb db : hashDatabases){ if(model.getDatabase().equals(db)){ model.setValid(isHashDbValid(db)); hashDatabases.remove(db); @@ -161,7 +170,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } // Add any new hash sets. All new sets are enabled by default. - for (HashDatabase db : hashDatabases) { + for (HashDb db : hashDatabases) { hashSetModels.add(new HashSetModel(db, true, isHashDbValid(db))); } } @@ -173,7 +182,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe knownBadHashSetsTableModel.fireTableDataChanged(); } - private boolean isHashDbValid(HashDatabase hashDb) { + private boolean isHashDbValid(HashDb hashDb) { boolean isValid = false; try { isValid = hashDb.isValid(); @@ -185,17 +194,17 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe private static final class HashSetModel { - private final HashDatabase db; + private final HashDb db; private boolean valid; private boolean enabled; - HashSetModel(HashDatabase db, boolean enabled, boolean valid) { + HashSetModel(HashDb db, boolean enabled, boolean valid) { this.db = db; this.enabled = enabled; this.valid = valid; } - HashDatabase getDatabase(){ + HashDb getDatabase(){ return db; } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java index 89d807d507..948f18451d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettings.java @@ -36,13 +36,13 @@ import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase.DatabaseType; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashSet; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SleuthkitHashSet; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Class to represent the settings to be serialized for hash lookup. @@ -74,9 +74,9 @@ final class HashLookupSettings implements Serializable { this.hashDbInfoList = hashDbInfoList; } - static List convertHashSetList(List hashSets) throws HashLookupSettingsException{ + static List convertHashSetList(List hashSets) throws HashLookupSettingsException{ List dbInfoList = new ArrayList<>(); - for(HashDbManager.HashDatabase db:hashSets){ + for(HashDbManager.HashDb db:hashSets){ try{ dbInfoList.add(new HashDbInfo(db)); } catch (TskCoreException ex){ @@ -297,6 +297,11 @@ final class HashLookupSettings implements Serializable { */ static final class HashDbInfo implements Serializable { + enum DatabaseType{ + FILE, + CENTRAL_REPOSITORY + }; + private static final long serialVersionUID = 1L; private final String hashSetName; private final HashDbManager.HashDb.KnownFilesType knownFilesType; @@ -342,9 +347,9 @@ final class HashLookupSettings implements Serializable { dbType = DatabaseType.CENTRAL_REPOSITORY; } - HashDbInfo(HashDbManager.HashDatabase db) throws TskCoreException{ - if(db instanceof HashDbManager.HashDb){ - HashDbManager.HashDb fileTypeDb = (HashDbManager.HashDb)db; + HashDbInfo(HashDbManager.HashDb db) throws TskCoreException{ + if(db instanceof HashDbManager.SleuthkitHashSet){ + HashDbManager.SleuthkitHashSet fileTypeDb = (HashDbManager.SleuthkitHashSet)db; this.hashSetName = fileTypeDb.getHashSetName(); this.knownFilesType = fileTypeDb.getKnownFilesType(); this.searchDuringIngest = fileTypeDb.getSearchDuringIngest(); @@ -359,7 +364,7 @@ final class HashLookupSettings implements Serializable { this.path = fileTypeDb.getDatabasePath(); } } else { - HashDbManager.CentralRepoHashDb centralRepoDb = (HashDbManager.CentralRepoHashDb)db; + HashDbManager.CentralRepoHashSet centralRepoDb = (HashDbManager.CentralRepoHashSet)db; this.hashSetName = centralRepoDb.getHashSetName(); this.version = centralRepoDb.getVersion(); this.knownFilesType = centralRepoDb.getKnownFilesType(); @@ -457,7 +462,7 @@ final class HashLookupSettings implements Serializable { return dbType == DatabaseType.CENTRAL_REPOSITORY; } - boolean matches(HashDatabase hashDb){ + boolean matches(HashDb hashDb){ if(hashDb == null){ return false; } @@ -466,7 +471,8 @@ final class HashLookupSettings implements Serializable { return false; } - if( ! this.dbType.equals(hashDb.getDatabaseType())){ + if((this.dbType == DatabaseType.CENTRAL_REPOSITORY) && (! (hashDb instanceof CentralRepoHashSet)) + || (this.dbType == DatabaseType.FILE) && (! (hashDb instanceof SleuthkitHashSet))){ return false; } @@ -474,19 +480,15 @@ final class HashLookupSettings implements Serializable { return false; } - if(this.dbType.equals(DatabaseType.FILE)){ - // FILE types will always have unique names, so no more testing required - return true; - } - - // Central repo tests - CentralRepoHashDb crDb = (CentralRepoHashDb) hashDb; - if(this.referenceSetID != crDb.getReferenceSetID()){ - return false; - } - - if(! version.equals(crDb.getVersion())){ - return false; + if(hashDb instanceof CentralRepoHashSet){ + CentralRepoHashSet crDb = (CentralRepoHashSet) hashDb; + if(this.referenceSetID != crDb.getReferenceSetID()){ + return false; + } + + if(! version.equals(crDb.getVersion())){ + return false; + } } return true; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java old mode 100755 new mode 100644 index 4b40c60386..84be7d7142 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -45,11 +45,11 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SleuthkitHashSet; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashSet; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; /** * Instances of this class provide a comprehensive UI for managing the hash sets @@ -65,7 +65,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan .getMessage(HashLookupSettingsPanel.class, "HashDbConfigPanel.errorGettingIndexStatusText"); private final HashDbManager hashSetManager = HashDbManager.getInstance(); private final HashSetTableModel hashSetTableModel = new HashSetTableModel(); - private final List newReferenceSets = new ArrayList<>(); + private final List newReferenceSetIDs = new ArrayList<>(); public HashLookupSettingsPanel() { initComponents(); @@ -108,7 +108,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } private void updateComponents() { - HashDatabase db = ((HashSetTable) hashSetTable).getSelection(); + HashDb db = ((HashSetTable) hashSetTable).getSelection(); if (db != null) { updateComponentsForSelection(db); } else { @@ -157,7 +157,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan "HashLookupSettingsPanel.notApplicable=N/A", "HashLookupSettingsPanel.centralRepo=Central Repository" }) - private void updateComponentsForSelection(HashDatabase db) { + private void updateComponentsForSelection(HashDb db) { boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); // Update descriptive labels. @@ -180,8 +180,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan addHashesToDatabaseButton.setEnabled(false); } - if(db instanceof HashDb){ - HashDb hashDb = (HashDb)db; + if(db instanceof SleuthkitHashSet){ + SleuthkitHashSet hashDb = (SleuthkitHashSet)db; // Disable the central repo fields hashDbVersionLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); @@ -253,7 +253,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan indexButton.setEnabled(false); deleteDatabaseButton.setEnabled(false); - CentralRepoHashDb crDb = (CentralRepoHashDb)db; + CentralRepoHashSet crDb = (CentralRepoHashSet)db; hashDbVersionLabel.setText(crDb.getVersion()); hashDbOrgLabel.setText(crDb.getOrgName()); @@ -302,15 +302,19 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan @Override @Messages({"HashLookupSettingsPanel.saveFail.message=Couldn't save hash db settings.", "HashLookupSettingsPanel.saveFail.title=Save Fail"}) - public void saveSettings() { + public void saveSettings() { + // Clear out the list of new central repo hash sets. They don't need to be + // indexed so will all be saved on both code paths. + newReferenceSetIDs.clear(); + //Checking for for any unindexed databases - List unindexed = new ArrayList<>(); - for (HashDatabase hashSet : hashSetManager.getAllHashDatabases()) { - if(hashSet instanceof HashDb){ - HashDb db = (HashDb)hashSet; + List unindexed = new ArrayList<>(); + for (HashDb db : hashSetManager.getAllHashSets()) { + if(db instanceof SleuthkitHashSet){ try { - if (!db.hasIndex()) { - unindexed.add(db); + SleuthkitHashSet hashDatabase = (SleuthkitHashSet)db; + if (!hashDatabase.hasIndex()) { + unindexed.add(hashDatabase); } } catch (TskCoreException ex) { Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); //NON-NLS @@ -318,21 +322,28 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } } - //If unindexed ones are found, show a popup box that will either index them, or remove them. - if (unindexed.size() == 1) { - showInvalidIndex(false, unindexed); - } else if (unindexed.size() > 1) { - showInvalidIndex(true, unindexed); - } - - try { - hashSetManager.save(); - HashDbManager.getInstance().saveNewCentralRepoDatabases(newReferenceSets); - newReferenceSets.clear(); - } catch (HashDbManager.HashDbManagerException ex) { - SwingUtilities.invokeLater(() -> { - JOptionPane.showMessageDialog(null, Bundle.HashLookupSettingsPanel_saveFail_message(), Bundle.HashLookupSettingsPanel_saveFail_title(), JOptionPane.ERROR_MESSAGE); + // If there are unindexed databases, give the user the option to index them now. This + // needs to be on the EDT, and will save the hash settings after completing + if(! unindexed.isEmpty()){ + SwingUtilities.invokeLater(new Runnable(){ + @Override + public void run(){ + //If unindexed ones are found, show a popup box that will either index them, or remove them. + if (unindexed.size() == 1) { + showInvalidIndex(false, unindexed); + } else if (unindexed.size() > 1) { + showInvalidIndex(true, unindexed); + } + } }); + } else { + try { + hashSetManager.save(); + } catch (HashDbManager.HashDbManagerException ex) { + SwingUtilities.invokeLater(() -> { + JOptionPane.showMessageDialog(null, Bundle.HashLookupSettingsPanel_saveFail_message(), Bundle.HashLookupSettingsPanel_saveFail_title(), JOptionPane.ERROR_MESSAGE); + }); + } } } @@ -355,10 +366,10 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan */ if (IngestManager.getInstance().isIngestRunning() == false) { // Remove any new central repo hash sets from the database - for(CentralRepoHashDb db:newReferenceSets){ + for(Integer referenceSetID:newReferenceSetIDs){ try{ if(EamDb.isEnabled()){ - EamDb.getInstance().deleteReferenceSet(db.getReferenceSetID()); + EamDb.getInstance().deleteReferenceSet(referenceSetID); } else { // This is the case where the user imported a database, then switched over to the central // repo panel and disabled it before cancelling. We can't delete the database at this point. @@ -368,15 +379,15 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error reverting central repository hash sets", ex); //NON-NLS } } - newReferenceSets.clear(); + newReferenceSetIDs.clear(); HashDbManager.getInstance().loadLastSavedConfiguration(); } } @Messages({"# {0} - hash lookup name", "HashLookupSettingsPanel.removeDatabaseFailure.message=Failed to remove hash lookup: {0}"}) - void removeThese(List toRemove) { - for (HashDb hashDb : toRemove) { + void removeThese(List toRemove) { + for (SleuthkitHashSet hashDb : toRemove) { try { hashSetManager.removeHashDatabaseNoSave(hashDb); } catch (HashDbManager.HashDbManagerException ex) { @@ -394,10 +405,10 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan * @param plural Whether or not there are multiple unindexed databases * @param unindexed The list of unindexed databases. Can be of size 1. */ - private void showInvalidIndex(boolean plural, List unindexed) { + private void showInvalidIndex(boolean plural, List unindexed) { String total = ""; String message; - for (HashDatabase hdb : unindexed) { + for (HashDb hdb : unindexed) { total += "\n" + hdb.getHashSetName(); } if (plural) { @@ -421,6 +432,11 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan "HashDbConfigPanel.allUnindexedDbsRmFromListMsg")); removeThese(unindexed); } + try { + hashSetManager.save(); + } catch (HashDbManager.HashDbManagerException ex) { + JOptionPane.showMessageDialog(null, Bundle.HashLookupSettingsPanel_saveFail_message(), Bundle.HashLookupSettingsPanel_saveFail_title(), JOptionPane.ERROR_MESSAGE); + } } boolean valid() { @@ -450,7 +466,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan return cellRenderer; } - public HashDatabase getSelection() { + public HashDb getSelection() { return hashSetTableModel.getHashSetAt(getSelectionModel().getMinSelectionIndex()); } @@ -460,7 +476,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } } - public void selectRowByDatabase(HashDatabase db){ + public void selectRowByDatabase(HashDb db){ setSelection(hashSetTableModel.getIndexByDatabase(db)); } @@ -476,7 +492,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan */ private class HashSetTableModel extends AbstractTableModel { - List hashSets = HashDbManager.getInstance().getAllHashDatabases(); + List hashSets = HashDbManager.getInstance().getAllHashSets(); @Override public int getColumnCount() { @@ -523,7 +539,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan return getValueAt(0, c).getClass(); } - HashDatabase getHashSetAt(int index) { + HashDb getHashSetAt(int index) { if (!hashSets.isEmpty() && index >= 0 && index < hashSets.size()) { return hashSets.get(index); } else { @@ -531,7 +547,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } } - int getIndexByDatabase(HashDatabase db){ + int getIndexByDatabase(HashDb db){ for (int i = 0; i < hashSets.size(); ++i) { if (hashSets.get(i).equals(db)) { return i; @@ -551,7 +567,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } void refreshModel() { - hashSets = HashDbManager.getInstance().refreshAndGetAllHashDatabases(); + hashSets = HashDbManager.getInstance().getAllHashSets(); refreshDisplay(); } @@ -915,16 +931,16 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private void addHashesToDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addHashesToDatabaseButtonActionPerformed - HashDatabase hashDb = ((HashSetTable) hashSetTable).getSelection(); + HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); AddHashValuesToDatabaseDialog dialog = new AddHashValuesToDatabaseDialog(hashDb); }//GEN-LAST:event_addHashesToDatabaseButtonActionPerformed private void createDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createDatabaseButtonActionPerformed - HashDatabase hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); + HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); if (null != hashDb) { - if(hashDb instanceof CentralRepoHashDb){ - CentralRepoHashDb crDb = (CentralRepoHashDb)hashDb; - newReferenceSets.add(crDb); + if(hashDb instanceof CentralRepoHashSet){ + int newDbIndex = ((CentralRepoHashSet)hashDb).getReferenceSetID(); + newReferenceSetIDs.add(newDbIndex); } hashSetTableModel.refreshModel(); @@ -934,7 +950,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan }//GEN-LAST:event_createDatabaseButtonActionPerformed private void sendIngestMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendIngestMessagesCheckBoxActionPerformed - HashDatabase hashDb = ((HashSetTable) hashSetTable).getSelection(); + HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); if (hashDb != null) { hashDb.setSendIngestMessages(sendIngestMessagesCheckBox.isSelected()); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); @@ -942,18 +958,18 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan }//GEN-LAST:event_sendIngestMessagesCheckBoxActionPerformed private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed - final HashDatabase hashDatabase = ((HashSetTable) hashSetTable).getSelection(); + final HashDb hashDatabase = ((HashSetTable) hashSetTable).getSelection(); assert hashDatabase != null; - assert hashDatabase instanceof HashDb; + assert hashDatabase instanceof SleuthkitHashSet; // Add a listener for the INDEXING_DONE event. This listener will update // the UI. - HashDb hashDb = (HashDb)hashDatabase; + SleuthkitHashSet hashDb = (SleuthkitHashSet)hashDatabase; hashDb.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { - HashDatabase selectedHashDb = ((HashSetTable) hashSetTable).getSelection(); + if (evt.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.toString())) { + HashDb selectedHashDb = ((HashSetTable) hashSetTable).getSelection(); if (selectedHashDb != null && hashDb != null && hashDb.equals(selectedHashDb)) { updateComponents(); } @@ -974,11 +990,11 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan }//GEN-LAST:event_indexButtonActionPerformed private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed - HashDatabase hashDb = new HashDbImportDatabaseDialog().getHashDatabase(); + HashDb hashDb = new HashDbImportDatabaseDialog().getHashDatabase(); if (null != hashDb) { - if(hashDb instanceof CentralRepoHashDb){ - CentralRepoHashDb crDb = (CentralRepoHashDb)hashDb; - newReferenceSets.add(crDb); + if(hashDb instanceof CentralRepoHashSet){ + int newReferenceSetID = ((CentralRepoHashSet)hashDb).getReferenceSetID(); + newReferenceSetIDs.add(newReferenceSetID); } hashSetTableModel.refreshModel(); @@ -995,7 +1011,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.deleteDbActionMsg"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { - HashDatabase hashDb = ((HashSetTable) hashSetTable).getSelection(); + HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); if (hashDb != null) { try { hashSetManager.removeHashDatabaseNoSave(hashDb); @@ -1010,7 +1026,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed if (evt.getKeyCode() == KeyEvent.VK_DELETE) { - HashDatabase hashDb = ((HashSetTable) hashSetTable).getSelection(); + HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); if (hashDb != null) { try { hashSetManager.removeHashDatabaseNoSave(hashDb); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index 397b4948cf..880feabcb7 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalFileInstance; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -92,7 +93,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P this.setVisible(true); } - HashDbManager.HashDatabase getDatabase(){ + HashDbManager.HashDb getDatabase(){ if(worker != null){ return worker.getDatabase(); } @@ -128,7 +129,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P void addPropertyChangeListener(PropertyChangeListener dialog); int getProgressPercentage(); long getLinesProcessed(); - HashDbManager.HashDatabase getDatabase(); + HashDbManager.HashDb getDatabase(); } class ImportIDXWorker extends SwingWorker implements CentralRepoImportWorker{ @@ -144,7 +145,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P private final File importFile; private final long totalLines; private int referenceSetID = -1; - private HashDbManager.CentralRepoHashDb newHashDb = null; + private HashDbManager.CentralRepoHashSet newHashDb = null; private final AtomicLong numLines = new AtomicLong(); ImportIDXWorker(String hashSetName, String version, int orgId, @@ -176,7 +177,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P } @Override - public HashDbManager.HashDatabase getDatabase(){ + public HashDbManager.HashDb getDatabase(){ return newHashDb; } @@ -201,7 +202,7 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P } // Create an empty hashset in the central repository - referenceSetID = EamDb.getInstance().newReferenceSet(orgId, hashSetName, version, knownStatus, readOnly); + referenceSetID = EamDb.getInstance().newReferenceSet(new EamGlobalSet(orgId, hashSetName, version, knownStatus, readOnly)); EamDb dbManager = EamDb.getInstance(); CorrelationAttribute.Type contentType = dbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); // get "FILES" type diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java index 33f65488d2..41a9fe4fe8 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ModalNoButtons.java @@ -26,7 +26,7 @@ import java.util.List; import javax.swing.JOptionPane; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SleuthkitHashSet; /** * This class exists as a stop-gap measure to force users to have an indexed @@ -43,8 +43,8 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; */ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListener { - List unindexed; - HashDb toIndex; + List unindexed; + SleuthkitHashSet toIndex; HashLookupSettingsPanel hdbmp; int length = 0; int currentcount = 1; @@ -58,7 +58,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed the list of unindexed databases to index. */ - ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, List unindexed) { + ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, List unindexed) { super(parent, NbBundle.getMessage(ModalNoButtons.class, "ModalNoButtons.indexingDbsTitle"), true); this.unindexed = unindexed; this.toIndex = null; @@ -75,7 +75,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed The unindexed database to index. */ - ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, HashDb unindexed) { + ModalNoButtons(HashLookupSettingsPanel hdbmp, java.awt.Frame parent, SleuthkitHashSet unindexed) { super(parent, NbBundle.getMessage(ModalNoButtons.class, "ModalNoButtons.indexingDbTitle"), true); this.unindexed = null; this.toIndex = unindexed; @@ -183,7 +183,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen "ModalNoButtons.dlgTitle.unfinishedIndexing"), JOptionPane.YES_NO_OPTION); if (res == JOptionPane.YES_OPTION) { - List remove = new ArrayList<>(); + List remove = new ArrayList<>(); if (this.toIndex == null) { remove = this.unindexed; } else { @@ -230,7 +230,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen private void indexThese() { length = this.unindexed.size(); this.INDEXING_PROGBAR.setIndeterminate(true); - for (HashDb db : this.unindexed) { + for (SleuthkitHashSet db : this.unindexed) { currentDb = db.getHashSetName(); this.CURRENTDB_LABEL.setText("(" + currentDb + ")"); this.CURRENTLYON_LABEL.setText( @@ -255,7 +255,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * this dialog if all indexing is complete. */ public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.name())) { + if (evt.getPropertyName().equals(SleuthkitHashSet.Event.INDEXING_DONE.name())) { if (currentcount >= length) { this.INDEXING_PROGBAR.setValue(100); this.setModal(false); diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java index 233aad0202..1de1db7eaa 100755 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java @@ -27,6 +27,7 @@ import javax.swing.JPanel; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.report.GeneralReportModule; import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.datamodel.AbstractFile; @@ -34,7 +35,6 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; /** * Instances of this class plug in to the reporting infrastructure to provide a @@ -69,7 +69,7 @@ public class AddTaggedHashesToHashDb implements GeneralReportModule { progressPanel.start(); progressPanel.updateStatusLabel("Adding hashes..."); - HashDatabase hashSet = configPanel.getSelectedHashDatabase(); + HashDb hashSet = configPanel.getSelectedHashDatabase(); if (hashSet != null) { progressPanel.updateStatusLabel("Adding hashes to " + hashSet.getHashSetName() + " hash set..."); diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form index 20cec74d82..dfe9ba921e 100755 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.form @@ -124,7 +124,7 @@
- + diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java index 9c1875eeb2..4dd665b890 100644 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java @@ -35,11 +35,11 @@ import javax.swing.ListModel; import javax.swing.event.ListDataListener; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDatabase; /** * Instances of this class are used to configure the report module plug in that @@ -52,7 +52,7 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { private final Map tagNameSelections = new LinkedHashMap<>(); private final TagNamesListModel tagsNamesListModel = new TagNamesListModel(); private final TagsNamesListCellRenderer tagsNamesRenderer = new TagsNamesListCellRenderer(); - private HashDatabase selectedHashSet = null; + private HashDb selectedHashSet = null; AddTaggedHashesToHashDbConfigPanel() { initComponents(); @@ -107,9 +107,9 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // Get the updateable hash databases and add their hash set names to the // JComboBox component. - List updateableHashSets = HashDbManager.getInstance().getUpdateableHashDatabases(); + List updateableHashSets = HashDbManager.getInstance().getUpdateableHashSets(); if (!updateableHashSets.isEmpty()) { - for (HashDatabase hashDb : updateableHashSets) { + for (HashDb hashDb : updateableHashSets) { hashSetsComboBox.addItem(hashDb); } hashSetsComboBox.setEnabled(true); @@ -138,7 +138,7 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { * * @return A HashDb object representing the database or null. */ - HashDatabase getSelectedHashDatabase() { + HashDb getSelectedHashDatabase() { return selectedHashSet; } @@ -286,7 +286,7 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { }//GEN-LAST:event_selectAllButtonActionPerformed private void hashSetsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashSetsComboBoxActionPerformed - selectedHashSet = (HashDatabase)hashSetsComboBox.getSelectedItem(); + selectedHashSet = (HashDb)hashSetsComboBox.getSelectedItem(); }//GEN-LAST:event_hashSetsComboBoxActionPerformed private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed @@ -311,7 +311,7 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton configureHashDatabasesButton; private javax.swing.JButton deselectAllButton; - private javax.swing.JComboBox hashSetsComboBox; + private javax.swing.JComboBox hashSetsComboBox; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane1; diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java new file mode 100755 index 0000000000..843e9e53fa --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java @@ -0,0 +1,71 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ingest; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import junit.framework.TestCase; +import org.netbeans.junit.NbModuleSuite; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.casemodule.CaseDetails; +import junit.framework.Test; +import org.apache.commons.io.FileUtils; +import org.openide.util.Exceptions; + +public class IngestFileFiltersTest extends TestCase { + + private static final Path caseDirectoryPath = Paths.get(System.getProperty("java.io.tmpdir"), "IngestFileFiltersTest"); + private static final File CASE_DIR = new File(caseDirectoryPath.toString()); + + public static Test suite() { + NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestFileFiltersTest.class). + clusters(".*"). + enableModules(".*"); + return conf.suite(); + } + + @Override + public void setUp() { + try { + Case.createAsCurrentCase(Case.CaseType.SINGLE_USER_CASE, caseDirectoryPath.toString(), new CaseDetails("IngestFiltersTest")); + } catch (CaseActionException ex) { + Exceptions.printStackTrace(ex); + } + assertTrue(CASE_DIR.exists()); + } + + @Override + public void tearDown() { + try { + Case.closeCurrentCase(); + FileUtils.deleteDirectory(CASE_DIR); + + } catch (CaseActionException | IOException ex) { + Exceptions.printStackTrace(ex); + } + assertFalse(CASE_DIR.exists()); + } + + public void testFilter() { + System.out.println("testFilter"); + } +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java new file mode 100755 index 0000000000..cfa9f3dc59 --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspCallback.java @@ -0,0 +1,109 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.testutils; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import org.sleuthkit.datamodel.Content; + +/** + * A data source processor "callback" for unit testing that collects the results + * of running a data source processor on a data source and unblocks the job + * processing thread when the data source processor finishes running in its own + * thread. + */ +@Immutable +public class FunctionalTestDspCallback extends DataSourceProcessorCallback { + + private final Object monitor; + private final List errorMessages = new ArrayList<>(); + private final List dataSourceContent = new ArrayList<>(); + + /** + * Constructs a data source processor "callback" for unit testing that + * collects the results of running a data source processor on a data source + * and unblocks the job processing thread when the data source processor + * finishes running in its own thread. + * + * @param monitor A monitor for the callback to signal when the data source + * processor completes its processing. + */ + FunctionalTestDspCallback(Object monitor) { + this.monitor = monitor; + } + + /** + * Called by the data source processor when it finishes running in its own + * thread. + * + * @param result The result code for the processing of the data + * source. + * @param errorMessages Any error messages generated during the + * processing of the data source. + * @param dataSourceContent The content produced by processing the data + * source. + */ + @Override + public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { + this.errorMessages.addAll(errorMessages); + this.dataSourceContent.addAll(dataSourceContent); + synchronized (monitor) { + monitor.notify(); + } + } + + /** + * Called by the data source processor when it finishes running in its own + * thread, if that thread is the AWT (Abstract Window Toolkit) event + * dispatch thread (EDT). + * + * @param result The result code for the processing of the data + * source. + * @param errorMessages Any error messages generated during the + * processing of the data source. + * @param dataSourceContent The content produced by processing the data + * source. + */ + @Override + public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { + done(result, errorMessages, dataSourceContent); + } + + /** + * Gets any error messages emitted by the data source processor. + * + * @return A list of error messages, possibly empty. + */ + public List getDspErrorMessages() { + return new ArrayList<>(this.errorMessages); + } + + /** + * Gets any data source content objects produced by the data source + * processor. + * + * @return A list of content objects, possibly empty. + */ + public List getDataSourceContent() { + return new ArrayList<>(this.dataSourceContent); + } + +} diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java new file mode 100755 index 0000000000..03d26eb9b2 --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/FunctionalTestDspProgressMonitor.java @@ -0,0 +1,62 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.testutils; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; + +/** + * A data source processor progress monitor for unit testing. + */ +@Immutable +public class FunctionalTestDspProgressMonitor implements DataSourceProcessorProgressMonitor { + + /** + * Switches the progress indicator to indeterminate mode (the total number + * of work units to be completed is unknown) or determinate mode (the total + * number of work units to be completed is unknown). + * + * @param indeterminate True for indeterminate mode, false for determinate + * mode. + */ + @Override + public void setIndeterminate(final boolean indeterminate) { + } + + /** + * Updates the progress indicator with the number of work units completed so + * far when in determinate mode (the total number of work units to be + * completed is known). + * + * @param workUnitsCompleted Number of work units completed so far. + */ + @Override + public void setProgress(final int workUnitsCompleted) { + } + + /** + * Updates the progress indicator with a progress message. + * + * @param message The progress message. + */ + @Override + public void setProgressText(final String message) { + } + +} diff --git a/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IntestFileFiltersTest.java b/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java similarity index 94% rename from Core/test/unit/src/org/sleuthkit/autopsy/ingest/IntestFileFiltersTest.java rename to Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java index b952462de8..29618e30ec 100755 --- a/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IntestFileFiltersTest.java +++ b/Core/test/unit/src/org/sleuthkit/autopsy/ingest/IngestFileFiltersTest.java @@ -23,9 +23,9 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -public class IntestFileFiltersTest { +public class IngestFileFiltersTest { - public IntestFileFiltersTest() { + public IngestFileFiltersTest() { } @BeforeClass diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 3bc76e61fd..ffe121cb7d 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -18,21 +18,34 @@ */ 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.Collection; +import java.util.Collections; +import java.util.Iterator; import java.util.List; +import java.util.UUID; import java.util.logging.Level; +import java.util.stream.Collectors; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; +import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.LocalDiskDSProcessor; +import org.sleuthkit.autopsy.casemodule.LocalFilesDSProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import static org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; import org.sleuthkit.datamodel.Content; /* - * A runnable that adds an archive data source as well as data sources - * contained in the archive to the case database. + * A runnable that adds an archive data source as well as data sources contained + * in the archive to the case database. */ class AddArchiveTask implements Runnable { @@ -42,6 +55,7 @@ class AddArchiveTask implements Runnable { private final DataSourceProcessorProgressMonitor progressMonitor; private final DataSourceProcessorCallback callback; private boolean criticalErrorOccurred; + private final Object archiveDspLock; private static final String ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR = "Archive Extractor"; @@ -49,19 +63,20 @@ class AddArchiveTask implements Runnable { * Constructs a runnable task that adds an archive as well as data sources * contained in the archive to the case database. * - * @param deviceId An ASCII-printable identifier for the device associated - * with the data source that is intended to be unique across multiple cases - * (e.g., a UUID). - * @param archivePath Path to the archive file. + * @param deviceId An ASCII-printable identifier for the device + * associated with the data source that is intended + * to be unique across multiple cases (e.g., a UUID). + * @param archivePath Path to the archive file. * @param progressMonitor Progress monitor to report progress during - * processing. - * @param callback Callback to call when processing is done. + * processing. + * @param callback Callback to call when processing is done. */ AddArchiveTask(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { this.deviceId = deviceId; this.archivePath = archivePath; this.callback = callback; this.progressMonitor = progressMonitor; + this.archiveDspLock = new Object(); } /** @@ -69,39 +84,172 @@ class AddArchiveTask implements Runnable { */ @Override public void run() { + progressMonitor.setIndeterminate(true); List errorMessages = new ArrayList<>(); List newDataSources = new ArrayList<>(); DataSourceProcessorCallback.DataSourceProcessorResult result; if (!ArchiveUtil.isArchive(Paths.get(archivePath))) { criticalErrorOccurred = true; logger.log(Level.SEVERE, String.format("Input data source is not a valid datasource: %s", archivePath)); //NON-NLS - errorMessages.add("Input data source is not a valid datasource: " + archivePath); + errorMessages.add("Input data source is not a valid datasource: " + archivePath); result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; callback.done(result, errorMessages, newDataSources); } + logger.log(Level.INFO, "Using Archive Extractor DSP to process archive {0} ", archivePath); + // extract the archive and pass the extracted folder as input - Path destinationFolder = Paths.get(""); try { Case currentCase = Case.getCurrentCase(); - // get file name without full path or extension - String dataSourceFileNameNoExt = FilenameUtils.getBaseName(archivePath); - // create folder to extract archive to - destinationFolder = Paths.get(currentCase.getModuleDirectory(), ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR, dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); - destinationFolder.toFile().mkdirs(); + Path destinationFolder = createDirectoryForFile(archivePath, currentCase.getModuleDirectory()); + if (destinationFolder.toString().isEmpty()) { + // unable to create directory + criticalErrorOccurred = true; + errorMessages.add(String.format("Unable to create directory {0} to extract archive {1} ", new Object[]{destinationFolder.toString(), archivePath})); + logger.log(Level.SEVERE, String.format("Unable to create directory {0} to extract archive {1} ", new Object[]{destinationFolder.toString(), archivePath})); + return; + } - // extract contents of ZIP archive into destination folder - //ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); + // extract contents of ZIP archive into destination folder + progressMonitor.setProgressText(String.format("Extracting archive contents to: %s", destinationFolder.toString())); + List extractedFiles = ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); + int numExtractedFilesRemaining = extractedFiles.size(); + + // lookup all AutomatedIngestDataSourceProcessors so that we only do it once. + // LocalDisk, LocalFiles, and ArchiveDSP are removed from the list. + List processorCandidates = getListOfValidDataSourceProcessors(); // do processing - + for (String file : extractedFiles) { + + // we only care about files, skip directories + File fileObject = new File(file); + if (fileObject.isDirectory()) { + numExtractedFilesRemaining--; + continue; + } + + // identify all "valid" DSPs that can process this file + List validDataSourceProcessors = getDataSourceProcessorsForFile(Paths.get(file), errorMessages, processorCandidates); + if (validDataSourceProcessors.isEmpty()) { + continue; + } + + // identified a "valid" data source within the archive + progressMonitor.setProgressText(String.format("Adding: %s", file)); + + /* + * NOTE: we have to move the valid data sources to a separate + * folder and then add the data source from that folder. This is + * necessary because after all valid data sources have been + * identified, we are going to add the remaining extracted + * contents of the archive as a single logical file set. Hence, + * if we do not move the data sources out of the extracted + * contents folder, those data source files will get added twice + * and can potentially result in duplicate keyword hits. + */ + Path newFolder = createDirectoryForFile(file, currentCase.getModuleDirectory()); + if (newFolder.toString().isEmpty()) { + // unable to create directory + criticalErrorOccurred = true; + errorMessages.add(String.format("Unable to create directory {0} to extract content of archive {1} ", new Object[]{newFolder.toString(), archivePath})); + logger.log(Level.SEVERE, String.format("Unable to create directory {0} to extract content of archive {1} ", new Object[]{newFolder.toString(), archivePath})); + return; + } + + // Copy it to a different folder + FileUtils.copyFileToDirectory(fileObject, newFolder.toFile()); + Path newFilePath = Paths.get(newFolder.toString(), FilenameUtils.getName(file)); + + // Try each DSP in decreasing order of confidence + boolean success = false; + for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { + + logger.log(Level.INFO, "Using {0} to process extracted file {1} ", new Object[]{selectedProcessor.getDataSourceType(), file}); + synchronized (archiveDspLock) { + try { + UUID taskId = UUID.randomUUID(); + currentCase.notifyAddingDataSource(taskId); + AutoIngestDataSource internalDataSource = new AutoIngestDataSource(deviceId, newFilePath); + DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); + selectedProcessor.process(deviceId, newFilePath, progressMonitor, internalArchiveDspCallBack); + archiveDspLock.wait(); + + // at this point we got the content object(s) from the current DSP. + // check whether the data source was processed successfully + if ((internalDataSource.getResultDataSourceProcessorResultCode() == CRITICAL_ERRORS) + || internalDataSource.getContent().isEmpty()) { + // move onto the the next DSP that can process this data source + continue; + } + + // if we are here it means the data source was addedd successfully + success = true; + newDataSources.addAll(internalDataSource.getContent()); + + // skip all other DSPs for this data source + break; + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { + // Log that the current DSP failed and set the error flag. We consider it an error + // if a DSP fails even if a later one succeeds since we expected to be able to process + // the data source which each DSP on the list. + criticalErrorOccurred = true; + errorMessages.add(ex.getMessage()); + logger.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{newFilePath.toString(), selectedProcessor.getDataSourceType()}); + } + } + } + + if (success) { + // one of the DSPs successfully processed the data source. delete the + // copy of the data source in the original extracted archive folder. + // otherwise the data source is going to be added again as a logical file. + numExtractedFilesRemaining--; + FileUtils.deleteQuietly(fileObject); + } else { + // none of the DSPs were able to process the data source. delete the + // copy of the data source in the temporary folder. the data source is + // going to be added as a logical file with the rest of the extracted contents. + FileUtils.deleteQuietly(newFolder.toFile()); + } + } + + // after all archive contents have been examined (and moved to separate folders if necessary), + // add remaining extracted contents as one logical file set + if (numExtractedFilesRemaining > 0) { + progressMonitor.setProgressText(String.format("Adding: %s", destinationFolder.toString())); + logger.log(Level.INFO, "Adding directory {0} as logical file set", destinationFolder.toString()); + synchronized (archiveDspLock) { + UUID taskId = UUID.randomUUID(); + currentCase.notifyAddingDataSource(taskId); + AutoIngestDataSource internalDataSource = new AutoIngestDataSource(deviceId, destinationFolder); + DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock); + + // folder where archive was extracted to + List pathsList = new ArrayList<>(); + pathsList.add(destinationFolder.toString()); + + // use archive file name as the name of the logical file set + String archiveFileName = FilenameUtils.getName(archivePath); + + LocalFilesDSProcessor localFilesDSP = new LocalFilesDSProcessor(); + localFilesDSP.run(deviceId, archiveFileName, pathsList, progressMonitor, internalArchiveDspCallBack); + + archiveDspLock.wait(); + + // at this point we got the content object(s) from the current DSP + newDataSources.addAll(internalDataSource.getContent()); + } + } } catch (Exception ex) { criticalErrorOccurred = true; errorMessages.add(ex.getMessage()); logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS } finally { + logger.log(Level.INFO, "Finished processing of archive {0}", archivePath); + progressMonitor.setProgress(100); if (criticalErrorOccurred) { result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; } else if (!errorMessages.isEmpty()) { @@ -113,10 +261,78 @@ class AddArchiveTask implements Runnable { } } - /* - * Attempts to cancel adding the archive to the case database. + /** + * Get a list of data source processors. LocalDisk, LocalFiles, and + * ArchiveDSP are removed from the list. + * + * @return List of data source processors */ - public void cancelTask() { + private List getListOfValidDataSourceProcessors() { + Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); + + List validDataSourceProcessors = processorCandidates.stream().collect(Collectors.toList()); + + for (Iterator iterator = validDataSourceProcessors.iterator(); iterator.hasNext();) { + AutoIngestDataSourceProcessor selectedProcessor = iterator.next(); + + // skip local files and local disk DSPs, only looking for "valid" data sources. + // also skip nested archive files, those will be ingested as logical files and extracted during ingest + if ((selectedProcessor instanceof LocalDiskDSProcessor) + || (selectedProcessor instanceof LocalFilesDSProcessor) + || (selectedProcessor instanceof ArchiveExtractorDSProcessor)) { + iterator.remove(); + } + } + + return validDataSourceProcessors; + } + + /** + * Get a list of data source processors that can process the data source of + * interest. The list is sorted by confidence in decreasing order. + * + * @param dataSourcePath Full path to the data source + * @param errorMessages List for error messages + * @param errorMessages List of AutoIngestDataSourceProcessor to try + * + * @return Ordered list of applicable DSPs + */ + private List getDataSourceProcessorsForFile(Path dataSourcePath, List errorMessages, + List processorCandidates) { + + // Get an ordered list of data source processors to try + List validDataSourceProcessorsForFile = Collections.emptyList(); + try { + validDataSourceProcessorsForFile = DataSourceProcessorUtility.getOrderedListOfDataSourceProcessors(dataSourcePath, processorCandidates); + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { + criticalErrorOccurred = true; + errorMessages.add(ex.getMessage()); + logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS + return Collections.emptyList(); + } + return validDataSourceProcessorsForFile; + } + + /** + * Create a directory in ModuleOutput folder based on input file name. A + * time stamp is appended to the directory name. + * + * @param fileName File name + * @param baseDirectory Base directory. Typically the case output directory. + * + * @return Full path to the new directory + */ + private Path createDirectoryForFile(String fileName, String baseDirectory) { + // get file name without full path or extension + String fileNameNoExt = FilenameUtils.getBaseName(fileName); + + // create folder to extract archive to + Path newFolder = Paths.get(baseDirectory, ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR, fileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); + if (newFolder.toFile().mkdirs() == false) { + // unable to create directory + return Paths.get(""); + } + return newFolder; } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java index db19fc2fbc..fc00149249 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java @@ -35,7 +35,7 @@ import org.sleuthkit.datamodel.Content; class AddDataSourceCallback extends DataSourceProcessorCallback { private final Case caseForJob; - private final DataSource dataSourceInfo; + private final AutoIngestDataSource dataSourceInfo; private final UUID taskId; private final Object lock; @@ -48,7 +48,7 @@ class AddDataSourceCallback extends DataSourceProcessorCallback { * @param dataSourceInfo The data source * @param taskId The task id to associate with ingest job events. */ - AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId, Object lock) { + AddDataSourceCallback(Case caseForJob, AutoIngestDataSource dataSourceInfo, UUID taskId, Object lock) { this.caseForJob = caseForJob; this.dataSourceInfo = dataSourceInfo; this.taskId = taskId; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index a649b0f37a..0eba2b8f95 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -18,13 +18,15 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.nio.file.Path; import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import javax.swing.JPanel; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; @@ -35,13 +37,12 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; * add data source wizard. It also provides a run method overload to allow it to * be used independently of the wizard. */ -//@ServiceProviders(value={ -// @ServiceProvider(service=DataSourceProcessor.class), -// @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} -//) +@ServiceProviders(value={ + @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} +) @NbBundle.Messages({ "ArchiveDSP.dsType.text=Archive file"}) -public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor { +public class ArchiveExtractorDSProcessor implements AutoIngestDataSourceProcessor { private final static String DATA_SOURCE_TYPE = Bundle.ArchiveDSP_dsType_text(); @@ -50,6 +51,8 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng private String archivePath; private boolean setDataSourceOptionsCalled; + private final ExecutorService jobProcessingExecutor; + private static final String ARCHIVE_DSP_THREAD_NAME = "Archive-DSP-%d"; private AddArchiveTask addArchiveTask; /** @@ -60,6 +63,7 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng */ public ArchiveExtractorDSProcessor() { configPanel = ArchiveFilePanel.createInstance(ArchiveExtractorDSProcessor.class.getName(), ArchiveUtil.getArchiveFilters()); + jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(ARCHIVE_DSP_THREAD_NAME).build()); } @Override @@ -151,21 +155,15 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng */ public void run(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { addArchiveTask = new AddArchiveTask(deviceId, archivePath, progressMonitor, callback); - new Thread(addArchiveTask).start(); + jobProcessingExecutor.submit(addArchiveTask); } /** - * Requests cancellation of the background task that adds a data source to - * the case database, after the task is started using the run method. This - * is a "best effort" cancellation, with no guarantees that the case - * database will be unchanged. If cancellation succeeded, the list of new - * data sources returned by the background task will be empty. + * This DSP is a service to AutoIngestDataSourceProcessor only. Hence it is + * only used by AIM. AIM currently doesn't support DSP cancellation. */ @Override public void cancel() { - if (null != addArchiveTask) { - addArchiveTask.cancelTask(); - } } @Override @@ -175,50 +173,4 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng configPanel.reset(); setDataSourceOptionsCalled = false; } - - /** - * Extracts the contents of a ZIP archive submitted as a data source to a - * subdirectory of the auto ingest module output directory. - * - * @throws IOException if there is a problem extracting the data source from - * the archive. - - private static Path extractDataSource(Path outputDirectoryPath, Path dataSourcePath) throws IOException { - String dataSourceFileNameNoExt = FilenameUtils.removeExtension(dataSourcePath.getFileName().toString()); - Path destinationFolder = Paths.get(outputDirectoryPath.toString(), - AUTO_INGEST_MODULE_OUTPUT_DIR, - dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); - Files.createDirectories(destinationFolder); - - int BUFFER_SIZE = 524288; // Read/write 500KB at a time - File sourceZipFile = dataSourcePath.toFile(); - ZipFile zipFile; - zipFile = new ZipFile(sourceZipFile, ZipFile.OPEN_READ); - Enumeration zipFileEntries = zipFile.entries(); - try { - while (zipFileEntries.hasMoreElements()) { - ZipEntry entry = zipFileEntries.nextElement(); - String currentEntry = entry.getName(); - File destFile = new File(destinationFolder.toString(), currentEntry); - destFile = new File(destinationFolder.toString(), destFile.getName()); - File destinationParent = destFile.getParentFile(); - destinationParent.mkdirs(); - if (!entry.isDirectory()) { - BufferedInputStream is = new BufferedInputStream(zipFile.getInputStream(entry)); - int currentByte; - byte data[] = new byte[BUFFER_SIZE]; - try (FileOutputStream fos = new FileOutputStream(destFile); BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) { - currentByte = is.read(data, 0, BUFFER_SIZE); - while (currentByte != -1) { - dest.write(data, 0, currentByte); - currentByte = is.read(data, 0, BUFFER_SIZE); - } - } - } - } - } finally { - zipFile.close(); - } - return destinationFolder; - } */ } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java index b7a2926092..db2b954bca 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java @@ -214,10 +214,11 @@ final class ArchiveUtil { * @param destinationFolder Path to directory where results will be * extracted to. * + * @return List of file names contained within archive * @throws * ArchiveExtractionException */ - static void unpackArchiveFile(String archiveFilePath, String destinationFolder) throws ArchiveExtractionException { + static List unpackArchiveFile(String archiveFilePath, String destinationFolder) throws ArchiveExtractionException { if (!SevenZip.isInitializedSuccessfully() && (SevenZip.getLastInitializationException() == null)) { try { SevenZip.initSevenZipFromPlatformJAR(); @@ -225,6 +226,7 @@ final class ArchiveUtil { throw new ArchiveExtractionException("Unable to initialize 7Zip libraries", ex); } } + List files = new ArrayList<>(); ISevenZipInArchive inArchive = null; try { RandomAccessFile randomAccessFile = new RandomAccessFile(new File(archiveFilePath), "r"); @@ -251,6 +253,8 @@ final class ArchiveUtil { } } } + // keep track of extracted files + files.add(fullPath.toString()); } } catch (Exception ex) { throw new ArchiveExtractionException("Exception while unpacking archive contents", ex); @@ -263,6 +267,7 @@ final class ArchiveUtil { throw new ArchiveExtractionException("Exception while closing the archive", ex); } } + return files; } /** diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestAlertFile.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestAlertFile.java deleted file mode 100755 index 40fff351eb..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestAlertFile.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 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.io.IOException; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.logging.Level; - -/** - * Utility for creating and checking for the existence of an automated ingest - * alert file. The purpose of the file is to put a marker in the case directory - * when an error or warning occurs in connection with an automated ingest job. - */ -final class AutoIngestAlertFile { - - private static final String ERROR_FILE_NAME = "autoingest.alert"; - - /** - * Checks whether an automated ingest alert file exists in a case directory. - * - * @param caseDirectoryPath The case directory path. - * - * @return True or false. - */ - static boolean exists(Path caseDirectoryPath) { - return caseDirectoryPath.resolve(ERROR_FILE_NAME).toFile().exists(); - } - - /** - * Creates an automated ingest alert file in a case directory if such a file - * does not already exist. - * - * @param caseDirectoryPath The case directory path. - * - * @return True or false. - */ - static void create(Path caseDirectoryPath) throws AutoIngestAlertFileException { - try { - Files.createFile(caseDirectoryPath.resolve(ERROR_FILE_NAME)); - } catch (FileAlreadyExistsException ignored) { - /* - * The file already exists, the exception is not exceptional. - */ - } catch (IOException ex) { - /* - * FileAlreadyExistsException implementation is optional, so check - * for that case. - */ - if (!exists(caseDirectoryPath)) { - throw new AutoIngestAlertFileException(String.format("Error creating automated ingest alert file in %s", caseDirectoryPath), ex); - } - } - } - - /** - * Exception thrown when there is a problem creating an alert file. - */ - final static class AutoIngestAlertFileException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs an exception to throw when there is a problem creating an - * alert file. - * - * @param message The exception message. - */ - private AutoIngestAlertFileException(String message) { - super(message); - } - - /** - * Constructs an exception to throw when there is a problem creating an - * alert file. - * - * @param message The exception message. - * @param cause The cause of the exception, if it was an exception. - */ - private AutoIngestAlertFileException(String message, Throwable cause) { - super(message, cause); - } - } - - /** - * Prevents instantiation of this utility class. - */ - private AutoIngestAlertFile() { - } - -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java deleted file mode 100755 index ff47423030..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCase.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015-2017 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.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Comparator; -import java.util.Date; -import java.util.Objects; -import java.util.logging.Level; -import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.coreutils.Logger; - -/** - * A representation of a case created by automated ingest. - */ -class AutoIngestCase implements Comparable { - - private static final Logger logger = Logger.getLogger(AutoIngestCase.class.getName()); - private final Path caseDirectoryPath; - private final String caseName; - private final Path metadataFilePath; - private final Date createDate; - private final Date lastAccessedDate; - - /** - * Constructs a representation of case created by automated ingest. - * - * @param caseDirectoryPath The case directory path. - */ - AutoIngestCase(Path caseDirectoryPath) { - this.caseDirectoryPath = caseDirectoryPath; - caseName = PathUtils.caseNameFromCaseDirectoryPath(caseDirectoryPath); - metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension()); - BasicFileAttributes fileAttrs = null; - try { - fileAttrs = Files.readAttributes(metadataFilePath, BasicFileAttributes.class); - } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, will use current time for case createDate/lastModfiedDate", caseDirectoryPath), ex); - } - if (null != fileAttrs) { - createDate = new Date(fileAttrs.creationTime().toMillis()); - lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); - } else { - createDate = new Date(); - lastAccessedDate = new Date(); - } - } - - /** - * Gets the case directory path. - * - * @return The case directory path. - */ - Path getCaseDirectoryPath() { - return this.caseDirectoryPath; - } - - /** - * Gets the case name. - * - * @return The case name. - */ - String getCaseName() { - return this.caseName; - } - - /** - * Gets the creation date for the case, defined as the create time of the - * case metadata file. - * - * @return The case creation date. - */ - Date getCreationDate() { - return this.createDate; - } - - /** - * Gets the last accessed date for the case, defined as the last accessed - * time of the case metadata file. - * - * @return The last accessed date. - */ - Date getLastAccessedDate() { - return this.lastAccessedDate; - } - - /** - * Gets the status of this case based on the auto ingest result file in the - * case directory. - * - * @return See CaseStatus enum definition. - */ - CaseStatus getStatus() { - if (AutoIngestAlertFile.exists(caseDirectoryPath)) { - return CaseStatus.ALERT; - } else { - return CaseStatus.OK; - } - } - - /** - * Indicates whether or not some other object is "equal to" this - * AutoIngestCase object. - * - * @param other The other object. - * - * @return True or false. - */ - @Override - public boolean equals(Object other) { - if (!(other instanceof AutoIngestCase)) { - return false; - } - if (other == this) { - return true; - } - return this.caseDirectoryPath.toString().equals(((AutoIngestCase) other).caseDirectoryPath.toString()); - } - - /** - * Returns a hash code value for this AutoIngestCase object. - * - * @return The has code. - */ - @Override - public int hashCode() { - int hash = 7; - hash = 71 * hash + Objects.hashCode(this.caseDirectoryPath); - hash = 71 * hash + Objects.hashCode(this.createDate); - hash = 71 * hash + Objects.hashCode(this.caseName); - return hash; - } - - /** - * Compares this AutopIngestCase object with abnother AutoIngestCase object - * for order. - */ - @Override - public int compareTo(AutoIngestCase other) { - return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); - } - - /** - * Comparator for a descending order sort on date created. - */ - static class LastAccessedDateDescendingComparator implements Comparator { - - /** - * Compares two AutoIngestCase objects for order based on last accessed - * date (descending). - * - * @param object The first AutoIngestCase object - * @param otherObject The second AuotIngestCase object. - * - * @return A negative integer, zero, or a positive integer as the first - * argument is less than, equal to, or greater than the second. - */ - @Override - public int compare(AutoIngestCase object, AutoIngestCase otherObject) { - return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); - } - } - - enum CaseStatus { - - OK, - ALERT - } - -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java deleted file mode 100755 index 8469ff2315..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 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.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.CaseActionException; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; - -/** - * Handles locating and opening cases created by auto ingest. - */ -final class AutoIngestCaseManager { - - private static AutoIngestCaseManager instance; - - private CoordinationService coordinationService; - - /** - * Gets the auto ingest case manager. - * - * @return The auto ingest case manager singleton. - * - * @throws AutoIngestCaseManagerException - */ - synchronized static AutoIngestCaseManager getInstance() throws AutoIngestCaseManager.AutoIngestCaseManagerException { - if (null == instance) { - instance = new AutoIngestCaseManager(); - } - return instance; - } - - /** - * Constructs an object that handles locating and opening cases created by - * auto ingest. - * - * @throws AutoIngestCaseManagerException - */ - private AutoIngestCaseManager() throws AutoIngestCaseManagerException { - try { - coordinationService = CoordinationService.getInstance(); - } catch (CoordinationServiceException ex) { - throw new AutoIngestCaseManager.AutoIngestCaseManagerException("Failed to get the coordination service.", ex); - } - } - - /** - * Gets a list of the cases in the top level case folder used by auto - * ingest. - * - * @return List of cases. - * - * @throws AutoIngestCaseManagerException - */ - List getCases() throws AutoIngestCaseManagerException { - List cases = new ArrayList<>(); - List casePathList = getCasePaths(); - for (Path casePath : casePathList) { - cases.add(new AutoIngestCase(casePath)); - } - return cases; - } - - /** - * Retrieve all of the case nodes and filter for only those that represent - * case paths. - * - * @return List of case paths. - * - * @throws AutoIngestCaseManagerException - */ - private List getCasePaths() throws AutoIngestCaseManagerException { - try { - List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); - List casePathList = new ArrayList(0); - for (String node : nodeList) { - if(node.indexOf('\\') >= 0 || node.indexOf('/') >= 0) { - /* - * This is not a case name lock (name specifies a path). - */ - String nodeUpperCase = node.toUpperCase(); - if(!nodeUpperCase.endsWith("_RESOURCES") && !nodeUpperCase.endsWith("AUTO_INGEST_LOG.TXT")) { - /* - * This is not a case resource lock, nor a case auto - * ingest log lock. Collect the path. - */ - casePathList.add(Paths.get(node)); - } - } - } - return casePathList; - - } catch (CoordinationServiceException ex) { - throw new AutoIngestCaseManager.AutoIngestCaseManagerException("Failed to get node list from coordination service.", ex); - } - } - - /** - * Opens an auto ingest case case. - * - * @param caseMetadataFilePath Path to the case metadata file. - * - * @throws CaseActionException - */ - synchronized void openCase(Path caseMetadataFilePath) throws CaseActionException { - /* - * Open the case. - */ - Case.openAsCurrentCase(caseMetadataFilePath.toString()); - } - - /** - * Exception type thrown when there is an error completing an auto ingest - * case manager operation. - */ - static final class AutoIngestCaseManagerException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing an auto ingest case manager operation. - * - * @param message The exception message. - */ - private AutoIngestCaseManagerException(String message) { - super(message); - } - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing an auto ingest case manager operation. - * - * @param message The exception message. - * @param cause A Throwable cause for the error. - */ - private AutoIngestCaseManagerException(String message, Throwable cause) { - super(message, cause); - } - - } -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java deleted file mode 100755 index e86a7bcf8a..0000000000 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseOpenAction.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 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.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.logging.Level; -import org.openide.util.HelpCtx; -import org.openide.util.Lookup; -import org.openide.util.NbBundle; -import org.openide.util.actions.CallableSystemAction; -import org.openide.util.actions.SystemAction; -import org.sleuthkit.autopsy.casemodule.CaseCloseAction; -import org.sleuthkit.autopsy.casemodule.CaseOpenAction; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; -import org.sleuthkit.autopsy.core.UserPreferences; - -final class AutoIngestCaseOpenAction extends CallableSystemAction implements ActionListener { - - private static final Logger logger = Logger.getLogger(AutoIngestCaseOpenAction.class.getName()); - private static final long serialVersionUID = 1L; - - public AutoIngestCaseOpenAction() { - } - - @Override - public void actionPerformed(ActionEvent e) { - - UserPreferences.SelectedMode mode = UserPreferences.getMode(); - switch (mode) { - case REVIEW: - - if (Case.isCaseOpen()) { - /* - * In review mode, close the currently open case, if any, and - * then display the review mode cases panel. This can be - * accomplished by invoking CaseCloseAction because it calls - * StartupWindowProvider.getInstance().open() after it closes - * the current case. - */ - SystemAction.get(CaseCloseAction.class).actionPerformed(e); - } else { - // no case is open, so show the startup window - StartupWindowProvider.getInstance().open(); - } - break; - - case AUTOINGEST: - /* - * New case action is disabled in auto ingest mode. - */ - break; - - case STANDALONE: - /** - * In standalone mode, invoke default Autopsy version of CaseOpenAction. - */ - Lookup.getDefault().lookup(CaseOpenAction.class).actionPerformed(e); - break; - - - default: - logger.log(Level.SEVERE, "Attempting to open case in unsupported mode {0}", mode.toString()); - } - } - - @Override - public void performAction() { - } - - @Override - public String getName() { - return NbBundle.getMessage(AutoIngestCaseOpenAction.class, "CTL_OpenAction"); - } - - @Override - public HelpCtx getHelpCtx() { - return HelpCtx.DEFAULT_HELP; - } - -} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form index ad525e92ee..f00e28374c 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.form @@ -17,46 +17,22 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - + + + + + + + + + @@ -73,8 +49,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -99,9 +103,9 @@ - + - + @@ -135,16 +139,13 @@ - - - - - - - - - - + + + + + + + @@ -234,6 +235,15 @@ + + + + + + + + + @@ -247,6 +257,15 @@ + + + + + + + + + @@ -290,6 +309,15 @@ + + + + + + + + + @@ -303,6 +331,15 @@ + + + + + + + + + @@ -316,6 +353,15 @@ + + + + + + + + + @@ -330,6 +376,15 @@ + + + + + + + + + @@ -343,6 +398,15 @@ + + + + + + + + + @@ -356,6 +420,15 @@ + + + + + + + + + @@ -369,6 +442,15 @@ + + + + + + + + + @@ -382,6 +464,15 @@ + + + + + + + + + @@ -422,6 +513,15 @@ + + + + + + + + + @@ -456,20 +556,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- + \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java index 891975223a..be8abbd1ee 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestControlPanel.java @@ -39,7 +39,6 @@ import javax.swing.DefaultListSelectionModel; import java.awt.Color; import java.beans.PropertyChangeEvent; import java.io.File; -import java.util.Collections; import java.util.logging.Logger; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -60,10 +59,13 @@ import org.sleuthkit.autopsy.core.ServicesMonitor; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.CaseDeletionResult; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.JobsSnapshot; +import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; +import org.sleuthkit.autopsy.guiutils.LongDateCellRenderer; +import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog; /** * A panel for monitoring automated ingest by a cluster, and for controlling @@ -71,6 +73,7 @@ import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.JobsSnaps * one such panel per node. */ @Messages({ + "AutoIngestControlPanel.bnClusterMetrics.text=Cluster Metrics", "AutoIngestControlPanel.bnPause.text=Pause", "AutoIngestControlPanel.bnPause.paused=Paused", "AutoIngestControlPanel.bnPause.running=Running", @@ -114,7 +117,7 @@ import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.JobsSnaps "AutoIngestControlPanel.bnPrioritizeJob.actionCommand=", "AutoIngestControlPanel.lbServicesStatus.text=Services Status:", "AutoIngestControlPanel.tbServicesStatusMessage.text=", - "AutoIngestControlPanel.bnOpenLogDir.text=Open System Logs Directory", + "AutoIngestControlPanel.bnOpenLogDir.text=Open System Logs Folder", "AutoIngestControlPanel.bnReprocessJob.text=Reprocess Job", "AutoIngestControlPanel.bnPrioritizeFolder.label=", "AutoIngestControlPanel.Cancelling=Cancelling...", @@ -138,6 +141,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { private static final int GENERIC_COL_MAX_WIDTH = 2000; private static final int PENDING_TABLE_COL_PREFERRED_WIDTH = 280; private static final int RUNNING_TABLE_COL_PREFERRED_WIDTH = 175; + private static final int PRIORITY_COLUMN_PREFERRED_WIDTH = 60; + private static final int PRIORITY_COLUMN_MAX_WIDTH = 150; private static final int ACTIVITY_TIME_COL_MIN_WIDTH = 250; private static final int ACTIVITY_TIME_COL_MAX_WIDTH = 450; private static final int TIME_COL_MIN_WIDTH = 30; @@ -177,6 +182,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * ordinal or a column header string. */ @Messages({ + "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Priority=Prioritized", "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Case=Case", "AutoIngestControlPanel.JobsTableModel.ColumnHeader.ImageFolder=Data Source", "AutoIngestControlPanel.JobsTableModel.ColumnHeader.HostName=Host Name", @@ -203,8 +209,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { STATUS(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Status")), CASE_DIRECTORY_PATH(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.CaseFolder")), IS_LOCAL_JOB(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.LocalJob")), - MANIFEST_FILE_PATH(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.ManifestFilePath")); - + MANIFEST_FILE_PATH(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.ManifestFilePath")), + PRIORITY(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Priority")); private final String header; private JobsTableModelColumns(String header) { @@ -227,7 +233,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { STAGE_TIME.getColumnHeader(), CASE_DIRECTORY_PATH.getColumnHeader(), IS_LOCAL_JOB.getColumnHeader(), - MANIFEST_FILE_PATH.getColumnHeader()}; + MANIFEST_FILE_PATH.getColumnHeader(), + PRIORITY.getColumnHeader()}; } /** @@ -259,32 +266,11 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { manager = AutoIngestManager.getInstance(); - pendingTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; + pendingTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; + runningTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - runningTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; - - completedTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; + completedTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); initComponents(); // Generated code. setServicesStatusMessage(); @@ -292,7 +278,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { initRunningJobsTable(); initCompletedJobsTable(); initButtons(); - + completedTable.getRowSorter().toggleSortOrder(JobsTableModelColumns.COMPLETED_TIME.ordinal()); /* * Must set this flag, otherwise pop up menus don't close properly. */ @@ -412,10 +398,16 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); column.setWidth(TIME_COL_PREFERRED_WIDTH); + column = pendingTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()); + column.setCellRenderer(new PrioritizedIconCellRenderer()); + column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH); + column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); + column.setWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); + /** - * Prevent sorting when a column header is clicked. + * Allow sorting when a column header is clicked. */ - pendingTable.setAutoCreateRowSorter(false); + pendingTable.setRowSorter(new AutoIngestRowSorter<>(pendingTableModel)); /* * Create a row selection listener to enable/disable the prioritize @@ -454,7 +446,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.getColumnHeader())); runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); - + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); /* * Set up a column to display the cases associated with the jobs. */ @@ -524,9 +516,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { } private void updateRunningTableButtonsBasedOnSelectedRow() { - int row = runningTable.getSelectedRow(); + int row = runningTable.convertRowIndexToModel(runningTable.getSelectedRow()); if (row >= 0 && row < runningTable.getRowCount()) { - if ((boolean) runningTableModel.getValueAt(row, JobsTableModelColumns.IS_LOCAL_JOB.ordinal())) { + if ((boolean) runningTable.getModel().getValueAt(row, JobsTableModelColumns.IS_LOCAL_JOB.ordinal())) { enableRunningTableButtons(true); return; } @@ -544,13 +536,13 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * does not remove the columns from the model, just from this table. */ completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.getColumnHeader())); - completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); - + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); /* * Set up a column to display the cases associated with the jobs. */ @@ -596,16 +588,16 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * renderer that will choose an icon to represent the job status. */ column = completedTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader()); - column.setCellRenderer(new CaseStatusIconCellRenderer()); + column.setCellRenderer(new StatusIconCellRenderer()); column.setMinWidth(STATUS_COL_MIN_WIDTH); column.setMaxWidth(STATUS_COL_MAX_WIDTH); column.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); column.setWidth(STATUS_COL_PREFERRED_WIDTH); /* - * Prevent sorting when a column header is clicked. + * Allow sorting when a column header is clicked. */ - completedTable.setAutoCreateRowSorter(false); + completedTable.setRowSorter(new AutoIngestRowSorter<>(completedTableModel)); /* * Create a row selection listener to enable/disable the delete case and @@ -982,7 +974,6 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { List completedJobs = new ArrayList<>(); manager.getJobs(pendingJobs, runningJobs, completedJobs); // Sort the completed jobs list by completed date - Collections.sort(completedJobs, new AutoIngestJob.CompletedDateDescendingComparator()); EventQueue.invokeLater(new RefreshComponentsTask(pendingJobs, runningJobs, completedJobs)); } } @@ -1030,9 +1021,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { */ if (null != pendingJobs) { - Path currentRow = getSelectedEntry(pendingTable, pendingTableModel); - refreshTable(pendingJobs, pendingTableModel, null); - setSelectedEntry(pendingTable, pendingTableModel, currentRow); + Path currentRow = getSelectedEntry(pendingTable); + refreshTable(pendingJobs, (DefaultTableModel) pendingTable.getModel(), null); + setSelectedEntry(pendingTable, currentRow); } if (null != runningJobs) { @@ -1041,15 +1032,15 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { } else { updateRunningTableButtonsBasedOnSelectedRow(); } - Path currentRow = getSelectedEntry(runningTable, runningTableModel); - refreshTable(runningJobs, runningTableModel, null); - setSelectedEntry(runningTable, runningTableModel, currentRow); + Path currentRow = getSelectedEntry(runningTable); + refreshTable(runningJobs, (DefaultTableModel) runningTable.getModel(), null); + setSelectedEntry(runningTable, currentRow); } if (null != completedJobs) { - Path currentRow = getSelectedEntry(completedTable, completedTableModel); - refreshTable(completedJobs, completedTableModel, null); - setSelectedEntry(completedTable, completedTableModel, currentRow); + Path currentRow = getSelectedEntry(completedTable); + refreshTable(completedJobs, (DefaultTableModel) completedTable.getModel(), null); + setSelectedEntry(completedTable, currentRow); } } @@ -1087,12 +1078,12 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * * @return a path representing the current selection */ - Path getSelectedEntry(JTable table, DefaultTableModel tableModel) { + Path getSelectedEntry(JTable table) { try { - int currentlySelectedRow = table.getSelectedRow(); + int currentlySelectedRow = table.convertRowIndexToModel(table.getSelectedRow()); if (currentlySelectedRow >= 0 && currentlySelectedRow < table.getRowCount()) { - return Paths.get(tableModel.getValueAt(currentlySelectedRow, JobsTableModelColumns.CASE.ordinal()).toString(), - tableModel.getValueAt(currentlySelectedRow, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); + return Paths.get(table.getModel().getValueAt(currentlySelectedRow, JobsTableModelColumns.CASE.ordinal()).toString(), + table.getModel().getValueAt(currentlySelectedRow, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); } } catch (Exception ignored) { return null; @@ -1108,12 +1099,12 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { * @param tableModel The tableModel of the table to set * @param path The path of the item to set */ - void setSelectedEntry(JTable table, DefaultTableModel tableModel, Path path) { + void setSelectedEntry(JTable table, Path path) { if (path != null) { try { for (int row = 0; row < table.getRowCount(); ++row) { - Path temp = Paths.get(tableModel.getValueAt(row, JobsTableModelColumns.CASE.ordinal()).toString(), - tableModel.getValueAt(row, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); + Path temp = Paths.get(table.getModel().getValueAt(row, JobsTableModelColumns.CASE.ordinal()).toString(), + table.getModel().getValueAt(row, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); if (temp.compareTo(path) == 0) { // found it table.setRowSelectionInterval(row, row); return; @@ -1152,11 +1143,12 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { job.getProcessingStageStartDate(), // STARTED_TIME job.getCompletedDate(), // COMPLETED_TIME status.getDescription(), // ACTIVITY - job.getErrorsOccurred(), // STATUS + job.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, // STATUS ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // ACTIVITY_TIME job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH job.getProcessingHostName().equals(LOCAL_HOST_NAME), // IS_LOCAL_JOB - job.getManifest().getFilePath()}); // MANIFEST_FILE_PATH + job.getManifest().getFilePath(), // MANIFEST_FILE_PATH + job.getPriority()}); // PRIORITY } } catch (Exception ex) { SYS_LOGGER.log(Level.SEVERE, "Dashboard error refreshing table", ex); @@ -1168,9 +1160,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { */ private void refreshTables() { JobsSnapshot jobsSnapshot = manager.getCurrentJobsSnapshot(); - refreshTable(jobsSnapshot.getCompletedJobs(), completedTableModel, null); - refreshTable(jobsSnapshot.getPendingJobs(), pendingTableModel, null); - refreshTable(jobsSnapshot.getRunningJobs(), runningTableModel, null); + refreshTable(jobsSnapshot.getCompletedJobs(), (DefaultTableModel) completedTable.getModel(), null); + refreshTable(jobsSnapshot.getPendingJobs(), (DefaultTableModel) pendingTable.getModel(), null); + refreshTable(jobsSnapshot.getRunningJobs(), (DefaultTableModel) runningTable.getModel(), null); } /** @@ -1207,6 +1199,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { lbServicesStatus = new javax.swing.JLabel(); tbServicesStatusMessage = new javax.swing.JTextField(); bnOpenLogDir = new javax.swing.JButton(); + bnClusterMetrics = new javax.swing.JButton(); bnReprocessJob = new javax.swing.JButton(); pendingTable.setModel(pendingTableModel); @@ -1265,6 +1258,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnCancelJob, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelJob.text")); // NOI18N bnCancelJob.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelJob.toolTipText")); // NOI18N + bnCancelJob.setMaximumSize(new java.awt.Dimension(162, 23)); + bnCancelJob.setMinimumSize(new java.awt.Dimension(162, 23)); + bnCancelJob.setPreferredSize(new java.awt.Dimension(162, 23)); bnCancelJob.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnCancelJobActionPerformed(evt); @@ -1273,6 +1269,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnDeleteCase, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnDeleteCase.text")); // NOI18N bnDeleteCase.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnDeleteCase.toolTipText")); // NOI18N + bnDeleteCase.setMaximumSize(new java.awt.Dimension(162, 23)); + bnDeleteCase.setMinimumSize(new java.awt.Dimension(162, 23)); + bnDeleteCase.setPreferredSize(new java.awt.Dimension(162, 23)); bnDeleteCase.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnDeleteCaseActionPerformed(evt); @@ -1290,6 +1289,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnRefresh.text")); // NOI18N bnRefresh.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnRefresh.toolTipText")); // NOI18N + bnRefresh.setMaximumSize(new java.awt.Dimension(162, 23)); + bnRefresh.setMinimumSize(new java.awt.Dimension(162, 23)); + bnRefresh.setPreferredSize(new java.awt.Dimension(162, 23)); bnRefresh.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnRefreshActionPerformed(evt); @@ -1298,6 +1300,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnCancelModule, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelModule.text")); // NOI18N bnCancelModule.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnCancelModule.toolTipText")); // NOI18N + bnCancelModule.setMaximumSize(new java.awt.Dimension(162, 23)); + bnCancelModule.setMinimumSize(new java.awt.Dimension(162, 23)); + bnCancelModule.setPreferredSize(new java.awt.Dimension(162, 23)); bnCancelModule.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnCancelModuleActionPerformed(evt); @@ -1306,6 +1311,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnExit, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnExit.text")); // NOI18N bnExit.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnExit.toolTipText")); // NOI18N + bnExit.setMaximumSize(new java.awt.Dimension(162, 23)); + bnExit.setMinimumSize(new java.awt.Dimension(162, 23)); + bnExit.setPreferredSize(new java.awt.Dimension(162, 23)); bnExit.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnExitActionPerformed(evt); @@ -1315,6 +1323,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnOptions, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnOptions.text")); // NOI18N bnOptions.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnOptions.toolTipText")); // NOI18N bnOptions.setEnabled(false); + bnOptions.setMaximumSize(new java.awt.Dimension(162, 23)); + bnOptions.setMinimumSize(new java.awt.Dimension(162, 23)); + bnOptions.setPreferredSize(new java.awt.Dimension(162, 23)); bnOptions.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnOptionsActionPerformed(evt); @@ -1323,6 +1334,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnShowProgress, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowProgress.text")); // NOI18N bnShowProgress.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowProgress.toolTipText")); // NOI18N + bnShowProgress.setMaximumSize(new java.awt.Dimension(162, 23)); + bnShowProgress.setMinimumSize(new java.awt.Dimension(162, 23)); + bnShowProgress.setPreferredSize(new java.awt.Dimension(162, 23)); bnShowProgress.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnShowProgressActionPerformed(evt); @@ -1331,6 +1345,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnPause, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPause.text")); // NOI18N bnPause.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPause.toolTipText")); // NOI18N + bnPause.setMaximumSize(new java.awt.Dimension(162, 23)); + bnPause.setMinimumSize(new java.awt.Dimension(162, 23)); + bnPause.setPreferredSize(new java.awt.Dimension(162, 23)); bnPause.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnPauseActionPerformed(evt); @@ -1339,6 +1356,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnPrioritizeCase, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeCase.text")); // NOI18N bnPrioritizeCase.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeCase.toolTipText")); // NOI18N + bnPrioritizeCase.setMaximumSize(new java.awt.Dimension(162, 23)); + bnPrioritizeCase.setMinimumSize(new java.awt.Dimension(162, 23)); + bnPrioritizeCase.setPreferredSize(new java.awt.Dimension(162, 23)); bnPrioritizeCase.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnPrioritizeCaseActionPerformed(evt); @@ -1347,6 +1367,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnShowCaseLog, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowCaseLog.text")); // NOI18N bnShowCaseLog.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnShowCaseLog.toolTipText")); // NOI18N + bnShowCaseLog.setMaximumSize(new java.awt.Dimension(162, 23)); + bnShowCaseLog.setMinimumSize(new java.awt.Dimension(162, 23)); + bnShowCaseLog.setPreferredSize(new java.awt.Dimension(162, 23)); bnShowCaseLog.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnShowCaseLogActionPerformed(evt); @@ -1364,6 +1387,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(bnPrioritizeJob, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeJob.text")); // NOI18N bnPrioritizeJob.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeJob.toolTipText")); // NOI18N bnPrioritizeJob.setActionCommand(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPrioritizeJob.actionCommand")); // NOI18N + bnPrioritizeJob.setMaximumSize(new java.awt.Dimension(162, 23)); + bnPrioritizeJob.setMinimumSize(new java.awt.Dimension(162, 23)); + bnPrioritizeJob.setPreferredSize(new java.awt.Dimension(162, 23)); bnPrioritizeJob.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnPrioritizeJobActionPerformed(evt); @@ -1379,13 +1405,29 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { tbServicesStatusMessage.setBorder(null); org.openide.awt.Mnemonics.setLocalizedText(bnOpenLogDir, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnOpenLogDir.text")); // NOI18N + bnOpenLogDir.setMaximumSize(new java.awt.Dimension(162, 23)); + bnOpenLogDir.setMinimumSize(new java.awt.Dimension(162, 23)); + bnOpenLogDir.setPreferredSize(new java.awt.Dimension(162, 23)); bnOpenLogDir.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnOpenLogDirActionPerformed(evt); } }); + org.openide.awt.Mnemonics.setLocalizedText(bnClusterMetrics, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnClusterMetrics.text")); // NOI18N + bnClusterMetrics.setMaximumSize(new java.awt.Dimension(162, 23)); + bnClusterMetrics.setMinimumSize(new java.awt.Dimension(162, 23)); + bnClusterMetrics.setPreferredSize(new java.awt.Dimension(162, 23)); + bnClusterMetrics.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnClusterMetricsActionPerformed(evt); + } + }); + org.openide.awt.Mnemonics.setLocalizedText(bnReprocessJob, org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnReprocessJob.text")); // NOI18N + bnReprocessJob.setMaximumSize(new java.awt.Dimension(162, 23)); + bnReprocessJob.setMinimumSize(new java.awt.Dimension(162, 23)); + bnReprocessJob.setPreferredSize(new java.awt.Dimension(162, 23)); bnReprocessJob.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnReprocessJobActionPerformed(evt); @@ -1399,38 +1441,20 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(bnPrioritizeCase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(bnPrioritizeJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(bnPause) - .addGap(18, 18, 18) - .addComponent(bnRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(bnOptions) - .addGap(18, 18, 18) - .addComponent(bnOpenLogDir) - .addGap(18, 18, 18) - .addComponent(bnExit, javax.swing.GroupLayout.PREFERRED_SIZE, 94, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(bnPause, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(bnCancelJob, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) - .addComponent(bnShowProgress, javax.swing.GroupLayout.DEFAULT_SIZE, 116, Short.MAX_VALUE) - .addComponent(bnCancelModule, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) - .addComponent(bnDeleteCase, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) - .addComponent(bnShowCaseLog, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(bnReprocessJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(bnRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnOptions, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnOpenLogDir, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnClusterMetrics, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(bnExit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addComponent(lbStatus) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -1441,11 +1465,32 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { .addComponent(lbServicesStatus) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbPending) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 1021, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 1021, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(bnCancelJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnShowProgress, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnCancelModule, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnDeleteCase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnShowCaseLog, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnReprocessJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGroup(layout.createSequentialGroup() + .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 1021, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(bnPrioritizeCase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bnPrioritizeJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnDeleteCase, bnExit, bnOpenLogDir, bnOptions, bnPause, bnRefresh, bnShowProgress}); + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnDeleteCase, bnShowProgress}); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1465,48 +1510,47 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addGap(82, 82, 82) - .addComponent(bnPrioritizeCase) + .addComponent(bnPrioritizeCase, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnPrioritizeJob))) + .addComponent(bnPrioritizeJob, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lbRunning) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(34, 34, 34) - .addComponent(bnShowProgress) + .addComponent(bnShowProgress, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnCancelJob) + .addComponent(bnCancelJob, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnCancelModule)) + .addComponent(bnCancelModule, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(68, 68, 68) - .addComponent(bnReprocessJob) + .addComponent(bnReprocessJob, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnDeleteCase) + .addComponent(bnDeleteCase, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnShowCaseLog)) + .addComponent(bnShowCaseLog, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lbCompleted) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnExit) - .addComponent(bnOpenLogDir)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnPause) - .addComponent(bnRefresh) - .addComponent(bnOptions))))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnPause, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnOptions, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnOpenLogDir, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnClusterMetrics, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(bnExit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addContainerGap()) ); - layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnDeleteCase, bnExit, bnOpenLogDir, bnOptions, bnRefresh, bnShowProgress}); + layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnClusterMetrics, bnDeleteCase, bnExit, bnOpenLogDir, bnOptions, bnPrioritizeCase, bnPrioritizeJob, bnRefresh, bnShowProgress}); }// //GEN-END:initComponents @@ -1535,11 +1579,11 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { "AutoIngestControlPanel.DeletionFailed=Deletion failed for job" }) private void bnDeleteCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDeleteCaseActionPerformed - if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { + if (completedTable.getModel().getRowCount() < 0 || completedTable.getSelectedRow() < 0) { return; } - String caseName = (String) completedTable.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal()); + String caseName = (String) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.CASE.ordinal()); Object[] options = { org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.Delete"), org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.DoNotDelete") @@ -1556,8 +1600,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { if (reply == JOptionPane.YES_OPTION) { bnDeleteCase.setEnabled(false); bnShowCaseLog.setEnabled(false); - if (completedTableModel.getRowCount() > 0 && completedTable.getSelectedRow() >= 0) { - Path caseDirectoryPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); + if (completedTable.getModel().getRowCount() > 0 && completedTable.getSelectedRow() >= 0) { + Path caseDirectoryPath = (Path) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); completedTable.clearSelection(); this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); CaseDeletionResult result = manager.deleteCase(caseName, caseDirectoryPath); @@ -1703,9 +1747,10 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { */ @Messages({"AutoIngestControlPanel.casePrioritization.errorMessage=An error occurred when prioritizing the case. Some or all jobs may not have been prioritized."}) private void bnPrioritizeCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeCaseActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { + if (pendingTable.getModel().getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); + + String caseName = (pendingTable.getModel().getValueAt(pendingTable.convertRowIndexToModel(pendingTable.getSelectedRow()), JobsTableModelColumns.CASE.ordinal())).toString(); try { manager.prioritizeCase(caseName); } catch (AutoIngestManager.AutoIngestManagerException ex) { @@ -1731,9 +1776,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { }) private void bnShowCaseLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowCaseLogActionPerformed try { - int selectedRow = completedTable.getSelectedRow(); + int selectedRow = completedTable.convertRowIndexToModel(completedTable.getSelectedRow()); if (selectedRow != -1) { - Path caseDirectoryPath = (Path) completedTableModel.getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); + Path caseDirectoryPath = (Path) completedTable.getModel().getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal()); if (null != caseDirectoryPath) { Path pathToLog = AutoIngestJobLogger.getLogPath(caseDirectoryPath); if (pathToLog.toFile().exists()) { @@ -1762,9 +1807,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { @Messages({"AutoIngestControlPanel.jobPrioritization.errorMessage=An error occurred when prioritizing the job."}) private void bnPrioritizeJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeJobActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { + if (pendingTable.getModel().getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - Path manifestFilePath = (Path) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal())); + Path manifestFilePath = (Path) (pendingTable.getModel().getValueAt(pendingTable.convertRowIndexToModel(pendingTable.getSelectedRow()), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal())); try { manager.prioritizeJob(manifestFilePath); } catch (AutoIngestManager.AutoIngestManagerException ex) { @@ -1791,19 +1836,28 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { }//GEN-LAST:event_bnOpenLogDirActionPerformed private void bnReprocessJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnReprocessJobActionPerformed - if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) { + if (completedTable.getModel().getRowCount() < 0 || completedTable.getSelectedRow() < 0) { return; } this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - Path manifestPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()); + Path manifestPath = (Path) completedTable.getModel().getValueAt(completedTable.convertRowIndexToModel(completedTable.getSelectedRow()), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()); manager.reprocessJob(manifestPath); refreshTables(); AutoIngestControlPanel.this.setCursor(Cursor.getDefaultCursor()); }//GEN-LAST:event_bnReprocessJobActionPerformed + private void bnClusterMetricsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnClusterMetricsActionPerformed + try { + new AutoIngestMetricsDialog(this.getTopLevelAncestor()); + } catch (AutoIngestMetricsDialog.AutoIngestMetricsDialogException ex) { + MessageNotifyUtil.Message.error(ex.getMessage()); + } + }//GEN-LAST:event_bnClusterMetricsActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton bnCancelJob; private javax.swing.JButton bnCancelModule; + private javax.swing.JButton bnClusterMetrics; private javax.swing.JButton bnDeleteCase; private javax.swing.JButton bnExit; private javax.swing.JButton bnOpenLogDir; @@ -1830,4 +1884,33 @@ public final class AutoIngestControlPanel extends JPanel implements Observer { private javax.swing.JTextField tbStatusMessage; // End of variables declaration//GEN-END:variables + private class AutoIngestTableModel extends DefaultTableModel { + + private static final long serialVersionUID = 1L; + + private AutoIngestTableModel(String[] headers, int i) { + super(headers, i); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + @Override + public Class getColumnClass(int columnIndex) { + if (columnIndex == JobsTableModelColumns.PRIORITY.ordinal()) { + return Integer.class; + } else if (columnIndex == JobsTableModelColumns.CREATED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.COMPLETED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.STARTED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.STAGE_TIME.ordinal()) { + return Date.class; + } else if (columnIndex == JobsTableModelColumns.STATUS.ordinal()) { + return Boolean.class; + } else { + return super.getColumnClass(columnIndex); + } + } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form index 4a943b4924..78ae8fb2a4 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form @@ -29,8 +29,19 @@ + + - + + + + + + + + + + @@ -39,18 +50,9 @@ - - - - - - - - - @@ -81,6 +83,7 @@ + @@ -103,7 +106,6 @@ - @@ -127,7 +129,6 @@ - @@ -151,7 +152,6 @@ - @@ -255,5 +255,15 @@
+ + + + + + + + + +
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 2d10dff258..421b1f92f0 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -44,17 +44,22 @@ import org.sleuthkit.autopsy.core.ServicesMonitor; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; +import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; +import org.sleuthkit.autopsy.guiutils.LongDateCellRenderer; +import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; /** * A dashboard for monitoring an automated ingest cluster. */ -public final class AutoIngestDashboard extends JPanel implements Observer { +final class AutoIngestDashboard extends JPanel implements Observer { private static final long serialVersionUID = 1L; private static final int GENERIC_COL_MIN_WIDTH = 30; private static final int GENERIC_COL_MAX_WIDTH = 2000; private static final int PENDING_TABLE_COL_PREFERRED_WIDTH = 280; private static final int RUNNING_TABLE_COL_PREFERRED_WIDTH = 175; + private static final int PRIORITY_COLUMN_PREFERRED_WIDTH = 60; + private static final int PRIORITY_COLUMN_MAX_WIDTH = 150; private static final int STAGE_TIME_COL_MIN_WIDTH = 250; private static final int STAGE_TIME_COL_MAX_WIDTH = 450; private static final int TIME_COL_MIN_WIDTH = 30; @@ -100,32 +105,11 @@ public final class AutoIngestDashboard extends JPanel implements Observer { * Constructs a panel for monitoring an automated ingest cluster. */ private AutoIngestDashboard() { - pendingTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; + pendingTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; + runningTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - runningTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; - - completedTableModel = new DefaultTableModel(JobsTableModelColumns.headers, 0) { - private static final long serialVersionUID = 1L; - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; + completedTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); initComponents(); setServicesStatusMessage(); @@ -243,10 +227,15 @@ public final class AutoIngestDashboard extends JPanel implements Observer { column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); column.setWidth(TIME_COL_PREFERRED_WIDTH); - /** - * Prevent sorting when a column header is clicked. + column = pendingTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()); + column.setCellRenderer(new PrioritizedIconCellRenderer()); + column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH); + column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); + column.setWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); + /* + * Allow sorting when a column header is clicked. */ - pendingTable.setAutoCreateRowSorter(false); + pendingTable.setRowSorter(new AutoIngestRowSorter<>(pendingTableModel)); /* * Create a row selection listener to enable/disable the Prioritize @@ -257,8 +246,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer { return; } int row = pendingTable.getSelectedRow(); - - boolean enablePrioritizeButtons = (row >= 0 && row < pendingTable.getRowCount()); + + boolean enablePrioritizeButtons = (row >= 0 && row < pendingTable.getRowCount()); this.prioritizeJobButton.setEnabled(enablePrioritizeButtons); this.prioritizeCaseButton.setEnabled(enablePrioritizeButtons); }); @@ -280,7 +269,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); - + runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); /* * Set up a column to display the cases associated with the jobs. */ @@ -354,7 +343,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); - + completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); /* * Set up a column to display the cases associated with the jobs. */ @@ -400,16 +389,15 @@ public final class AutoIngestDashboard extends JPanel implements Observer { * renderer that will choose an icon to represent the job status. */ column = completedTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader()); - column.setCellRenderer(new CaseStatusIconCellRenderer()); + column.setCellRenderer(new StatusIconCellRenderer()); column.setMinWidth(STATUS_COL_MIN_WIDTH); column.setMaxWidth(STATUS_COL_MAX_WIDTH); column.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); column.setWidth(STATUS_COL_PREFERRED_WIDTH); - /* - * Prevent sorting when a column header is clicked. + * Allow sorting when a column header is clicked. */ - completedTable.setAutoCreateRowSorter(false); + completedTable.setRowSorter(new AutoIngestRowSorter<>(completedTableModel)); } /** @@ -472,10 +460,11 @@ public final class AutoIngestDashboard extends JPanel implements Observer { job.getProcessingStageStartDate(), // STARTED_TIME job.getCompletedDate(), // COMPLETED_TIME status.getDescription(), // STAGE - job.getErrorsOccurred(), // STATUS + job.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, // STATUS ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // STAGE_TIME job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH job.getManifest().getFilePath(), // MANIFEST_FILE_PATH + job.getPriority(), // PRIORITY job }); } @@ -541,6 +530,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { * described by either an enum ordinal or a column header string. */ private enum JobsTableModelColumns { + @Messages({"AutoIngestDashboard.JobsTableModel.ColumnHeader.Priority=Prioritized"}) CASE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Case")), DATA_SOURCE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ImageFolder")), @@ -553,6 +543,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { STATUS(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Status")), CASE_DIRECTORY_PATH(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.CaseFolder")), MANIFEST_FILE_PATH(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ManifestFilePath")), + PRIORITY(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Priority")), JOB(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Job")); private final String header; @@ -577,6 +568,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer { STAGE_TIME.getColumnHeader(), CASE_DIRECTORY_PATH.getColumnHeader(), MANIFEST_FILE_PATH.getColumnHeader(), + PRIORITY.getColumnHeader(), JOB.getColumnHeader() }; }; @@ -662,12 +654,12 @@ public final class AutoIngestDashboard extends JPanel implements Observer { tbServicesStatusMessage = new javax.swing.JTextField(); prioritizeJobButton = new javax.swing.JButton(); prioritizeCaseButton = new javax.swing.JButton(); + clusterMetricsButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.jButton1.text")); // NOI18N pendingTable.setModel(pendingTableModel); pendingTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.pendingTable.toolTipText")); // NOI18N - pendingTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); pendingTable.setRowHeight(20); pendingTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -685,7 +677,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { runningTable.setModel(runningTableModel); runningTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.runningTable.toolTipText")); // NOI18N - runningTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); runningTable.setRowHeight(20); runningTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -703,7 +694,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer { completedTable.setModel(completedTableModel); completedTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.completedTable.toolTipText")); // NOI18N - completedTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); completedTable.setRowHeight(20); completedTable.setSelectionModel(new DefaultListSelectionModel() { private static final long serialVersionUID = 1L; @@ -762,6 +752,13 @@ public final class AutoIngestDashboard extends JPanel implements Observer { } }); + org.openide.awt.Mnemonics.setLocalizedText(clusterMetricsButton, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.clusterMetricsButton.text")); // NOI18N + clusterMetricsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + clusterMetricsButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -770,24 +767,26 @@ public final class AutoIngestDashboard extends JPanel implements Observer { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(pendingScrollPane) + .addComponent(runningScrollPane, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(completedScrollPane, javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbPending) - .addComponent(lbCompleted) - .addComponent(lbRunning) - .addGroup(layout.createSequentialGroup() - .addComponent(lbServicesStatus) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addComponent(refreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(prioritizeJobButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(prioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(runningScrollPane, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(completedScrollPane, javax.swing.GroupLayout.Alignment.LEADING)) + .addComponent(prioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(clusterMetricsButton)) + .addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbCompleted, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbRunning, javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(lbServicesStatus) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); layout.setVerticalGroup( @@ -813,7 +812,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(refreshButton) .addComponent(prioritizeJobButton) - .addComponent(prioritizeCaseButton)) + .addComponent(prioritizeCaseButton) + .addComponent(clusterMetricsButton)) .addContainerGap()) ); }// //GEN-END:initComponents @@ -872,7 +872,16 @@ public final class AutoIngestDashboard extends JPanel implements Observer { } }//GEN-LAST:event_prioritizeCaseButtonActionPerformed + private void clusterMetricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clusterMetricsButtonActionPerformed + try { + new AutoIngestMetricsDialog(this.getTopLevelAncestor()); + } catch (AutoIngestMetricsDialog.AutoIngestMetricsDialogException ex) { + MessageNotifyUtil.Message.error(ex.getMessage()); + } + }//GEN-LAST:event_clusterMetricsButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton clusterMetricsButton; private javax.swing.JScrollPane completedScrollPane; private javax.swing.JTable completedTable; private javax.swing.JButton jButton1; @@ -890,4 +899,33 @@ public final class AutoIngestDashboard extends JPanel implements Observer { private javax.swing.JTextField tbServicesStatusMessage; // End of variables declaration//GEN-END:variables + private class AutoIngestTableModel extends DefaultTableModel { + + private static final long serialVersionUID = 1L; + + private AutoIngestTableModel(String[] headers, int i) { + super(headers, i); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + + @Override + public Class getColumnClass(int columnIndex) { + if (columnIndex == JobsTableModelColumns.PRIORITY.ordinal()) { + return Integer.class; + } else if (columnIndex == JobsTableModelColumns.CREATED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.COMPLETED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.STARTED_TIME.ordinal() + || columnIndex == JobsTableModelColumns.STAGE_TIME.ordinal()) { + return Date.class; + } else if (columnIndex == JobsTableModelColumns.STATUS.ordinal()) { + return Boolean.class; + } else { + return super.getColumnClass(columnIndex); + } + } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java index 7e1b1907af..45563a4f4b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardOpenAction.java @@ -25,7 +25,6 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.autopsy.core.UserPreferences; -import static org.sleuthkit.autopsy.core.UserPreferences.SelectedMode.REVIEW; import org.sleuthkit.autopsy.coreutils.Logger; @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.experimental.autoingest.AutoIngestDashboardOpenAction") @@ -39,8 +38,7 @@ public final class AutoIngestDashboardOpenAction extends CallableSystemAction { @Override public boolean isEnabled() { - UserPreferences.SelectedMode mode = UserPreferences.getMode(); - return (mode == REVIEW); + return (UserPreferences.getIsMultiUserModeEnabled()); } @Override diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDataSource.java similarity index 96% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java rename to Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDataSource.java index db9d3d5ad9..89a0d0ad5f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDataSource.java @@ -26,7 +26,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback import org.sleuthkit.datamodel.Content; @ThreadSafe -class DataSource { +class AutoIngestDataSource { private final String deviceId; private final Path path; @@ -34,7 +34,7 @@ class DataSource { private List errorMessages; private List content; - DataSource(String deviceId, Path path) { + AutoIngestDataSource(String deviceId, Path path) { this.deviceId = deviceId; this.path = path; } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 2f2f22fb0d..35b563b961 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -62,7 +62,9 @@ import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.casemodule.CaseDetails; import org.sleuthkit.autopsy.casemodule.CaseMetadata; +import org.sleuthkit.autopsy.coordinationservice.CaseNodeData; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.Lock; @@ -77,7 +79,6 @@ import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.events.AutopsyEventException; import org.sleuthkit.autopsy.events.AutopsyEventPublisher; -import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestAlertFile.AutoIngestAlertFileException; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJobLogger.AutoIngestJobLoggerException; import org.sleuthkit.autopsy.experimental.autoingest.FileExporter.FileExportException; import org.sleuthkit.autopsy.experimental.autoingest.ManifestFileParser.ManifestFileParserException; @@ -112,12 +113,11 @@ import org.sleuthkit.autopsy.ingest.IngestModuleError; * The activities of the auto ingest nodes in a cluster are coordinated by way * of a coordination service and the nodes communicate via event messages. */ -public final class AutoIngestManager extends Observable implements PropertyChangeListener { +final class AutoIngestManager extends Observable implements PropertyChangeListener { private static final int NUM_INPUT_SCAN_SCHEDULING_THREADS = 1; private static final String INPUT_SCAN_SCHEDULER_THREAD_NAME = "AIM-input-scan-scheduler-%d"; private static final String INPUT_SCAN_THREAD_NAME = "AIM-input-scan-%d"; - private static int DEFAULT_JOB_PRIORITY = 0; private static final String AUTO_INGEST_THREAD_NAME = "AIM-job-processing-%d"; private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); private static final String EVENT_CHANNEL_NAME = "Auto-Ingest-Manager-Events"; @@ -498,6 +498,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang } SYS_LOGGER.log(Level.INFO, "Starting input scan of {0}", rootInputDirectory); InputDirScanner scanner = new InputDirScanner(); + scanner.scan(); SYS_LOGGER.log(Level.INFO, "Completed input scan of {0}", rootInputDirectory); } @@ -553,10 +554,12 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (!prioritizedJobs.isEmpty()) { ++maxPriority; for (AutoIngestJob job : prioritizedJobs) { + int oldPriority = job.getPriority(); + job.setPriority(maxPriority); try { - this.updateCoordinationServiceNode(job); - job.setPriority(maxPriority); + this.updateCoordinationServiceManifestNode(job); } catch (CoordinationServiceException | InterruptedException ex) { + job.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating case priority", ex); } } @@ -602,17 +605,19 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /* - * Bump the priority by one and update the coordination service node - * data for the job. + * Bump the priority by one and update the coordination service + * manifest node data for the job. */ if (null != prioritizedJob) { ++maxPriority; + int oldPriority = prioritizedJob.getPriority(); + prioritizedJob.setPriority(maxPriority); try { - this.updateCoordinationServiceNode(prioritizedJob); + this.updateCoordinationServiceManifestNode(prioritizedJob); } catch (CoordinationServiceException | InterruptedException ex) { + prioritizedJob.setPriority(oldPriority); throw new AutoIngestManagerException("Error updating job priority", ex); } - prioritizedJob.setPriority(maxPriority); } Collections.sort(pendingJobs, new AutoIngestJob.PriorityComparator()); @@ -649,7 +654,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang /* * Add the job to the pending jobs queue and update the coordination - * service node data for the job. + * service manifest node data for the job. */ if (null != completedJob && !completedJob.getCaseDirectoryPath().toString().isEmpty()) { try { @@ -661,7 +666,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang completedJob.setCompletedDate(new Date(0)); completedJob.setProcessingStatus(PENDING); completedJob.setProcessingStage(AutoIngestJob.Stage.PENDING, Date.from(Instant.now())); - updateCoordinationServiceNode(completedJob); + updateCoordinationServiceManifestNode(completedJob); pendingJobs.add(completedJob); } catch (CoordinationServiceException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Coordination service error while reprocessing %s", manifestPath), ex); @@ -755,7 +760,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString())); AutoIngestJob deletedJob = new AutoIngestJob(nodeData); deletedJob.setProcessingStatus(AutoIngestJob.ProcessingStatus.DELETED); - this.updateCoordinationServiceNode(deletedJob); + this.updateCoordinationServiceManifestNode(deletedJob); } catch (AutoIngestJobNodeData.InvalidDataException | AutoIngestJobException ex) { SYS_LOGGER.log(Level.WARNING, String.format("Invalid auto ingest job node data for %s", manifestPath), ex); return CaseDeletionResult.PARTIALLY_DELETED; @@ -865,21 +870,37 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /** - * Sets the coordination service node data for an auto ingest job. + * Sets the coordination service manifest node. * - * Note that a new auto ingest node data object will be created from the job - * passed in. Thus, if the data version of the node has changed, the node - * will be "upgraded" as well as updated. + * Note that a new auto ingest job node data object will be created from the + * job passed in. Thus, if the data version of the node has changed, the + * node will be "upgraded" as well as updated. * * @param job The auto ingest job. */ - void updateCoordinationServiceNode(AutoIngestJob job) throws CoordinationServiceException, InterruptedException { + void updateCoordinationServiceManifestNode(AutoIngestJob job) throws CoordinationServiceException, InterruptedException { AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(job); String manifestNodePath = job.getManifest().getFilePath().toString(); byte[] rawData = nodeData.toArray(); coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, rawData); } + /** + * Sets the error flag for case node data given a case directory path. + * + * @param caseDirectoryPath The case directory path. + * + * @throws CoordinationService.CoordinationServiceException + * @throws InterruptedException + * @throws CaseNodeData.InvalidDataException + */ + private void setCaseNodeDataErrorsOccurred(Path caseDirectoryPath) throws CoordinationServiceException, InterruptedException, CaseNodeData.InvalidDataException { + CaseNodeData caseNodeData = new CaseNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString())); + caseNodeData.setErrorsOccurred(true); + byte[] rawData = caseNodeData.toArray(); + coordinationService.setNodeData(CoordinationService.CategoryNode.CASES, caseDirectoryPath.toString(), rawData); + } + /** * A task that submits an input directory scan task to the input directory * scan task executor. @@ -1041,8 +1062,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (null != manifest) { /* - * Update the mapping of case names to manifest paths that is - * used for case deletion. + * Update the mapping of case names to manifest paths that + * is used for case deletion. */ String caseName = manifest.getCaseName(); Path manifestPath = manifest.getFilePath(); @@ -1056,8 +1077,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /* - * Add a job to the pending jobs queue, the completed jobs list, - * or do crashed job recovery, as required. + * Add a job to the pending jobs queue, the completed jobs + * list, or do crashed job recovery, as required. */ try { byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString()); @@ -1077,7 +1098,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang break; case DELETED: /* - * Ignore jobs marked as "deleted." + * Ignore jobs marked as "deleted." */ break; default: @@ -1147,8 +1168,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang } /* - * Try to upgrade/update the coordination service node data for - * the job. + * Try to upgrade/update the coordination service manifest node + * data for the job. * * An exclusive lock is obtained before doing so because another * host may have already found the job, obtained an exclusive @@ -1161,7 +1182,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) { if (null != manifestLock) { - updateCoordinationServiceNode(job); + updateCoordinationServiceManifestNode(job); } } catch (CoordinationServiceException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifest.getFilePath()), ex); @@ -1186,9 +1207,9 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ private void addNewPendingJob(Manifest manifest) throws InterruptedException, AutoIngestJobException { /* - * Create the coordination service node data for the job. Note that - * getting the lock will create the node for the job (with no data) - * if it does not already exist. + * Create the coordination service manifest node data for the job. + * Note that getting the lock will create the node for the job (with + * no data) if it does not already exist. * * An exclusive lock is obtained before creating the node data * because another host may have already found the job, obtained an @@ -1202,7 +1223,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) { if (null != manifestLock) { AutoIngestJob job = new AutoIngestJob(manifest); - updateCoordinationServiceNode(job); + updateCoordinationServiceManifestNode(job); newPendingJobsList.add(job); } } catch (CoordinationServiceException ex) { @@ -1218,15 +1239,17 @@ public final class AutoIngestManager extends Observable implements PropertyChang * the node that was processing the job crashed and the processing * status was not updated. * - * @param manifest The manifest for upgrading the node. - * @param nodeData The node data. + * @param manifest The manifest for upgrading the node. + * @param jobNodeData The auto ingest job node data. * - * @throws InterruptedException if the thread running the input - * directory scan task is interrupted while - * blocked, i.e., if auto ingest is - * shutting down. + * @throws InterruptedException if the thread running the input + * directory scan task is interrupted + * while blocked, i.e., if auto ingest is + * shutting down. + * @throws AutoIngestJobException if there is an issue creating a new + * AutoIngestJob object. */ - private void doRecoveryIfCrashed(Manifest manifest, AutoIngestJobNodeData nodeData) throws InterruptedException, AutoIngestJobException { + private void doRecoveryIfCrashed(Manifest manifest, AutoIngestJobNodeData jobNodeData) throws InterruptedException, AutoIngestJobException { /* * Try to get an exclusive lock on the coordination service node for * the job. If the lock cannot be obtained, another host in the auto @@ -1237,48 +1260,35 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (null != manifestLock) { SYS_LOGGER.log(Level.SEVERE, "Attempting crash recovery for {0}", manifestPath); try { + Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName()); + /* * Create the recovery job. */ - AutoIngestJob job = new AutoIngestJob(nodeData); + AutoIngestJob job = new AutoIngestJob(jobNodeData); int numberOfCrashes = job.getNumberOfCrashes(); - ++numberOfCrashes; - job.setNumberOfCrashes(numberOfCrashes); - job.setCompletedDate(new Date(0)); - Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName()); + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { + ++numberOfCrashes; + job.setNumberOfCrashes(numberOfCrashes); + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { + job.setCompletedDate(new Date(0)); + } else { + job.setCompletedDate(Date.from(Instant.now())); + } + } + if (null != caseDirectoryPath) { job.setCaseDirectoryPath(caseDirectoryPath); job.setErrorsOccurred(true); + try { + setCaseNodeDataErrorsOccurred(caseDirectoryPath); + } catch (CaseNodeData.InvalidDataException ex) { + SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to get case node data for %s", caseDirectoryPath), ex); + } } else { job.setErrorsOccurred(false); } - /* - * Update the coordination service node for the job. If - * this fails, leave the recovery to another host. - */ - try { - updateCoordinationServiceNode(job); - if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { - newPendingJobsList.add(job); - } else { - newCompletedJobsList.add(new AutoIngestJob(nodeData)); - } - } catch (CoordinationServiceException ex) { - SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifestPath), ex); - return; - } - - /* - * Write the alert file and do the logging. - */ - if (null != caseDirectoryPath) { - try { - AutoIngestAlertFile.create(nodeData.getCaseDirectoryPath()); - } catch (AutoIngestAlertFileException ex) { - SYS_LOGGER.log(Level.SEVERE, String.format("Error creating alert file for crashed job for %s", manifestPath), ex); - } - } if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { job.setProcessingStatus(AutoIngestJob.ProcessingStatus.PENDING); if (null != caseDirectoryPath) { @@ -1292,13 +1302,32 @@ public final class AutoIngestManager extends Observable implements PropertyChang job.setProcessingStatus(AutoIngestJob.ProcessingStatus.COMPLETED); if (null != caseDirectoryPath) { try { - new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), nodeData.getCaseDirectoryPath()).logCrashRecoveryNoRetry(); + new AutoIngestJobLogger(manifest.getFilePath(), manifest.getDataSourceFileName(), caseDirectoryPath).logCrashRecoveryNoRetry(); } catch (AutoIngestJobLoggerException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error creating case auto ingest log entry for crashed job for %s", manifestPath), ex); } } } + /* + * Update the coordination service node for the job. If + * this fails, leave the recovery to another host. + */ + try { + updateCoordinationServiceManifestNode(job); + } catch (CoordinationServiceException ex) { + SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifestPath), ex); + return; + } + + jobNodeData = new AutoIngestJobNodeData(job); + + if (numberOfCrashes <= AutoIngestUserPreferences.getMaxNumTimesToProcessImage()) { + newPendingJobsList.add(job); + } else { + newCompletedJobsList.add(new AutoIngestJob(jobNodeData)); + } + } finally { try { manifestLock.release(); @@ -1352,15 +1381,15 @@ public final class AutoIngestManager extends Observable implements PropertyChang job.setProcessingStatus(AutoIngestJob.ProcessingStatus.COMPLETED); /* - * Try to upgrade/update the coordination service node data - * for the job. It is possible that two hosts will both try - * to obtain the lock to do the upgrade operation at the - * same time. If this happens, the host that is holding the - * lock will complete the upgrade operation. + * Try to upgrade/update the coordination service manifest + * node data for the job. It is possible that two hosts will + * both try to obtain the lock to do the upgrade operation + * at the same time. If this happens, the host that is + * holding the lock will complete the upgrade operation. */ try (Lock manifestLock = coordinationService.tryGetExclusiveLock(CoordinationService.CategoryNode.MANIFESTS, manifest.getFilePath().toString())) { if (null != manifestLock) { - updateCoordinationServiceNode(job); + updateCoordinationServiceManifestNode(job); } } catch (CoordinationServiceException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to set node data for %s", manifest.getFilePath()), ex); @@ -1507,8 +1536,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang errorState = ErrorState.ANALYSIS_STARTUP_ERROR; } else if (ex instanceof FileExportException) { errorState = ErrorState.FILE_EXPORT_ERROR; - } else if (ex instanceof AutoIngestAlertFileException) { - errorState = ErrorState.ALERT_FILE_ERROR; } else if (ex instanceof AutoIngestJobLoggerException) { errorState = ErrorState.JOB_LOGGER_ERROR; } else if (ex instanceof AutoIngestDataSourceProcessorException) { @@ -1691,9 +1718,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * @throws FileExportException if there is an * error exporting * files. - * @throws AutoIngestAlertFileException if there is an - * error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an * error writing to * the auto ingest @@ -1710,7 +1734,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * auto ingest node * data objects. */ - private void processJobs() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, AutoIngestJobNodeData.InvalidDataException { + private void processJobs() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, AutoIngestJobNodeData.InvalidDataException, CaseNodeData.InvalidDataException { SYS_LOGGER.log(Level.INFO, "Started processing pending jobs queue"); Lock manifestLock = JobProcessingTask.this.dequeueAndLockNextJob(); while (null != manifestLock) { @@ -1890,9 +1914,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * @throws FileExportException if there is an * error exporting * files. - * @throws AutoIngestAlertFileException if there is an - * error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an * error writing to * the auto ingest @@ -1909,13 +1930,13 @@ public final class AutoIngestManager extends Observable implements PropertyChang * auto ingest node * data objects. */ - private void processJob() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, AutoIngestJobNodeData.InvalidDataException { + private void processJob() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException { Path manifestPath = currentJob.getManifest().getFilePath(); SYS_LOGGER.log(Level.INFO, "Started processing of {0}", manifestPath); currentJob.setProcessingStatus(AutoIngestJob.ProcessingStatus.PROCESSING); currentJob.setProcessingStage(AutoIngestJob.Stage.STARTING, Date.from(Instant.now())); currentJob.setProcessingHostName(AutoIngestManager.LOCAL_HOST_NAME); - updateCoordinationServiceNode(currentJob); + updateCoordinationServiceManifestNode(currentJob); setChanged(); notifyObservers(Event.JOB_STARTED); eventPublisher.publishRemotely(new AutoIngestJobStartedEvent(currentJob)); @@ -1939,14 +1960,14 @@ public final class AutoIngestManager extends Observable implements PropertyChang currentJob.setProcessingStatus(AutoIngestJob.ProcessingStatus.PENDING); } currentJob.setProcessingHostName(""); - updateCoordinationServiceNode(currentJob); + updateCoordinationServiceManifestNode(currentJob); boolean retry = (!currentJob.isCanceled() && !currentJob.isCompleted()); SYS_LOGGER.log(Level.INFO, "Completed processing of {0}, retry = {1}", new Object[]{manifestPath, retry}); if (currentJob.isCanceled()) { Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); if (null != caseDirectoryPath) { - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, currentJob.getManifest().getDataSourceFileName(), caseDirectoryPath); jobLogger.logJobCancelled(); } @@ -1994,7 +2015,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * i.e., if auto ingest is * shutting down. */ - private void attemptJob() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException { + private void attemptJob() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException { updateConfiguration(); if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) { return; @@ -2115,7 +2136,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang Case.openAsCurrentCase(metadataFilePath.toString()); } else { caseDirectoryPath = PathUtils.createCaseFolderPath(rootOutputDirectory, caseName); - Case.createAsCurrentCase(caseDirectoryPath.toString(), caseName, "", "", CaseType.MULTI_USER_CASE); + CaseDetails caseDetails = new CaseDetails(caseName); + Case.createAsCurrentCase(CaseType.MULTI_USER_CASE, caseDirectoryPath.toString(), caseDetails); /* * Sleep a bit before releasing the lock to ensure * that the new case folder is visible on the @@ -2158,8 +2180,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * level ingest modules. * @throws FileExportException if there is an error exporting * files. - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2168,7 +2188,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void runIngestForJob(Case caseForJob) throws CoordinationServiceException, AnalysisStartupException, FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException { + private void runIngestForJob(Case caseForJob) throws CoordinationServiceException, AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException { try { if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) { return; @@ -2196,8 +2216,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * level ingest modules. * @throws FileExportException if there is an error exporting * files. - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2206,12 +2224,12 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void ingestDataSource(Case caseForJob) throws AnalysisStartupException, FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException { + private void ingestDataSource(Case caseForJob) throws AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException, CoordinationServiceException { if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) { return; } - DataSource dataSource = identifyDataSource(); + AutoIngestDataSource dataSource = identifyDataSource(); if (null == dataSource) { currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now())); return; @@ -2254,8 +2272,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * * @return A data source object. * - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2264,7 +2280,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * interrupted while blocked, i.e., * if auto ingest is shutting down. */ - private DataSource identifyDataSource() throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private AutoIngestDataSource identifyDataSource() throws AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Identifying data source for {0} ", manifestPath); @@ -2276,22 +2292,20 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (!dataSource.exists()) { SYS_LOGGER.log(Level.SEVERE, "Missing data source for {0}", manifestPath); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logMissingDataSource(); return null; } String deviceId = manifest.getDeviceId(); - return new DataSource(deviceId, dataSourcePath); + return new AutoIngestDataSource(deviceId, dataSourcePath); } - + /** * Passes the data source for the current job through a data source * processor that adds it to the case database. * * @param dataSource The data source. * - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2300,23 +2314,20 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void runDataSourceProcessor(Case caseForJob, DataSource dataSource) throws InterruptedException, AutoIngestAlertFileException, AutoIngestJobLoggerException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException { + private void runDataSourceProcessor(Case caseForJob, AutoIngestDataSource dataSource) throws InterruptedException, AutoIngestJobLoggerException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath); currentJob.setProcessingStage(AutoIngestJob.Stage.ADDING_DATA_SOURCE, Date.from(Instant.now())); - UUID taskId = UUID.randomUUID(); - DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock); DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor(); Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath); try { - caseForJob.notifyAddingDataSource(taskId); - Map validDataSourceProcessorsMap; + // Get an ordered list of data source processors to try + List validDataSourceProcessors; try { - // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source - validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(dataSource.getPath()); + validDataSourceProcessors = DataSourceProcessorUtility.getOrderedListOfDataSourceProcessors(dataSource.getPath()); } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { SYS_LOGGER.log(Level.SEVERE, "Exception while determining best data source processor for {0}", dataSource.getPath()); // rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause. @@ -2324,24 +2335,22 @@ public final class AutoIngestManager extends Observable implements PropertyChang } // did we find a data source processor that can process the data source - if (validDataSourceProcessorsMap.isEmpty()) { + if (validDataSourceProcessors.isEmpty()) { // This should never happen. We should add all unsupported data sources as logical files. - AutoIngestAlertFile.create(caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); currentJob.setErrorsOccurred(true); jobLogger.logFailedToIdentifyDataSource(); SYS_LOGGER.log(Level.WARNING, "Unsupported data source {0} for {1}", new Object[]{dataSource.getPath(), manifestPath}); // NON-NLS return; } - // Get an ordered list of data source processors to try - List validDataSourceProcessors = validDataSourceProcessorsMap.entrySet().stream() - .sorted(Map.Entry.comparingByValue().reversed()) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); - synchronized (ingestLock) { // Try each DSP in decreasing order of confidence for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { + UUID taskId = UUID.randomUUID(); + caseForJob.notifyAddingDataSource(taskId); + DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock); + caseForJob.notifyAddingDataSource(taskId); jobLogger.logDataSourceProcessorSelected(selectedProcessor.getDataSourceType()); SYS_LOGGER.log(Level.INFO, "Identified data source type for {0} as {1}", new Object[]{manifestPath, selectedProcessor.getDataSourceType()}); try { @@ -2352,7 +2361,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang // Log that the current DSP failed and set the error flag. We consider it an error // if a DSP fails even if a later one succeeds since we expected to be able to process // the data source which each DSP on the list. - AutoIngestAlertFile.create(caseDirectoryPath); + setCaseNodeDataErrorsOccurred(caseDirectoryPath); currentJob.setErrorsOccurred(true); jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType()); SYS_LOGGER.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()}); @@ -2376,8 +2385,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * * @param dataSource The data source. * - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2386,7 +2393,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void logDataSourceProcessorResult(DataSource dataSource) throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private void logDataSourceProcessorResult(AutoIngestDataSource dataSource) throws AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); @@ -2398,7 +2405,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang jobLogger.logDataSourceAdded(); if (dataSource.getContent().isEmpty()) { currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logNoDataSourceContent(); } break; @@ -2410,7 +2417,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang jobLogger.logDataSourceAdded(); if (dataSource.getContent().isEmpty()) { currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logNoDataSourceContent(); } break; @@ -2420,7 +2427,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang SYS_LOGGER.log(Level.SEVERE, "Critical error running data source processor for {0}: {1}", new Object[]{manifestPath, errorMessage}); } currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logFailedToAddDataSource(); break; } @@ -2434,7 +2441,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ SYS_LOGGER.log(Level.WARNING, "Cancellation while waiting for data source processor for {0}", manifestPath); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logDataSourceProcessorCancelled(); } } @@ -2448,8 +2455,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * * @throws AnalysisStartupException if there is an error analyzing * the data source. - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2458,7 +2463,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void analyze(DataSource dataSource) throws AnalysisStartupException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private void analyze(AutoIngestDataSource dataSource) throws AnalysisStartupException, AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Starting ingest modules analysis for {0} ", manifestPath); @@ -2490,7 +2495,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang if (!cancelledModules.isEmpty()) { SYS_LOGGER.log(Level.WARNING, String.format("Ingest module(s) cancelled for %s", manifestPath)); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); for (String module : snapshot.getCancelledDataSourceIngestModules()) { SYS_LOGGER.log(Level.WARNING, String.format("%s ingest module cancelled for %s", module, manifestPath)); jobLogger.logIngestModuleCancelled(module); @@ -2500,7 +2505,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang } else { currentJob.setProcessingStage(AutoIngestJob.Stage.CANCELLING, Date.from(Instant.now())); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logAnalysisCancelled(); CancellationReason cancellationReason = snapshot.getCancellationReason(); if (CancellationReason.NOT_CANCELLED != cancellationReason && CancellationReason.USER_CANCELLED != cancellationReason) { @@ -2513,13 +2518,13 @@ public final class AutoIngestManager extends Observable implements PropertyChang SYS_LOGGER.log(Level.SEVERE, String.format("%s ingest module startup error for %s", error.getModuleDisplayName(), manifestPath), error.getThrowable()); } currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logIngestModuleStartupErrors(); throw new AnalysisStartupException(String.format("Error(s) during ingest module startup for %s", manifestPath)); } else { SYS_LOGGER.log(Level.SEVERE, String.format("Ingest manager ingest job start error for %s", manifestPath), ingestJobStartResult.getStartupException()); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logAnalysisStartupError(); throw new AnalysisStartupException("Ingest manager error starting job", ingestJobStartResult.getStartupException()); } @@ -2528,7 +2533,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang SYS_LOGGER.log(Level.SEVERE, "Ingest job settings error for {0}: {1}", new Object[]{manifestPath, warning}); } currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logIngestJobSettingsErrors(); throw new AnalysisStartupException("Error(s) in ingest job settings"); } @@ -2547,8 +2552,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang * * @throws FileExportException if there is an error exporting * the files. - * @throws AutoIngestAlertFileException if there is an error creating an - * alert file. * @throws AutoIngestJobLoggerException if there is an error writing to * the auto ingest log for the * case. @@ -2557,7 +2560,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * while blocked, i.e., if auto * ingest is shutting down. */ - private void exportFiles(DataSource dataSource) throws FileExportException, AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private void exportFiles(AutoIngestDataSource dataSource) throws FileExportException, AutoIngestJobLoggerException, InterruptedException, CaseNodeData.InvalidDataException, CoordinationServiceException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Exporting files for {0}", manifestPath); @@ -2573,11 +2576,11 @@ public final class AutoIngestManager extends Observable implements PropertyChang } catch (FileExportException ex) { SYS_LOGGER.log(Level.SEVERE, String.format("Error doing file export for %s", manifestPath), ex); currentJob.setErrorsOccurred(true); - AutoIngestAlertFile.create(caseDirectoryPath); // Do this first, it is more important than the case log + setCaseNodeDataErrorsOccurred(caseDirectoryPath); jobLogger.logFileExportError(); } } - + /** * A data source processor progress monitor does nothing. There is * currently no mechanism for showing or recording data source processor @@ -2739,7 +2742,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang currentJob.getProcessingStageDetails(); setChanged(); notifyObservers(Event.JOB_STATUS_UPDATED); - updateCoordinationServiceNode(currentJob); + updateCoordinationServiceManifestNode(currentJob); eventPublisher.publishRemotely(new AutoIngestJobStatusEvent(currentJob)); } @@ -2842,7 +2845,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang CASE_MANAGEMENT_ERROR("Case management error"), ANALYSIS_STARTUP_ERROR("Analysis startup error"), FILE_EXPORT_ERROR("File export error"), - ALERT_FILE_ERROR("Alert file error"), JOB_LOGGER_ERROR("Job logger error"), DATA_SOURCE_PROCESSOR_ERROR("Data source processor error"), UNEXPECTED_EXCEPTION("Unknown error"); @@ -2917,7 +2919,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang PARTIALLY_DELETED, FULLY_DELETED } - + static final class AutoIngestManagerException extends Exception { private static final long serialVersionUID = 1L; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java new file mode 100755 index 0000000000..9567b70470 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java @@ -0,0 +1,160 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ArrayList; +import java.util.List; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * Collects metrics for an auto ingest cluster. + */ +final class AutoIngestMetricsCollector { + + private static final Logger LOGGER = Logger.getLogger(AutoIngestMetricsCollector.class.getName()); + private CoordinationService coordinationService; + + /** + * Creates an instance of the AutoIngestMetricsCollector. + * + * @throws AutoIngestMetricsCollector.AutoIngestMetricsCollectorException + */ + AutoIngestMetricsCollector() throws AutoIngestMetricsCollectorException { + try { + coordinationService = CoordinationService.getInstance(); + } catch (CoordinationServiceException ex) { + throw new AutoIngestMetricsCollectorException("Failed to get coordination service", ex); //NON-NLS + } + } + + /** + * Gets a new metrics snapshot from the coordination service for an auto + * ingest cluster. + * + * @return The metrics snapshot. + */ + MetricsSnapshot queryCoordinationServiceForMetrics() { + try { + MetricsSnapshot newMetricsSnapshot = new MetricsSnapshot(); + List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.MANIFESTS); + for (String node : nodeList) { + try { + AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, node)); + if (nodeData.getVersion() < 1) { + /* + * Ignore version '0' nodes that have not been + * "upgraded" since they don't carry enough data. + */ + continue; + } + AutoIngestJob job = new AutoIngestJob(nodeData); + AutoIngestJob.ProcessingStatus processingStatus = nodeData.getProcessingStatus(); + switch (processingStatus) { + case PENDING: + case PROCESSING: + case DELETED: + /* + * These are not jobs we care about for metrics, so + * we will ignore them. + */ + break; + case COMPLETED: + newMetricsSnapshot.addCompletedJobDate(job.getCompletedDate()); + break; + default: + LOGGER.log(Level.SEVERE, "Unknown AutoIngestJobData.ProcessingStatus"); + break; + } + } catch (InterruptedException ex) { + LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex); + } catch (AutoIngestJobNodeData.InvalidDataException ex) { + LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex); + } catch (AutoIngestJob.AutoIngestJobException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to create a job for '%s'", node), ex); + } + } + + return newMetricsSnapshot; + + } catch (CoordinationService.CoordinationServiceException ex) { + LOGGER.log(Level.SEVERE, "Failed to get node list from coordination service", ex); + return new MetricsSnapshot(); + } + } + + /** + * A snapshot of metrics for an auto ingest cluster. + */ + static final class MetricsSnapshot { + + private final List completedJobDates = new ArrayList<>(); + + /** + * Gets a list of completed job dates, formatted in milliseconds. + * + * @return The completed job dates, formatted in milliseconds. + */ + List getCompletedJobDates() { + return new ArrayList<>(completedJobDates); + } + + /** + * Adds a new date to the list of completed job dates. + * + * @param date The date to be added. + */ + void addCompletedJobDate(java.util.Date date) { + completedJobDates.add(date.getTime()); + } + } + + /** + * Exception type thrown when there is an error completing an auto ingest + * metrics collector operation. + */ + static final class AutoIngestMetricsCollectorException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing an auto ingest metrics collector operation. + * + * @param message The exception message. + */ + private AutoIngestMetricsCollectorException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing an auto ingest metrics collector operation. + * + * @param message The exception message. + * @param cause A Throwable cause for the error. + */ + private AutoIngestMetricsCollectorException(String message, Throwable cause) { + super(message, cause); + } + + } +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form new file mode 100755 index 0000000000..49e700ca21 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form @@ -0,0 +1,113 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java new file mode 100755 index 0000000000..80bcb6958b --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java @@ -0,0 +1,212 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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 com.github.lgooddatepicker.datepicker.DatePicker; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Window; +import java.sql.Date; +import java.text.SimpleDateFormat; +import java.time.ZoneOffset; +import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; + +/** + * Displays auto ingest metrics for a cluster. + */ +final class AutoIngestMetricsDialog extends javax.swing.JDialog { + + private final AutoIngestMetricsCollector autoIngestMetricsCollector; + + /** + * Creates an instance of AutoIngestMetricsDialog + * + * @param parent The parent container. + */ + @Messages({ + "AutoIngestMetricsDialog.title.text=Auto Ingest Cluster Metrics", + "AutoIngestMetricsDialog.initReportText=Select a date below and click the 'Get Metrics Since...' button to generate\na metrics report." + }) + AutoIngestMetricsDialog(Container parent) throws AutoIngestMetricsDialogException { + super((Window) parent, NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.title.text"), ModalityType.MODELESS); + try { + autoIngestMetricsCollector = new AutoIngestMetricsCollector(); + } catch (AutoIngestMetricsCollector.AutoIngestMetricsCollectorException ex) { + throw new AutoIngestMetricsDialogException("Error starting up the auto ingest metrics dialog.", ex); + } + initComponents(); + reportTextArea.setText(NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.initReportText")); + setModal(true); + setSize(getPreferredSize()); + setLocationRelativeTo(parent); + setVisible(true); + } + + /** + * Update the metrics shown in the report text area. + */ + private void updateMetrics() { + if(datePicker.getDate() == null) { + return; + } + + AutoIngestMetricsCollector.MetricsSnapshot metricsSnapshot = autoIngestMetricsCollector.queryCoordinationServiceForMetrics(); + Object[] completedJobDates = metricsSnapshot.getCompletedJobDates().toArray(); + int count = 0; + long pickedDate = datePicker.getDate().atStartOfDay().toEpochSecond(ZoneOffset.UTC) * 1000; + for(int i = completedJobDates.length - 1; i >= 0; i--) { + if((Long)completedJobDates[i] >= pickedDate) { + count++; + } + } + + SimpleDateFormat dateFormatter = new SimpleDateFormat("MMM d, yyyy"); + reportTextArea.setText(String.format( + "Since %s:\n" + + "\tNumber of Jobs Completed: %d\n", + dateFormatter.format(Date.valueOf(datePicker.getDate())), + count + )); + } + + /** + * Exception type thrown when there is an error completing an auto ingest + * metrics dialog operation. + */ + static final class AutoIngestMetricsDialogException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing an auto ingest metrics dialog operation. + * + * @param message The exception message. + */ + private AutoIngestMetricsDialogException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception type thrown when there is an + * error completing an auto ingest metrics dialog operation. + * + * @param message The exception message. + * @param cause A Throwable cause for the error. + */ + private AutoIngestMetricsDialogException(String message, Throwable cause) { + super(message, cause); + } + + } + + /** + * 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() { + + closeButton = new javax.swing.JButton(); + jScrollPane1 = new javax.swing.JScrollPane(); + reportTextArea = new javax.swing.JTextArea(); + metricsButton = new javax.swing.JButton(); + datePicker = new DatePicker(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setAlwaysOnTop(true); + setResizable(false); + + org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.closeButton.text")); // NOI18N + closeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + closeButtonActionPerformed(evt); + } + }); + + reportTextArea.setEditable(false); + reportTextArea.setColumns(20); + reportTextArea.setRows(5); + reportTextArea.setText(org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.reportTextArea.text")); // NOI18N + jScrollPane1.setViewportView(reportTextArea); + + org.openide.awt.Mnemonics.setLocalizedText(metricsButton, org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.metricsButton.text")); // NOI18N + metricsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + metricsButtonActionPerformed(evt); + } + }); + + datePicker.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.datePicker.toolTipText")); // NOI18N + + 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(jScrollPane1) + .addGroup(layout.createSequentialGroup() + .addComponent(metricsButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 33, Short.MAX_VALUE) + .addComponent(closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(closeButton) + .addComponent(metricsButton)) + .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed + setVisible(false); + dispose(); + }//GEN-LAST:event_closeButtonActionPerformed + + private void metricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_metricsButtonActionPerformed + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + updateMetrics(); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + }//GEN-LAST:event_metricsButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton closeButton; + private com.github.lgooddatepicker.datepicker.DatePicker datePicker; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JButton metricsButton; + private javax.swing.JTextArea reportTextArea; + // End of variables declaration//GEN-END:variables +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java index 9a262bb6d3..e46a5e43c0 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMonitor.java @@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.ProcessingSta * An auto ingest monitor responsible for monitoring and reporting the * processing of auto ingest jobs. */ -public final class AutoIngestMonitor extends Observable implements PropertyChangeListener { +final class AutoIngestMonitor extends Observable implements PropertyChangeListener { private static final Logger LOGGER = Logger.getLogger(AutoIngestMonitor.class.getName()); private static final int NUM_COORD_SVC_QUERY_THREADS = 1; @@ -265,11 +265,15 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang } } catch (InterruptedException ex) { LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex); - } catch (AutoIngestJobNodeData.InvalidDataException | AutoIngestJob.AutoIngestJobException ex) { + } catch (AutoIngestJobNodeData.InvalidDataException ex) { LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex); + } catch (AutoIngestJob.AutoIngestJobException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to create a job for '%s'", node), ex); } } + return newJobsSnapshot; + } catch (CoordinationServiceException ex) { LOGGER.log(Level.SEVERE, "Failed to get node list from coordination service", ex); return new JobsSnapshot(); @@ -552,4 +556,4 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang } } -} +} \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java new file mode 100644 index 0000000000..31ecd5f4ca --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestRowSorter.java @@ -0,0 +1,57 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.ArrayList; +import java.util.Date; +import javax.swing.RowSorter; +import javax.swing.SortOrder; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableRowSorter; + +/** + * RowSorter which makes columns whose type is Date to be sorted first in + * Descending order then in Ascending order + */ +class AutoIngestRowSorter extends TableRowSorter { + + AutoIngestRowSorter(M tModel) { + super(tModel); + } + + @Override + public void toggleSortOrder(int column) { + if (!this.getModel().getColumnClass(column).equals(Date.class) && !this.getModel().getColumnClass(column).equals(Integer.class)) { + //currently the only Integer column this sorter is being applied to is the Priority column + super.toggleSortOrder(column); //if it isn't a date or Integer column perform the regular sorting + } else { + ArrayList sortKeys = new ArrayList<>(getSortKeys()); + if (sortKeys.isEmpty() || sortKeys.get(0).getColumn() != column) { //sort descending + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.DESCENDING)); + } else if (sortKeys.get(0).getSortOrder() == SortOrder.ASCENDING) { + sortKeys.removeIf(key -> key.getColumn() == column); + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.DESCENDING)); + } else { + sortKeys.removeIf(key -> key.getColumn() == column); + sortKeys.add(0, new RowSorter.SortKey(column, SortOrder.ASCENDING)); + } + setSortKeys(sortKeys); + } + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index edac418672..5f335b1ba4 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -1,4 +1,3 @@ -CTL_OpenAction=Open Case... AutoIngestDashboard.lbCompleted.text=Completed Jobs AutoIngestDashboard.lbRunning.text=Running Jobs AutoIngestDashboard.lbPending.text=Pending Jobs @@ -47,14 +46,10 @@ OpenIDE-Module-Long-Description=\ We make no guarantee that the API of this module will not change, so developers should be careful when relying on it. OpenIDE-Module-Name=Experimental OpenIDE-Module-Short-Description=This module contains features that are being developed by Basis Technology and are not part of the default Autopsy distribution. -ReviewModeCasePanel.cannotOpenCase=Cannot Open Case -ReviewModeCasePanel.casePathNotFound=Case path not found -ReviewModeCasePanel.caseIsLocked=Single-user case is locked. DisplayLogDialog.cannotOpenLog=Unable to open the selected case log file DisplayLogDialog.cannotFindLog=Unable to find the selected case log file DisplayLogDialog.unableToShowLogFile=Unable to show log file DisplayLogDialog.okay=Okay -ReviewModeCasePanel.bnShowLog.text=&Show Log CopyFilesPanel.lbFrom.text=From Source CopyFilesPanel.lbTo.text=Destination Case CopyFilesPanel.bnCopy.text=&Copy @@ -128,8 +123,6 @@ CopyFilesPanel.cbThrottleNetwork.toolTipText=Select this box if a low-band CopyFilesPanel.bnShowCurrentLog.text=Show &Log CopyFilesPanel.bnShowCurrentLog.text=Show &Log CopyFilesPanel.lbCaseName.text=Case Name -CaseStatusIconCellRenderer.tooltiptext.ok=Images processed successfully -CaseStatusIconCellRenderer.tooltiptext.warning=An error occurred or processing was canceled for at least one image - please check the log OptionsCategory_Name_Case_Import=Case Import OptionsCategory_Keywords_Case_Import=Case Import Settings CaseImportPanel.validationErrMsg.MUdisabled=Multi user settings must be enabled and saved @@ -165,11 +158,6 @@ SingleUserCaseImporter.FailedToComplete=Failed to complete processing of SingleUserCaseImporter.CompletedBatch=Completed batch processing of SingleUserCaseImporter.AbortingBatch=Aborting batch processing of SingleUserCaseImporter.SourceImageMissing=. Source image missing for -ReviewModeCasePanel.CaseHeaderText=Case -ReviewModeCasePanel.CreatedTimeHeaderText=Created Time -ReviewModeCasePanel.StatusIconHeaderText=Status -ReviewModeCasePanel.OutputFolderHeaderText=Output Folder -ReviewModeCasePanel.LastAccessedTimeHeaderText=Last Accessed Time CopyFilesPanel.bnOptions.text=&Options AutoIngestDashboard.lbServicesStatus.text=Services Status: AutoIngestDashboard.tbServicesStatusMessage.text=Connecting... @@ -231,15 +219,6 @@ FileExporterSettingsPanel.BrowseReportTooltip_1=Browse for the Reports Folder FileExporterSettingsPanel.NewRuleTooltip_1=Clear the rule editor to begin a new rule FileExporterSettingsPanel.DeleteTooltip_1=Delete the selected rule FileExporterSettingsPanel.SaveTooltip_1=Save the current rule -AutoIngestCasePanel.rbDays.text=Days -AutoIngestCasePanel.rbWeeks.text=Weeks -AutoIngestCasePanel.rbMonths.text=Months -AutoIngestCasePanel.rbAllCases.text=Everything -AutoIngestCasePanel.bnRefresh.text=&Refresh -AutoIngestCasePanel.bnOpen.text=&Open -AutoIngestCasePanel.bnShowLog.toolTipText=Display case log file for selected case -AutoIngestCasePanel.bnShowLog.text=&Show Log -AutoIngestCasePanel.rbGroupLabel.text=Show cases accessed in the last 10: AutoIngestDashboard.refreshButton.toolTipText=Refresh displayed tables AutoIngestDashboard.refreshButton.text=&Refresh AutoIngestDashboard.jButton1.text=jButton1 @@ -247,6 +226,11 @@ AutoIngestDashboard.prioritizeJobButton.toolTipText=Move the selected job to the AutoIngestDashboard.prioritizeJobButton.text=Prioritize &Job AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue. AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case +AutoIngestMetricsDialog.reportTextArea.text= +AutoIngestDashboard.clusterMetricsButton.text=Cluster Metrics +AutoIngestMetricsDialog.metricsButton.text=Get Metrics Since... +AutoIngestMetricsDialog.closeButton.text=Close +AutoIngestMetricsDialog.datePicker.toolTipText=Choose a date ArchiveFilePanel.pathLabel.text=Browse for an archive file: ArchiveFilePanel.browseButton.text=Browse ArchiveFilePanel.pathTextField.text= diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java index a7cd13af72..2e4866b010 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseImportPanel.java @@ -672,7 +672,6 @@ public class CaseImportPanel extends javax.swing.JPanel implements ImportDoneCal */ private void enableStartButton() { if (UserPreferences.getIsMultiUserModeEnabled() - && AutoIngestUserPreferences.getJoinAutoModeCluster() && (! RuntimeProperties.runningWithGUI()) && !tbCaseSource.getText().isEmpty() && !tbCaseDestination.getText().isEmpty() diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java index 6f88d70a28..4878f7fa7d 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java @@ -21,7 +21,9 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.openide.util.Lookup; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException; @@ -30,8 +32,8 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor. * A utility class to find Data Source Processors */ class DataSourceProcessorUtility { - - private DataSourceProcessorUtility() { + + private DataSourceProcessorUtility() { } /** @@ -45,11 +47,7 @@ class DataSourceProcessorUtility { * @throws * org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException */ - static Map getDataSourceProcessor(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { - - // lookup all AutomatedIngestDataSourceProcessors - Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); - + static Map getDataSourceProcessorForFile(Path dataSourcePath, Collection processorCandidates) throws AutoIngestDataSourceProcessorException { Map validDataSourceProcessorsMap = new HashMap<>(); for (AutoIngestDataSourceProcessor processor : processorCandidates) { int confidence = processor.canProcess(dataSourcePath); @@ -60,4 +58,64 @@ class DataSourceProcessorUtility { return validDataSourceProcessorsMap; } + + /** + * A utility method to find all Data Source Processors (DSP) that are able + * to process the input data source. Only the DSPs that implement + * AutoIngestDataSourceProcessor interface are used. Returns ordered list of + * data source processors. DSPs are ordered in descending order from highest + * confidence to lowest. + * + * @param dataSourcePath Full path to the data source + * + * @return Ordered list of data source processors. DSPs are ordered in + * descending order from highest confidence to lowest. + * + * @throws + * org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException + */ + static List getOrderedListOfDataSourceProcessors(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { + // lookup all AutomatedIngestDataSourceProcessors + Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); + return getOrderedListOfDataSourceProcessors(dataSourcePath, processorCandidates); + } + + /** + * A utility method to find all Data Source Processors (DSP) that are able + * to process the input data source. Only the DSPs that implement + * AutoIngestDataSourceProcessor interface are used. Returns ordered list of + * data source processors. DSPs are ordered in descending order from highest + * confidence to lowest. + * + * @param dataSourcePath Full path to the data source + * @param processorCandidates Collection of AutoIngestDataSourceProcessor objects to use + * + * @return Ordered list of data source processors. DSPs are ordered in + * descending order from highest confidence to lowest. + * + * @throws + * org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException + */ + static List getOrderedListOfDataSourceProcessors(Path dataSourcePath, Collection processorCandidates) throws AutoIngestDataSourceProcessorException { + Map validDataSourceProcessorsMap = getDataSourceProcessorForFile(dataSourcePath, processorCandidates); + return orderDataSourceProcessorsByConfidence(validDataSourceProcessorsMap); + } + + + /** + * A utility method to get an ordered list of data source processors. DSPs + * are ordered in descending order from highest confidence to lowest. + * + * @param validDataSourceProcessorsMap Hash map of all DSPs that can process + * the data source along with their confidence score + * @return Ordered list of data source processors + */ + static List orderDataSourceProcessorsByConfidence(Map validDataSourceProcessorsMap) { + List validDataSourceProcessors = validDataSourceProcessorsMap.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + + return validDataSourceProcessors; + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java index 18ce9709d5..a7d5675883 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.sleuthkit.autopsy.casemodule.CaseMetadata; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; final class PathUtils { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java old mode 100755 new mode 100644 similarity index 61% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java rename to Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java index 0010cc90ee..a4066e6c15 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CaseStatusIconCellRenderer.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizedIconCellRenderer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,27 +23,34 @@ import javax.swing.ImageIcon; import javax.swing.JTable; import static javax.swing.SwingConstants.CENTER; import org.openide.util.ImageUtilities; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.guiutils.GrayableCellRenderer; +import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; /** - * A JTable cell renderer that represents an auto ingest alert file exists flag - * as a center-aligned icon, and grays out the cell if the table is disabled. + * A JTable cell renderer that represents whether the priority value of a job + * has ever been increased, tick if prioritized nothing if not. */ -class CaseStatusIconCellRenderer extends GrayableCellRenderer { +class PrioritizedIconCellRenderer extends GrayableCellRenderer { + + @Messages({ + "PrioritizedIconCellRenderer.prioritized.tooltiptext=This job has been prioritized. The most recently prioritized job should be processed next.", + "PrioritizedIconCellRenderer.notPrioritized.tooltiptext=This job has not been prioritized." + }) private static final long serialVersionUID = 1L; static final ImageIcon checkedIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/tick.png", false)); - static final ImageIcon warningIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/warning16.png", false)); @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setHorizontalAlignment(CENTER); - if ((value instanceof Boolean)) { - if (true == (Boolean) value) { - setIcon(warningIcon); - setToolTipText(org.openide.util.NbBundle.getMessage(CaseStatusIconCellRenderer.class, "CaseStatusIconCellRenderer.tooltiptext.warning")); + if ((value instanceof Integer)) { + if ((int) value == 0) { + setIcon(null); + setToolTipText(org.openide.util.NbBundle.getMessage(PrioritizedIconCellRenderer.class, "PrioritizedIconCellRenderer.notPrioritized.tooltiptext")); } else { setIcon(checkedIcon); - setToolTipText(org.openide.util.NbBundle.getMessage(CaseStatusIconCellRenderer.class, "CaseStatusIconCellRenderer.tooltiptext.ok")); + setToolTipText(org.openide.util.NbBundle.getMessage(PrioritizedIconCellRenderer.class, "PrioritizedIconCellRenderer.prioritized.tooltiptext")); } } grayCellIfTableNotEnabled(table, isSelected); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java index e04399d321..3a5c45632f 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/SingleUserCaseImporter.java @@ -47,6 +47,7 @@ import org.sleuthkit.autopsy.casemodule.SingleUserCaseConverter; import org.sleuthkit.autopsy.casemodule.SingleUserCaseConverter.ImportCaseData; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.NetworkUtils; +import org.sleuthkit.autopsy.coreutils.TimeStampUtils; public class SingleUserCaseImporter implements Runnable { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml index 56ad444eb0..ced44d8569 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/layer.xml @@ -2,20 +2,6 @@ - - - - - - - - - - - - @@ -23,19 +9,12 @@ - - - - - - - - + - + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form index 20c8c7a981..68002e8055 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.form @@ -1,10 +1,6 @@
- - - - @@ -56,18 +52,71 @@ - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -79,542 +128,65 @@ - - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -649,6 +221,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java index 4877ce9d60..58f68f3b54 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.experimental.configuration; import java.awt.BorderLayout; +import java.awt.Cursor; import java.io.File; import java.nio.file.Files; import java.util.List; @@ -56,7 +57,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { enum OptionsUiMode { - STANDALONE, AIM, REVIEW, DOWNLOADING_CONFIGURATION + STANDALONE, AIM, DOWNLOADING_CONFIGURATION }; /** @@ -127,21 +128,10 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { if (inStartup) { UserPreferences.SelectedMode storedMode = UserPreferences.getMode(); inputPathTextField.requestFocusInWindow(); - if (null != storedMode) { - switch (storedMode) { - case REVIEW: - jRadioButtonReview.setSelected(true); - enableOptionsBasedOnMode(OptionsUiMode.REVIEW); - break; - case AUTOINGEST: - jRadioButtonAutomated.setSelected(true); - enableOptionsBasedOnMode(OptionsUiMode.AIM); - break; - default: - cbJoinAutoIngestCluster.setSelected(false); - enableOptionsBasedOnMode(OptionsUiMode.STANDALONE); - break; - } + if (storedMode == UserPreferences.SelectedMode.AUTOINGEST) { + enableOptionsBasedOnMode(OptionsUiMode.AIM); + } else if (storedMode != null) { + enableOptionsBasedOnMode(OptionsUiMode.STANDALONE); } } @@ -207,22 +197,12 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { * Save mode to persistent storage. */ void store() { - boolean needsRestart = false; - UserPreferences.SelectedMode storedMode = UserPreferences.getMode(); - + boolean needsRestart = (cbJoinAutoIngestCluster.isSelected() != AutoIngestUserPreferences.getJoinAutoModeCluster()); + AutoIngestUserPreferences.setJoinAutoModeCluster(cbJoinAutoIngestCluster.isSelected()); if (!cbJoinAutoIngestCluster.isSelected()) { - if(storedMode == UserPreferences.SelectedMode.AUTOINGEST) { - needsRestart = true; - } - UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); - } - else if (jRadioButtonAutomated.isSelected()) { - if (storedMode == UserPreferences.SelectedMode.REVIEW) { - needsRestart = true; - } - + } else { UserPreferences.setMode(UserPreferences.SelectedMode.AUTOINGEST); String imageFolderPath = getNormalizedFolderPath(inputPathTextField.getText().trim()); AutoIngestUserPreferences.setAutoModeImageFolder(imageFolderPath); @@ -234,15 +214,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { AutoIngestUserPreferences.setSharedConfigFolder(globalSettingsPath); AutoIngestUserPreferences.setSharedConfigMaster(masterNodeCheckBox.isSelected()); } - } else if (jRadioButtonReview.isSelected()) { - if (storedMode == UserPreferences.SelectedMode.AUTOINGEST) { - needsRestart = true; - } - - UserPreferences.setMode(UserPreferences.SelectedMode.REVIEW); - String resultsFolderPath = getNormalizedFolderPath(outputPathTextField.getText().trim()); - AutoIngestUserPreferences.setAutoModeResultsFolder(resultsFolderPath); } + if (needsRestart) { SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(null, @@ -306,23 +279,14 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { configButtonErrorTextField.setText("Shared configuration folder is invalid"); } break; - case REVIEW: - jLabelInvalidImageFolder.setVisible(false); - if (!validateResultsPath()) { - isValidNodePanel = false; - } - break; - case STANDALONE: break; default: break; } - if (jRadioButtonAutomated.isSelected()) { - if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && !validSharedConfigSettings()) { - isValidNodePanel = false; - } + if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && !validSharedConfigSettings()) { + isValidNodePanel = false; } return isValidNodePanel; } @@ -550,7 +514,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } private void displayIngestJobSettingsPanel() { - + this.getParent().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + IngestJobSettings ingestJobSettings = new IngestJobSettings(AutoIngestUserPreferences.getAutoModeIngestModuleContextString()); showWarnings(ingestJobSettings); IngestJobSettingsPanel ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); @@ -563,6 +528,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { ingestJobSettings.save(); showWarnings(ingestJobSettings); } + + this.getParent().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } private static void showWarnings(IngestJobSettings ingestJobSettings) { @@ -579,24 +546,17 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private void enableOptionsBasedOnMode(OptionsUiMode mode) { if (mode != OptionsUiMode.DOWNLOADING_CONFIGURATION) { boolean nonMasterSharedConfig = !masterNodeCheckBox.isSelected() && sharedConfigCheckbox.isSelected(); - jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected()); - jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected()); - jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); inputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jLabelSelectOutputFolder.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); - outputPathTextField.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); - browseOutputFolderButton.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); + jLabelSelectOutputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + outputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + browseOutputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); - - jPanelIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnEditIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnAdvancedSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); bnLogging.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); sharedConfigCheckbox.setEnabled(mode == OptionsUiMode.AIM); masterNodeCheckBox.setEnabled(mode == OptionsUiMode.AIM && sharedConfigCheckbox.isSelected()); bnFileExport.setEnabled(mode == OptionsUiMode.AIM); @@ -613,14 +573,8 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private OptionsUiMode getModeFromRadioButtons() { if (!cbJoinAutoIngestCluster.isSelected()) { return OptionsUiMode.STANDALONE; - } - - if (jRadioButtonAutomated.isSelected()) { - return OptionsUiMode.AIM; - } else if (jRadioButtonReview.isSelected()) { - return OptionsUiMode.REVIEW; } else { - return OptionsUiMode.STANDALONE; + return OptionsUiMode.AIM; } } @@ -633,292 +587,51 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - modeRadioButtons = new javax.swing.ButtonGroup(); nodeScrollPane = new javax.swing.JScrollPane(); nodePanel = new javax.swing.JPanel(); - jPanelNodeType = new javax.swing.JPanel(); - jLabelSelectMode = new javax.swing.JLabel(); - jRadioButtonAutomated = new javax.swing.JRadioButton(); - jRadioButtonReview = new javax.swing.JRadioButton(); - jLabelSelectInputFolder = new javax.swing.JLabel(); - inputPathTextField = new javax.swing.JTextField(); - browseInputFolderButton = new javax.swing.JButton(); - jLabelSelectOutputFolder = new javax.swing.JLabel(); - outputPathTextField = new javax.swing.JTextField(); - browseOutputFolderButton = new javax.swing.JButton(); - jLabelInvalidImageFolder = new javax.swing.JLabel(); - jLabelInvalidResultsFolder = new javax.swing.JLabel(); - jLabel1 = new javax.swing.JLabel(); - jPanelSharedConfig = new javax.swing.JPanel(); - sharedConfigCheckbox = new javax.swing.JCheckBox(); - sharedSettingsTextField = new javax.swing.JTextField(); - browseSharedSettingsButton = new javax.swing.JButton(); - sharedSettingsErrorTextField = new javax.swing.JTextField(); - masterNodeCheckBox = new javax.swing.JCheckBox(); - uploadButton = new javax.swing.JButton(); - downloadButton = new javax.swing.JButton(); - jLabelCurrentTask = new javax.swing.JLabel(); - pbTaskInProgress = new javax.swing.JProgressBar(); - jLabelTaskDescription = new javax.swing.JLabel(); - configButtonErrorTextField = new javax.swing.JTextField(); - jSeparator1 = new javax.swing.JSeparator(); - jPanelIngestSettings = new javax.swing.JPanel(); + cbJoinAutoIngestCluster = new javax.swing.JCheckBox(); + tbOops = new javax.swing.JTextField(); bnEditIngestSettings = new javax.swing.JButton(); bnAdvancedSettings = new javax.swing.JButton(); bnFileExport = new javax.swing.JButton(); bnLogging = new javax.swing.JButton(); - cbJoinAutoIngestCluster = new javax.swing.JCheckBox(); - tbOops = new javax.swing.JTextField(); + browseOutputFolderButton = new javax.swing.JButton(); + browseInputFolderButton = new javax.swing.JButton(); + inputPathTextField = new javax.swing.JTextField(); + outputPathTextField = new javax.swing.JTextField(); + jLabelInvalidResultsFolder = new javax.swing.JLabel(); + jLabelInvalidImageFolder = new javax.swing.JLabel(); + jLabelSelectInputFolder = new javax.swing.JLabel(); + jLabelSelectOutputFolder = new javax.swing.JLabel(); + sharedConfigCheckbox = new javax.swing.JCheckBox(); + sharedSettingsErrorTextField = new javax.swing.JTextField(); + sharedSettingsTextField = new javax.swing.JTextField(); + browseSharedSettingsButton = new javax.swing.JButton(); + downloadButton = new javax.swing.JButton(); + configButtonErrorTextField = new javax.swing.JTextField(); + pbTaskInProgress = new javax.swing.JProgressBar(); + jLabelTaskDescription = new javax.swing.JLabel(); + jLabelCurrentTask = new javax.swing.JLabel(); + uploadButton = new javax.swing.JButton(); + masterNodeCheckBox = new javax.swing.JCheckBox(); nodeScrollPane.setMinimumSize(new java.awt.Dimension(0, 0)); nodePanel.setMinimumSize(new java.awt.Dimension(100, 100)); - jPanelNodeType.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelNodeType.border.title"))); // NOI18N - jPanelNodeType.setMinimumSize(new java.awt.Dimension(50, 50)); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectMode, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectMode.text")); // NOI18N - - modeRadioButtons.add(jRadioButtonAutomated); - jRadioButtonAutomated.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonAutomated, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonAutomated.text")); // NOI18N - jRadioButtonAutomated.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonAutomated.toolTipText")); // NOI18N - jRadioButtonAutomated.addActionListener(new java.awt.event.ActionListener() { + cbJoinAutoIngestCluster.setFont(cbJoinAutoIngestCluster.getFont().deriveFont(cbJoinAutoIngestCluster.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + org.openide.awt.Mnemonics.setLocalizedText(cbJoinAutoIngestCluster, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text")); // NOI18N + cbJoinAutoIngestCluster.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - jRadioButtonAutomatedActionPerformed(evt); + cbJoinAutoIngestClusterActionPerformed(evt); } }); - modeRadioButtons.add(jRadioButtonReview); - org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonReview, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonReview.text")); // NOI18N - jRadioButtonReview.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonReview.toolTipText")); // NOI18N - jRadioButtonReview.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - jRadioButtonReviewActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectInputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectInputFolder.text")); // NOI18N - jLabelSelectInputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); - - inputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.text")); // NOI18N - inputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.toolTipText")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(browseInputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseInputFolderButton.text")); // NOI18N - browseInputFolderButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseInputFolderButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectOutputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectOutputFolder.text")); // NOI18N - jLabelSelectOutputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); - - outputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.text")); // NOI18N - outputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.toolTipText")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(browseOutputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseOutputFolderButton.text")); // NOI18N - browseOutputFolderButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseOutputFolderButtonActionPerformed(evt); - } - }); - - jLabelInvalidImageFolder.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidImageFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidImageFolder.text")); // NOI18N - - jLabelInvalidResultsFolder.setForeground(new java.awt.Color(255, 0, 0)); - org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidResultsFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text")); // NOI18N - - jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/experimental/images/AIM.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabel1.text")); // NOI18N - - javax.swing.GroupLayout jPanelNodeTypeLayout = new javax.swing.GroupLayout(jPanelNodeType); - jPanelNodeType.setLayout(jPanelNodeTypeLayout); - jPanelNodeTypeLayout.setHorizontalGroup( - jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(outputPathTextField, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(inputPathTextField, javax.swing.GroupLayout.Alignment.LEADING)) - .addGap(10, 10, 10) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(browseInputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(browseOutputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING))) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabelSelectMode) - .addComponent(jRadioButtonReview) - .addComponent(jRadioButtonAutomated)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jLabel1)) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addComponent(jLabelSelectInputFolder) - .addGap(18, 18, 18) - .addComponent(jLabelInvalidImageFolder, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addComponent(jLabelSelectOutputFolder) - .addGap(18, 18, 18) - .addComponent(jLabelInvalidResultsFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 544, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) - ); - jPanelNodeTypeLayout.setVerticalGroup( - jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelNodeTypeLayout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabelSelectMode) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jRadioButtonAutomated) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jRadioButtonReview)) - .addComponent(jLabel1)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelSelectInputFolder) - .addComponent(jLabelInvalidImageFolder)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(inputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(browseInputFolderButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelSelectOutputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabelInvalidResultsFolder)) - .addGap(1, 1, 1) - .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(browseOutputFolderButton) - .addComponent(outputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(0, 0, Short.MAX_VALUE)) - ); - - jPanelSharedConfig.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelSharedConfig.border.title"))); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(sharedConfigCheckbox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedConfigCheckbox.text")); // NOI18N - sharedConfigCheckbox.setMaximumSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.setMinimumSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.setPreferredSize(new java.awt.Dimension(191, 14)); - sharedConfigCheckbox.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - sharedConfigCheckboxItemStateChanged(evt); - } - }); - - sharedSettingsTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsTextField.text")); // NOI18N - sharedSettingsTextField.setEnabled(false); - - org.openide.awt.Mnemonics.setLocalizedText(browseSharedSettingsButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseSharedSettingsButton.text")); // NOI18N - browseSharedSettingsButton.setEnabled(false); - browseSharedSettingsButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - browseSharedSettingsButtonActionPerformed(evt); - } - }); - - sharedSettingsErrorTextField.setEditable(false); - sharedSettingsErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); - sharedSettingsErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsErrorTextField.text")); // NOI18N - sharedSettingsErrorTextField.setBorder(null); - - org.openide.awt.Mnemonics.setLocalizedText(masterNodeCheckBox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.masterNodeCheckBox.text")); // NOI18N - masterNodeCheckBox.setEnabled(false); - masterNodeCheckBox.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - masterNodeCheckBoxItemStateChanged(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(uploadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.uploadButton.text")); // NOI18N - uploadButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - uploadButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(downloadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.downloadButton.text")); // NOI18N - downloadButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - downloadButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(jLabelCurrentTask, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelCurrentTask.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabelTaskDescription, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelTaskDescription.text")); // NOI18N - - configButtonErrorTextField.setEditable(false); - configButtonErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); - configButtonErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.configButtonErrorTextField.text")); // NOI18N - configButtonErrorTextField.setBorder(null); - - javax.swing.GroupLayout jPanelSharedConfigLayout = new javax.swing.GroupLayout(jPanelSharedConfig); - jPanelSharedConfig.setLayout(jPanelSharedConfigLayout); - jPanelSharedConfigLayout.setHorizontalGroup( - jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addGap(10, 10, 10) - .addComponent(jLabelCurrentTask) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabelTaskDescription, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(browseSharedSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(uploadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(downloadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(configButtonErrorTextField)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanelSharedConfigLayout.createSequentialGroup() - .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(sharedSettingsErrorTextField)) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 692, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 695, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(masterNodeCheckBox)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - jPanelSharedConfigLayout.setVerticalGroup( - jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelSharedConfigLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(browseSharedSettingsButton)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(downloadButton) - .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(1, 1, 1) - .addComponent(masterNodeCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(uploadButton) - .addGap(8, 8, 8) - .addGroup(jPanelSharedConfigLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabelCurrentTask) - .addComponent(jLabelTaskDescription)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - jPanelIngestSettings.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jPanelIngestSettings.border.title"))); // NOI18N + tbOops.setEditable(false); + tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); + tbOops.setForeground(new java.awt.Color(255, 0, 0)); + tbOops.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.tbOops.text")); // NOI18N + tbOops.setBorder(null); org.openide.awt.Mnemonics.setLocalizedText(bnEditIngestSettings, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.bnEditIngestSettings.text")); // NOI18N bnEditIngestSettings.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.bnEditIngestSettings.toolTipText")); // NOI18N @@ -949,46 +662,94 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }); - javax.swing.GroupLayout jPanelIngestSettingsLayout = new javax.swing.GroupLayout(jPanelIngestSettings); - jPanelIngestSettings.setLayout(jPanelIngestSettingsLayout); - jPanelIngestSettingsLayout.setHorizontalGroup( - jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelIngestSettingsLayout.createSequentialGroup() - .addContainerGap() - .addComponent(bnEditIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnAdvancedSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnFileExport, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnLogging, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - jPanelIngestSettingsLayout.setVerticalGroup( - jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelIngestSettingsLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelIngestSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnEditIngestSettings) - .addComponent(bnFileExport) - .addComponent(bnAdvancedSettings) - .addComponent(bnLogging)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - cbJoinAutoIngestCluster.setFont(cbJoinAutoIngestCluster.getFont().deriveFont(cbJoinAutoIngestCluster.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); - org.openide.awt.Mnemonics.setLocalizedText(cbJoinAutoIngestCluster, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text")); // NOI18N - cbJoinAutoIngestCluster.addActionListener(new java.awt.event.ActionListener() { + org.openide.awt.Mnemonics.setLocalizedText(browseOutputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseOutputFolderButton.text")); // NOI18N + browseOutputFolderButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - cbJoinAutoIngestClusterActionPerformed(evt); + browseOutputFolderButtonActionPerformed(evt); } }); - tbOops.setEditable(false); - tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); - tbOops.setForeground(new java.awt.Color(255, 0, 0)); - tbOops.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.tbOops.text")); // NOI18N - tbOops.setBorder(null); + org.openide.awt.Mnemonics.setLocalizedText(browseInputFolderButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseInputFolderButton.text")); // NOI18N + browseInputFolderButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseInputFolderButtonActionPerformed(evt); + } + }); + + inputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.text")); // NOI18N + inputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.inputPathTextField.toolTipText")); // NOI18N + + outputPathTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.text")); // NOI18N + outputPathTextField.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.outputPathTextField.toolTipText")); // NOI18N + + jLabelInvalidResultsFolder.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidResultsFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text")); // NOI18N + + jLabelInvalidImageFolder.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(jLabelInvalidImageFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelInvalidImageFolder.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectInputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectInputFolder.text")); // NOI18N + jLabelSelectInputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectOutputFolder, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectOutputFolder.text")); // NOI18N + jLabelSelectOutputFolder.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + + org.openide.awt.Mnemonics.setLocalizedText(sharedConfigCheckbox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedConfigCheckbox.text")); // NOI18N + sharedConfigCheckbox.setMaximumSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.setMinimumSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.setPreferredSize(new java.awt.Dimension(191, 14)); + sharedConfigCheckbox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + sharedConfigCheckboxItemStateChanged(evt); + } + }); + + sharedSettingsErrorTextField.setEditable(false); + sharedSettingsErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); + sharedSettingsErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsErrorTextField.text")); // NOI18N + sharedSettingsErrorTextField.setBorder(null); + + sharedSettingsTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.sharedSettingsTextField.text")); // NOI18N + sharedSettingsTextField.setEnabled(false); + + org.openide.awt.Mnemonics.setLocalizedText(browseSharedSettingsButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.browseSharedSettingsButton.text")); // NOI18N + browseSharedSettingsButton.setEnabled(false); + browseSharedSettingsButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseSharedSettingsButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(downloadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.downloadButton.text")); // NOI18N + downloadButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + downloadButtonActionPerformed(evt); + } + }); + + configButtonErrorTextField.setEditable(false); + configButtonErrorTextField.setForeground(new java.awt.Color(255, 0, 0)); + configButtonErrorTextField.setText(org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.configButtonErrorTextField.text")); // NOI18N + configButtonErrorTextField.setBorder(null); + + org.openide.awt.Mnemonics.setLocalizedText(jLabelTaskDescription, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelTaskDescription.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabelCurrentTask, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelCurrentTask.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(uploadButton, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.uploadButton.text")); // NOI18N + uploadButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + uploadButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(masterNodeCheckBox, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.masterNodeCheckBox.text")); // NOI18N + masterNodeCheckBox.setEnabled(false); + masterNodeCheckBox.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + masterNodeCheckBoxItemStateChanged(evt); + } + }); javax.swing.GroupLayout nodePanelLayout = new javax.swing.GroupLayout(nodePanel); nodePanel.setLayout(nodePanelLayout); @@ -998,14 +759,56 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { .addContainerGap() .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(nodePanelLayout.createSequentialGroup() - .addComponent(cbJoinAutoIngestCluster, javax.swing.GroupLayout.PREFERRED_SIZE, 171, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelCurrentTask) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabelTaskDescription, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(outputPathTextField, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(inputPathTextField, javax.swing.GroupLayout.Alignment.LEADING)) + .addGap(10, 10, 10) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(browseInputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(browseOutputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING))) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(jLabelSelectInputFolder) .addGap(18, 18, 18) - .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 465, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jPanelNodeType, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanelSharedConfig, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanelIngestSettings, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(jLabelInvalidImageFolder, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(uploadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 695, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(masterNodeCheckBox) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(cbJoinAutoIngestCluster, javax.swing.GroupLayout.PREFERRED_SIZE, 171, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 465, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(bnEditIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnAdvancedSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnFileExport, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnLogging, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(jLabelSelectOutputFolder) + .addGap(18, 18, 18) + .addComponent(jLabelInvalidResultsFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 544, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseSharedSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(nodePanelLayout.createSequentialGroup() + .addComponent(downloadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 396, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(0, 32, Short.MAX_VALUE))) + .addContainerGap()) ); nodePanelLayout.setVerticalGroup( nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1014,12 +817,51 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cbJoinAutoIngestCluster) .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(3, 3, 3) - .addComponent(jPanelNodeType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelSelectInputFolder) + .addComponent(jLabelInvalidImageFolder)) + .addGap(1, 1, 1) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(inputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseInputFolderButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanelIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 62, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelSelectOutputFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabelInvalidResultsFolder)) + .addGap(1, 1, 1) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(browseOutputFolderButton) + .addComponent(outputPathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(25, 25, 25) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnEditIngestSettings) + .addComponent(bnFileExport) + .addComponent(bnAdvancedSettings) + .addComponent(bnLogging)) + .addGap(18, 18, 18) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(sharedConfigCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(sharedSettingsErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanelSharedConfig, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(sharedSettingsTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseSharedSettingsButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(downloadButton) + .addComponent(configButtonErrorTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addComponent(masterNodeCheckBox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(uploadButton) + .addGap(8, 8, 8) + .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabelCurrentTask) + .addComponent(jLabelTaskDescription)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(pbTaskInProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(161, Short.MAX_VALUE)) ); nodeScrollPane.setViewportView(nodePanel); @@ -1039,31 +881,35 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { ); }// //GEN-END:initComponents - private void browseSharedSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseSharedSettingsButtonActionPerformed - - String oldText = sharedSettingsTextField.getText().trim(); - // set the current directory of the FileChooser if the oldText is valid - File currentDir = new File(oldText); - if (currentDir.exists()) { - fc.setCurrentDirectory(currentDir); - } - - fc.setDialogTitle("Select shared configuration folder:"); - fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - - int retval = fc.showOpenDialog(this); - if (retval == JFileChooser.APPROVE_OPTION) { - String path = fc.getSelectedFile().getPath(); - sharedSettingsTextField.setText(path); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_browseSharedSettingsButtonActionPerformed - boolean permissionsAppropriate(String path) { return FileUtil.hasReadWriteAccess(Paths.get(path)); } + private void setSharedConfigEnable() { + setEnabledStateForSharedConfiguration(); + if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected()) { + sharedSettingsTextField.setEnabled(true); + browseSharedSettingsButton.setEnabled(true); + masterNodeCheckBox.setEnabled(true); + downloadButton.setEnabled(true); + validateSettings(); + controller.changed(); + } else { + sharedSettingsTextField.setEnabled(false); + browseSharedSettingsButton.setEnabled(false); + masterNodeCheckBox.setEnabled(false); + downloadButton.setEnabled(false); + sharedSettingsErrorTextField.setText(""); + validateSettings(); + controller.changed(); + } + } + + private void cbJoinAutoIngestClusterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbJoinAutoIngestClusterActionPerformed + enableOptionsBasedOnMode(getModeFromRadioButtons()); + controller.changed(); + }//GEN-LAST:event_cbJoinAutoIngestClusterActionPerformed + private void downloadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downloadButtonActionPerformed // First save the shared config folder and solr settings to the properties String globalSettingsPath = getNormalizedFolderPath(sharedSettingsTextField.getText().trim()); @@ -1100,31 +946,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_uploadButtonActionPerformed - private void sharedConfigCheckboxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_sharedConfigCheckboxItemStateChanged - // Enable the global settings text box and browse button iff the checkbox is checked and enabled - setSharedConfigEnable(); - }//GEN-LAST:event_sharedConfigCheckboxItemStateChanged - - private void setSharedConfigEnable() { - setEnabledStateForSharedConfiguration(); - if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected() && jRadioButtonAutomated.isSelected()) { - sharedSettingsTextField.setEnabled(true); - browseSharedSettingsButton.setEnabled(true); - masterNodeCheckBox.setEnabled(true); - downloadButton.setEnabled(true); - validateSettings(); - controller.changed(); - } else { - sharedSettingsTextField.setEnabled(false); - browseSharedSettingsButton.setEnabled(false); - masterNodeCheckBox.setEnabled(false); - downloadButton.setEnabled(false); - sharedSettingsErrorTextField.setText(""); - validateSettings(); - controller.changed(); - } - } - private void masterNodeCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_masterNodeCheckBoxItemStateChanged // Enable the global settings text box and browse button iff the checkbox is checked and enabled setEnabledStateForSharedConfiguration(); @@ -1137,10 +958,31 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_masterNodeCheckBoxItemStateChanged - private void cbJoinAutoIngestClusterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbJoinAutoIngestClusterActionPerformed - enableOptionsBasedOnMode(getModeFromRadioButtons()); - controller.changed(); - }//GEN-LAST:event_cbJoinAutoIngestClusterActionPerformed + private void browseSharedSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseSharedSettingsButtonActionPerformed + + String oldText = sharedSettingsTextField.getText().trim(); + // set the current directory of the FileChooser if the oldText is valid + File currentDir = new File(oldText); + if (currentDir.exists()) { + fc.setCurrentDirectory(currentDir); + } + + fc.setDialogTitle("Select shared configuration folder:"); + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + int retval = fc.showOpenDialog(this); + if (retval == JFileChooser.APPROVE_OPTION) { + String path = fc.getSelectedFile().getPath(); + sharedSettingsTextField.setText(path); + validateSettings(); + controller.changed(); + } + }//GEN-LAST:event_browseSharedSettingsButtonActionPerformed + + private void sharedConfigCheckboxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_sharedConfigCheckboxItemStateChanged + // Enable the global settings text box and browse button iff the checkbox is checked and enabled + setSharedConfigEnable(); + }//GEN-LAST:event_sharedConfigCheckboxItemStateChanged private void browseOutputFolderButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseOutputFolderButtonActionPerformed String oldText = outputPathTextField.getText().trim(); @@ -1182,24 +1024,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } }//GEN-LAST:event_browseInputFolderButtonActionPerformed - private void jRadioButtonReviewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonReviewActionPerformed - if (cbJoinAutoIngestCluster.isSelected()) { - enableOptionsBasedOnMode(OptionsUiMode.REVIEW); - setSharedConfigEnable(); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_jRadioButtonReviewActionPerformed - - private void jRadioButtonAutomatedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonAutomatedActionPerformed - if (cbJoinAutoIngestCluster.isSelected()) { - enableOptionsBasedOnMode(OptionsUiMode.AIM); - setSharedConfigEnable(); - validateSettings(); - controller.changed(); - } - }//GEN-LAST:event_jRadioButtonAutomatedActionPerformed - private void bnLoggingActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnLoggingActionPerformed JDialog jDialog = new JDialog(); NodeStatusLogPanel loggingPanel = new NodeStatusLogPanel(jDialog); @@ -1242,9 +1066,9 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private void bnAdvancedSettingsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnAdvancedSettingsActionPerformed AdvancedAutoIngestSettingsPanel advancedAutoIngestSettingsPanel = new AdvancedAutoIngestSettingsPanel(getModeFromRadioButtons()); if (JOptionPane.showConfirmDialog(null, advancedAutoIngestSettingsPanel, - NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title"), - JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { - advancedAutoIngestSettingsPanel.store(); + NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.OK_OPTION) { + advancedAutoIngestSettingsPanel.store(); } }//GEN-LAST:event_bnAdvancedSettingsActionPerformed @@ -1349,7 +1173,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } void setEnabledStateForSharedConfiguration() { - if (jRadioButtonAutomated.isSelected() && cbJoinAutoIngestCluster.isSelected()) { + if (cbJoinAutoIngestCluster.isSelected()) { enableOptionsBasedOnMode(OptionsUiMode.AIM); } } @@ -1361,19 +1185,13 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { bnLogging.setEnabled(enabled); browseInputFolderButton.setEnabled(enabled); browseOutputFolderButton.setEnabled(enabled); - browseSharedSettingsButton.setEnabled(sharedConfigCheckbox.isSelected() && jRadioButtonAutomated.isSelected()); + browseSharedSettingsButton.setEnabled(sharedConfigCheckbox.isSelected() && cbJoinAutoIngestCluster.isSelected()); configButtonErrorTextField.setEnabled(enabled); inputPathTextField.setEnabled(enabled); jLabelInvalidImageFolder.setEnabled(enabled); jLabelInvalidResultsFolder.setEnabled(enabled); jLabelSelectInputFolder.setEnabled(enabled); - jLabelSelectMode.setEnabled(enabled); jLabelSelectOutputFolder.setEnabled(enabled); - jPanelIngestSettings.setEnabled(enabled); - jPanelNodeType.setEnabled(enabled); - jPanelSharedConfig.setEnabled(enabled); - jRadioButtonAutomated.setEnabled(enabled); - jRadioButtonReview.setEnabled(enabled); outputPathTextField.setEnabled(enabled); } @@ -1389,22 +1207,13 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private javax.swing.JTextField configButtonErrorTextField; private javax.swing.JButton downloadButton; private javax.swing.JTextField inputPathTextField; - private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabelCurrentTask; private javax.swing.JLabel jLabelInvalidImageFolder; private javax.swing.JLabel jLabelInvalidResultsFolder; private javax.swing.JLabel jLabelSelectInputFolder; - private javax.swing.JLabel jLabelSelectMode; private javax.swing.JLabel jLabelSelectOutputFolder; private javax.swing.JLabel jLabelTaskDescription; - private javax.swing.JPanel jPanelIngestSettings; - private javax.swing.JPanel jPanelNodeType; - private javax.swing.JPanel jPanelSharedConfig; - private javax.swing.JRadioButton jRadioButtonAutomated; - private javax.swing.JRadioButton jRadioButtonReview; - private javax.swing.JSeparator jSeparator1; private javax.swing.JCheckBox masterNodeCheckBox; - private javax.swing.ButtonGroup modeRadioButtons; private javax.swing.JPanel nodePanel; private javax.swing.JScrollPane nodeScrollPane; private javax.swing.JTextField outputPathTextField; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties index 66ed50dd20..a12453e3c1 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties @@ -23,12 +23,9 @@ AIMIngestSettingsPanel.lbSecondsBetweenJobs.toolTipText=Increase this value if d AIMIngestSettingsPanel.spSecondsBetweenJobs.toolTipText=Increase this value if database locks cause problems. It gives a little more time for finalizing. AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title=Advanced Settings AutoIngestSettingsPanel.browseGlobalSettingsButton.text=Browse -AutoIngestSettingsPanel.browseSharedSettingsButton.text=Browse AutoIngestSettingsPanel.CannotAccess=Cannot access AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text=Join auto ingest cluster AutoIngestSettingsPanel.CheckPermissions=Check permissions. -AutoIngestSettingsPanel.configButtonErrorTextField.text=configButtonErrorTextField -AutoIngestSettingsPanel.downloadButton.text=Download Config AutoIngestSettingsPanel.EmptySettingsDirectory=Enter path to settings directory AutoIngestSettingsPanel.ErrorSettingDefaultFolder=Error creating default folder AutoIngestSettingsPanel.FileExportRules.text=File Export Rules @@ -36,12 +33,8 @@ AutoIngestSettingsPanel.globalSettingsErrorTextField.text= AutoIngestSettingsPanel.globalSettingsTextField.text= AutoIngestSettingsPanel.ImageDirectoryUnspecified=Shared images folder must be set AutoIngestSettingsPanel.InvalidPortNumber=Invalid port number. -AutoIngestSettingsPanel.jLabelCurrentTask.text=Current task: -AutoIngestSettingsPanel.jLabelTaskDescription.text=jLabel1 -AutoIngestSettingsPanel.jPanelSharedConfig.border.title=Shared Configuration AutoIngestSettingsPanel.jRadioButtonCopyFiles.text=File Copy mode AutoIngestSettingsPanel.KeywordSearchNull=Cannot find Keyword Search service -AutoIngestSettingsPanel.masterNodeCheckBox.text=Use this node as a master node that can upload settings AutoIngestSettingsPanel.MustRestart=Autopsy must be restarted for new configuration to take effect AutoIngestSettingsPanel.nodePanel.TabConstraints.tabTitle=Node Configuration AutoIngestSettingsPanel.NodeStatusLogging.text=Node Status Logging Settings @@ -49,11 +42,7 @@ AutoIngestSettingsPanel.PathInvalid=Path is not valid AutoIngestSettingsPanel.restartRequiredLabel.text=Application restart required to take effect. AutoIngestSettingsPanel.restartRequiredLabel.text=Application restart required AutoIngestSettingsPanel.ResultsDirectoryUnspecified=Shared cases folder must be set -AutoIngestSettingsPanel.sharedConfigCheckbox.text=Use shared configuration in folder: -AutoIngestSettingsPanel.sharedSettingsErrorTextField.text=globalSettingsErrorTextField -AutoIngestSettingsPanel.sharedSettingsTextField.text= AutoIngestSettingsPanel.tbOops.text= -AutoIngestSettingsPanel.uploadButton.text=Save & Upload Config AutoIngestSettingsPanel.validationErrMsg.incomplete=Fill in all values AutoIngestSettingsPanel.validationErrMsg.invalidDatabasePort=Invalid database port number AutoIngestSettingsPanel.validationErrMsg.invalidIndexingServerPort=Invalid Solr server port number @@ -119,8 +108,16 @@ AdvancedAutoIngestSettingsPanel.lbConcurrentJobsPerCase.toolTipText_1=A soft lim AdvancedAutoIngestSettingsPanel.lbNumberOfThreads.toolTipText_1=The number of threads running file level ingest modules. AdvancedAutoIngestSettingsPanel.numberOfFileIngestThreadsComboBox.toolTipText=The number of threads running file level ingest modules. NodeStatusLogPanel.tbDbName.toolTipText_1=Database name -AutoIngestSettingsPanel.jPanelNodeType.border.title=Node Type Setup -AutoIngestSettingsPanel.jLabel1.text= +AutoIngestSettingsPanel.sharedSettingsTextField.text= +AutoIngestSettingsPanel.sharedConfigCheckbox.text=Use shared configuration in folder: +AutoIngestSettingsPanel.configButtonErrorTextField.text=configButtonErrorTextField +AutoIngestSettingsPanel.jLabelTaskDescription.text=jLabel1 +AutoIngestSettingsPanel.jLabelCurrentTask.text=Current task: +AutoIngestSettingsPanel.downloadButton.text=Download Config +AutoIngestSettingsPanel.uploadButton.text=Save & Upload Config +AutoIngestSettingsPanel.masterNodeCheckBox.text=Use this node as a master node that can upload settings +AutoIngestSettingsPanel.sharedSettingsErrorTextField.text=globalSettingsErrorTextField +AutoIngestSettingsPanel.browseSharedSettingsButton.text=Browse AutoIngestSettingsPanel.jLabelInvalidResultsFolder.text=jLabelInvalidResultsFolder AutoIngestSettingsPanel.jLabelInvalidImageFolder.text=jLabelInvalidImageFolder AutoIngestSettingsPanel.browseOutputFolderButton.text=Browse @@ -131,12 +128,6 @@ AutoIngestSettingsPanel.browseInputFolderButton.text=Browse AutoIngestSettingsPanel.inputPathTextField.toolTipText=Input folder for automated processing, i.e., the location where input case folders will be created for ingest by automated processing mode AutoIngestSettingsPanel.inputPathTextField.text= AutoIngestSettingsPanel.jLabelSelectInputFolder.text=Select shared images folder: -AutoIngestSettingsPanel.jRadioButtonReview.toolTipText=Review cases created in automated processing mode -AutoIngestSettingsPanel.jRadioButtonReview.text=Examiner node -AutoIngestSettingsPanel.jRadioButtonAutomated.toolTipText=Automatically detect new data sources and create cases. -AutoIngestSettingsPanel.jRadioButtonAutomated.text=Auto ingest node (application restart required) -AutoIngestSettingsPanel.jLabelSelectMode.text=Select mode: -AutoIngestSettingsPanel.jPanelIngestSettings.border.title=Automated Ingest Settings AutoIngestSettingsPanel.bnLogging.text=Node Status Logging AutoIngestSettingsPanel.bnFileExport.text=File Export Settings AutoIngestSettingsPanel.bnAdvancedSettings.text=Advanced Settings diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java index b715b7d309..1720b4b647 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/SharedConfiguration.java @@ -1016,7 +1016,7 @@ public class SharedConfiguration { // If a copy of the database is loaded, close it before deleting and copying. if (localDb.exists()) { - List hashDbs = HashDbManager.getInstance().getAllFileTypeHashSets(); + List hashDbs = HashDbManager.getInstance().getAllHashSets(); HashDbManager.HashDb matchingDb = null; for (HashDbManager.HashDb db : hashDbs) { try { @@ -1122,7 +1122,7 @@ public class SharedConfiguration { try { HashDbManager hashDbManager = HashDbManager.getInstance(); hashDbManager.loadLastSavedConfiguration(); - for (HashDb hashDb : hashDbManager.getAllFileTypeHashSets()) { + for (HashDbManager.HashDb hashDb : hashDbManager.getAllHashSets()) { if (hashDb.hasIndexOnly()) { results.add(hashDb.getIndexPath()); } else { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java index e28cd75654..862635ad4a 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java @@ -139,8 +139,31 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option @Override public void addPropertyChangeListener(PropertyChangeListener l) { super.addPropertyChangeListener(l); - listsManagementPanel.addPropertyChangeListener(l); - editListPanel.addPropertyChangeListener(l); + /* + * There is at least one look and feel library that follows the bad + * practice of calling overrideable methods in a constructor, e.g.: + * + * at + * javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83) + * at + * javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63) + * at javax.swing.JComponent.setUI(JComponent.java:666) at + * javax.swing.JPanel.setUI(JPanel.java:153) at + * javax.swing.JPanel.updateUI(JPanel.java:126) at + * javax.swing.JPanel.(JPanel.java:86) at + * javax.swing.JPanel.(JPanel.java:109) at + * javax.swing.JPanel.(JPanel.java:117) + * + * When this happens, the following child components of this JPanel + * subclass have not been constructed yet, since this panel's + * constructor has not been called yet. + */ + if (null != listsManagementPanel) { + listsManagementPanel.addPropertyChangeListener(l); + } + if (null != editListPanel) { + editListPanel.addPropertyChangeListener(l); + } } @Override diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java index 6836483b30..70d2e69194 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java @@ -205,7 +205,13 @@ class HighlightedText implements IndexedText { */ synchronized private void loadPageInfoFromHits() { isLiteral = hits.getQuery().isLiteral(); - //organize the hits by page, filter as needed + + /** + * Organize the hits by page, filter as needed. + * We process *every* keyword here because in the case of a regular + * expression search there may be multiple different keyword + * hits located in different chunks for the same file/artifact. + */ for (Keyword k : hits.getKeywords()) { for (KeywordHit hit : hits.getResults(k)) { int chunkID = hit.getChunkId(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java index e51c1c2620..f9284e81d9 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordHit.java @@ -38,12 +38,9 @@ class KeywordHit implements Comparable { private static final String GET_CONTENT_ID_FROM_ARTIFACT_ID = "SELECT obj_id FROM blackboard_artifacts WHERE artifact_id = "; - private final String solrDocumentId; private final long solrObjectId; private final int chunkId; private final String snippet; - private final long contentID; - private final boolean hitOnArtifact; private final String hit; /** @@ -56,14 +53,10 @@ class KeywordHit implements Comparable { * For some searches (ie substring, regex) this will be * different than the search term. * - * @throws TskCoreException If there is a problem getting the underlying - * content associated with a hit on the text of an - * artifact. */ - KeywordHit(String solrDocumentId, String snippet, String hit) throws TskCoreException { + KeywordHit(String solrDocumentId, String snippet, String hit) { this.snippet = StringUtils.stripToEmpty(snippet); this.hit = hit; - this.solrDocumentId = solrDocumentId; /* * Parse the Solr document id to get the Solr object id and chunk id. @@ -83,28 +76,6 @@ class KeywordHit implements Comparable { this.solrObjectId = Long.parseLong(split[0]); this.chunkId = Integer.parseInt(split[1]); } - - //artifacts have negative obj ids - hitOnArtifact = this.solrObjectId < 0; - - if (hitOnArtifact) { - // If the hit was in an artifact, look up the source content for the artifact. - SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase(); - try (SleuthkitCase.CaseDbQuery executeQuery = - caseDb.executeQuery(GET_CONTENT_ID_FROM_ARTIFACT_ID + this.solrObjectId); - ResultSet resultSet = executeQuery.getResultSet();) { - if (resultSet.next()) { - contentID = resultSet.getLong("obj_id"); - } else { - throw new TskCoreException("Failed to get obj_id for artifact with artifact_id =" + this.solrObjectId + ". No matching artifact was found."); - } - } catch (SQLException ex) { - throw new TskCoreException("Error getting obj_id for artifact with artifact_id =" + this.solrObjectId, ex); - } - } else { - //else the object id is for content. - contentID = this.solrObjectId; - } } String getHit() { @@ -112,7 +83,7 @@ class KeywordHit implements Comparable { } String getSolrDocumentId() { - return this.solrDocumentId; + return Long.toString(solrObjectId) + Server.CHUNK_ID_SEPARATOR + Long.toString(chunkId); } long getSolrObjectId() { @@ -131,8 +102,36 @@ class KeywordHit implements Comparable { return this.snippet; } - long getContentID() { - return this.contentID; + /** + * Get the content id associated with the content underlying hit. + * For hits on files this will be the same as the object id associated + * with the file. For hits on artifacts we look up the id of the object + * that produced the artifact. + * + * @return The id of the underlying content associated with the hit. + * @throws TskCoreException If there is a problem getting the underlying + * content associated with a hit on the text of an + * artifact. + */ + long getContentID() throws TskCoreException { + if (isArtifactHit()) { + // If the hit was in an artifact, look up the source content for the artifact. + SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase(); + try (SleuthkitCase.CaseDbQuery executeQuery = + caseDb.executeQuery(GET_CONTENT_ID_FROM_ARTIFACT_ID + this.solrObjectId); + ResultSet resultSet = executeQuery.getResultSet();) { + if (resultSet.next()) { + return resultSet.getLong("obj_id"); + } else { + throw new TskCoreException("Failed to get obj_id for artifact with artifact_id =" + this.solrObjectId + ". No matching artifact was found."); + } + } catch (SQLException ex) { + throw new TskCoreException("Error getting obj_id for artifact with artifact_id =" + this.solrObjectId, ex); + } + } else { + //else the object id is for content. + return this.solrObjectId; + } } /** @@ -141,7 +140,8 @@ class KeywordHit implements Comparable { * @return */ boolean isArtifactHit() { - return hitOnArtifact; + // artifacts have negative obj ids + return this.solrObjectId < 0; } /** @@ -150,7 +150,7 @@ class KeywordHit implements Comparable { * @return The artifact whose indexed text this hit is in. */ Optional getArtifactID() { - if (hitOnArtifact) { + if (isArtifactHit()) { return Optional.of(solrObjectId); } else { return Optional.empty(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java index 8e820b4c74..c34e672a1c 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java @@ -52,9 +52,34 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP @Override public void addPropertyChangeListener(PropertyChangeListener l) { super.addPropertyChangeListener(l); - listsPanel.addPropertyChangeListener(l); - languagesPanel.addPropertyChangeListener(l); - generalPanel.addPropertyChangeListener(l); + /* + * There is at least one look and feel library that follows the bad + * practice of calling overrideable methods in a constructor, e.g.: + * + * at + * javax.swing.plaf.synth.SynthPanelUI.installListeners(SynthPanelUI.java:83) + * at + * javax.swing.plaf.synth.SynthPanelUI.installUI(SynthPanelUI.java:63) + * at javax.swing.JComponent.setUI(JComponent.java:666) at + * javax.swing.JPanel.setUI(JPanel.java:153) at + * javax.swing.JPanel.updateUI(JPanel.java:126) at + * javax.swing.JPanel.(JPanel.java:86) at + * javax.swing.JPanel.(JPanel.java:109) at + * javax.swing.JPanel.(JPanel.java:117) + * + * When this happens, the following child components of this JPanel + * subclass have not been constructed yet, since this panel's + * constructor has not been called yet. + */ + if (null != listsPanel) { + listsPanel.addPropertyChangeListener(l); + } + if (null != languagesPanel) { + languagesPanel.addPropertyChangeListener(l); + } + if (null != generalPanel) { + generalPanel.addPropertyChangeListener(l); + } } @Override diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index 0927b68d6c..6734cbf47d 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -226,6 +226,8 @@ final class RegexQuery implements KeywordSearchQuery { private List createKeywordHits(SolrDocument solrDoc) throws TskCoreException { + final HashMap keywordsFoundInThisDocument = new HashMap<>(); + List hits = new ArrayList<>(); final String docId = solrDoc.getFieldValue(Server.Schema.ID.toString()).toString(); final Integer chunkSize = (Integer) solrDoc.getFieldValue(Server.Schema.CHUNK_SIZE.toString()); @@ -273,6 +275,23 @@ final class RegexQuery implements KeywordSearchQuery { hit = hit.replaceAll("[^0-9]$", ""); } + /** + * The use of String interning is an optimization to ensure + * that we reuse the same keyword hit String object across + * all hits. Even though we benefit from G1GC String + * deduplication, the overhead associated with creating a + * new String object for every KeywordHit can be significant + * when the number of hits gets large. + */ + hit = hit.intern(); + + // We will only create one KeywordHit instance per document for + // a given hit. + if (keywordsFoundInThisDocument.containsKey(hit)) { + continue; + } + keywordsFoundInThisDocument.put(hit, hit); + if (artifactAttributeType == null) { hits.add(new KeywordHit(docId, makeSnippet(content, hitMatcher, hit), hit)); } else { @@ -303,7 +322,7 @@ final class RegexQuery implements KeywordSearchQuery { final String group = ccnMatcher.group("ccn"); if (CreditCardValidator.isValidCCN(group)) { hits.add(new KeywordHit(docId, makeSnippet(content, hitMatcher, hit), hit)); - }; + } } } @@ -316,8 +335,6 @@ final class RegexQuery implements KeywordSearchQuery { } } - } catch (TskCoreException ex) { - throw ex; } catch (Throwable error) { /* * NOTE: Matcher.find() is known to throw StackOverflowError in rare @@ -463,7 +480,7 @@ final class RegexQuery implements KeywordSearchQuery { if (hit.isArtifactHit()) { LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS } else { - LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getContentID())); //NON-NLS + LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getSolrObjectId())); //NON-NLS } return null; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java index ab647ec048..68c510a7e3 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermsComponentQuery.java @@ -381,7 +381,7 @@ final class TermsComponentQuery implements KeywordSearchQuery { if (hit.isArtifactHit()) { LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", searchTerm, hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS } else { - LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), hit.getContentID())); //NON-NLS + LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), hit.getSolrObjectId())); //NON-NLS } return null; } diff --git a/developers/README.txt b/developers/README.txt index ce28add84d..61fcac0963 100755 --- a/developers/README.txt +++ b/developers/README.txt @@ -1,3 +1,6 @@ +CURRENTLY NOT WORKING for NETBEANS IDE 8.2, +NETBEANS BUG REPORT: https://netbeans.org/bugzilla/show_bug.cgi?id=271811 + Common NetBeans IDE settings for the Autopsy project are stored here. All contributors are kindly asked to use these settings. @@ -7,11 +10,11 @@ Select Options to Import dialog. Push the Browse... button to pop up a file chooser. Select ~\autopsy\developers\netbeans_ide_formatting_settings.zip. NetBeans IDE will require a restart for the settings to take effect. Formatting can be done by selecting Source, Format (Alt + Shift + F). -2. To make Java code hygiene hints (lint) settings, copy the entire contents of -~\autopsy\developers\netbeans_ide_java_hint_settings to the hint/default -subdirectory of your user settings directory for the IDE. For Windows, this is -~\AppData\Roaming\NetBeans\8.2\config\Preferences\org\netbeans\modules\java\hints -\default. Restart the IDE. +2. To make Java code hygiene hints (lint) settings, select Tools, +Options, Editor tab, Hints tab. Push the Import... button to pop up the +Select Options to Import dialog. Push the Browse... button to pop up a file +chooser. Select ~\autopsy\developers\netbeans_ide_editor_settings.zip. +NetBeans IDE will require a restart for the settings to take effect diff --git a/developers/netbeans_ide_java_editor_settings.zip b/developers/netbeans_ide_java_editor_settings.zip new file mode 100755 index 0000000000..102d366250 Binary files /dev/null and b/developers/netbeans_ide_java_editor_settings.zip differ diff --git a/developers/netbeans_ide_java_hint_settings/Braces_DO_WHILE_LOOP.properties b/developers/netbeans_ide_java_hint_settings/Braces_DO_WHILE_LOOP.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Braces_DO_WHILE_LOOP.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Braces_FOR_LOOP.properties b/developers/netbeans_ide_java_hint_settings/Braces_FOR_LOOP.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Braces_FOR_LOOP.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Braces_IF.properties b/developers/netbeans_ide_java_hint_settings/Braces_IF.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Braces_IF.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Braces_WHILE_LOOP.properties b/developers/netbeans_ide_java_hint_settings/Braces_WHILE_LOOP.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Braces_WHILE_LOOP.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/EmptyStatements_IF.properties b/developers/netbeans_ide_java_hint_settings/EmptyStatements_IF.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/EmptyStatements_IF.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Imports_STAR.properties b/developers/netbeans_ide_java_hint_settings/Imports_STAR.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Imports_STAR.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Javac_DEPRECATED.properties b/developers/netbeans_ide_java_hint_settings/Javac_DEPRECATED.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Javac_DEPRECATED.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Javac_DIVISION_BY_ZERO.properties b/developers/netbeans_ide_java_hint_settings/Javac_DIVISION_BY_ZERO.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Javac_DIVISION_BY_ZERO.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Javac_EMPTY_STATEMENT_AFTER_IF.properties b/developers/netbeans_ide_java_hint_settings/Javac_EMPTY_STATEMENT_AFTER_IF.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Javac_EMPTY_STATEMENT_AFTER_IF.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Javac_FALLTHROUGH.properties b/developers/netbeans_ide_java_hint_settings/Javac_FALLTHROUGH.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Javac_FALLTHROUGH.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Javac_FINALLY.properties b/developers/netbeans_ide_java_hint_settings/Javac_FINALLY.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Javac_FINALLY.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Javac_OVERRIDES.properties b/developers/netbeans_ide_java_hint_settings/Javac_OVERRIDES.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Javac_OVERRIDES.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Javac_RAWTYPES.properties b/developers/netbeans_ide_java_hint_settings/Javac_RAWTYPES.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Javac_RAWTYPES.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Javac_SERIALIZATION.properties b/developers/netbeans_ide_java_hint_settings/Javac_SERIALIZATION.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Javac_SERIALIZATION.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Javac_UNCHECKED.properties b/developers/netbeans_ide_java_hint_settings/Javac_UNCHECKED.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Javac_UNCHECKED.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/Javac_UNNECESSARY_CAST.properties b/developers/netbeans_ide_java_hint_settings/Javac_UNNECESSARY_CAST.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/Javac_UNNECESSARY_CAST.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/MAVEN_SEARCH_HINT.properties b/developers/netbeans_ide_java_hint_settings/MAVEN_SEARCH_HINT.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/MAVEN_SEARCH_HINT.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ConsistentAccessType.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ConsistentAccessType.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ConsistentAccessType.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.HasNoArgConstructor.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.HasNoArgConstructor.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.HasNoArgConstructor.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.IdClassOverridesEqualsAndHashCode.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.IdClassOverridesEqualsAndHashCode.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.IdClassOverridesEqualsAndHashCode.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.IdDefinedInHierarchy.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.IdDefinedInHierarchy.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.IdDefinedInHierarchy.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.JPAAnnotsOnlyOnAccesor.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.JPAAnnotsOnlyOnAccesor.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.JPAAnnotsOnlyOnAccesor.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.JPQLValidation.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.JPQLValidation.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.JPQLValidation.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.LegalCombinationOfAnnotations.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.LegalCombinationOfAnnotations.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.LegalCombinationOfAnnotations.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.NoIdClassOnEntitySubclass.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.NoIdClassOnEntitySubclass.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.NoIdClassOnEntitySubclass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.NonFinalClass.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.NonFinalClass.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.NonFinalClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.OnlyEntityOrMappedSuperclassCanUseIdClass.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.OnlyEntityOrMappedSuperclassCanUseIdClass.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.OnlyEntityOrMappedSuperclassCanUseIdClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.PersistenceUnitPresent.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.PersistenceUnitPresent.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.PersistenceUnitPresent.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.PublicClass.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.PublicClass.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.PublicClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.QueriesProperlyDefined.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.QueriesProperlyDefined.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.QueriesProperlyDefined.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.SerializableClass.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.SerializableClass.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.SerializableClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.TopLevelClass.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.TopLevelClass.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.TopLevelClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.UniqueEntityName.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.UniqueEntityName.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.UniqueEntityName.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ValidAttributes.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ValidAttributes.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ValidAttributes.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ValidPrimaryTableName.properties b/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ValidPrimaryTableName.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/o.n.m.j2ee.jpa.verification.ValidPrimaryTableName.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignResultToVariable.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignResultToVariable.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignResultToVariable.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToCatchBlockParameter.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToCatchBlockParameter.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToCatchBlockParameter.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToForLoopParam.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToForLoopParam.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToForLoopParam.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToMethodParam.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToMethodParam.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.assignmentToMethodParam.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.incrementDecrementUsed.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.incrementDecrementUsed.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.incrementDecrementUsed.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.nestedAssignment.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.nestedAssignment.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.nestedAssignment.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.replaceAssignWithOpAssign.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.replaceAssignWithOpAssign.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.AssignmentIssues.replaceAssignWithOpAssign.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.classMayBeInterface.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.classMayBeInterface.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.classMayBeInterface.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalClass.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalClass.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalMethodInFinalClass.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalMethodInFinalClass.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalMethodInFinalClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalPrivateMethod.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalPrivateMethod.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.finalPrivateMethod.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.markerInterface.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.markerInterface.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.markerInterface.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.multipleTopLevelClassesInFile.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.multipleTopLevelClassesInFile.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.multipleTopLevelClassesInFile.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.noopMethodInAbstractClass.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.noopMethodInAbstractClass.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.noopMethodInAbstractClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.protectedMemberInFinalClass.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.protectedMemberInFinalClass.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.protectedMemberInFinalClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.publicConstructorInNonPublicClass.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.publicConstructorInNonPublicClass.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ClassStructure.publicConstructorInNonPublicClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.EmptyCancelForCancellableTask.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.EmptyCancelForCancellableTask.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.EmptyCancelForCancellableTask.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ExportNonAccessibleElement.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ExportNonAccessibleElement.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ExportNonAccessibleElement.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.IllegalInstanceOf.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.IllegalInstanceOf.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.IllegalInstanceOf.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.IncompatibleMask.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.IncompatibleMask.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.IncompatibleMask.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.OrganizeImports.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.OrganizeImports.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.OrganizeImports.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.OrganizeMembers.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.OrganizeMembers.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.OrganizeMembers.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.PointlessBitwiseExpression.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.PointlessBitwiseExpression.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.PointlessBitwiseExpression.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ShiftOutOfRange.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ShiftOutOfRange.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.ShiftOutOfRange.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.StaticImport.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.StaticImport.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.StaticImport.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.SuspiciousNamesCombination.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.SuspiciousNamesCombination.properties deleted file mode 100755 index cec1caef1a..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.SuspiciousNamesCombination.properties +++ /dev/null @@ -1,2 +0,0 @@ -enabled=true -groups=x, width|y, height diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.SystemOut.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.SystemOut.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.SystemOut.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.UtilityClass_1.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.UtilityClass_1.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.UtilityClass_1.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.UtilityClass_2.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.UtilityClass_2.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.UtilityClass_2.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.BroadCatchBlock.broadCatch.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.BroadCatchBlock.broadCatch.properties deleted file mode 100755 index f422278785..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.BroadCatchBlock.broadCatch.properties +++ /dev/null @@ -1,4 +0,0 @@ -catch.common=true -catch.umbrella=false -catch.umbrella.types=java.io.IOException, java.sql.SqlException -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.CloneAndCloneable.cloneInNonCloneableClass.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.CloneAndCloneable.cloneInNonCloneableClass.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.CloneAndCloneable.cloneInNonCloneableClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.CloneAndCloneable.cloneableWithoutClone.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.CloneAndCloneable.cloneableWithoutClone.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.bugs.CloneAndCloneable.cloneableWithoutClone.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.packageCls.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.packageCls.properties deleted file mode 100755 index 65e0f4d095..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.packageCls.properties +++ /dev/null @@ -1,2 +0,0 @@ -allow.enums=false -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.protectedCls.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.protectedCls.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.protectedCls.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.publicCls.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.publicCls.properties deleted file mode 100755 index 65e0f4d095..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ClassEncapsulation.publicCls.properties +++ /dev/null @@ -1,2 +0,0 @@ -allow.enums=false -enabled=false diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.packageField.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.packageField.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.packageField.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.privateField.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.privateField.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.privateField.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.protectedField.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.protectedField.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.protectedField.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.publicField.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.publicField.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.FieldEncapsulation.publicField.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.array.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.array.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.array.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.collection.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.collection.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.collection.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.date.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.date.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ParamEncapsulation.date.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.array.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.array.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.array.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.collection.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.collection.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.collection.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.date.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.date.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.encapsulation.ReturnEncapsulation.date.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.finalize.FinalizeNotProtected.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.finalize.FinalizeNotProtected.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.finalize.FinalizeNotProtected.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.jdk.AddUnderscores.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.jdk.AddUnderscores.properties deleted file mode 100755 index 8e183448b6..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.jdk.AddUnderscores.properties +++ /dev/null @@ -1,4 +0,0 @@ -also-with-underscores=false -size-binary=4 -size-decimal=3 -size-hexadecimal=4 diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.jdk.mapreduce.ForLoopToFunctionalHint.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.jdk.mapreduce.ForLoopToFunctionalHint.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.jdk.mapreduce.ForLoopToFunctionalHint.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.InitialCapacity.stringBuilder.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.InitialCapacity.stringBuilder.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.InitialCapacity.stringBuilder.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.collectionsToArray.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.collectionsToArray.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.collectionsToArray.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.constantIntern.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.constantIntern.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.constantIntern.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.getClassInsteadOfDotClass.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.getClassInsteadOfDotClass.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.getClassInsteadOfDotClass.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.lengthOneStringIndexOf.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.lengthOneStringIndexOf.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.lengthOneStringIndexOf.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.stringEqualsEmpty.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.stringEqualsEmpty.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.perf.Tiny.stringEqualsEmpty.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.suggestions.ConstantNameHint.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.suggestions.ConstantNameHint.properties deleted file mode 100755 index 90d01d9f5d..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.suggestions.ConstantNameHint.properties +++ /dev/null @@ -1,5 +0,0 @@ -immutableClasses= -maxLength=35 -minLength=0 -namePattern=[A-Z]([A-Z\\d_]*[A-Z\\d])? -onlyCheckImmutables=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.suggestions.TooStrongCast.broadTypeCast.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.suggestions.TooStrongCast.broadTypeCast.properties deleted file mode 100755 index 46ba29290c..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.hints.suggestions.TooStrongCast.broadTypeCast.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=true diff --git a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.testrunner.ui.hints.CreateTestClassHint.properties b/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.testrunner.ui.hints.CreateTestClassHint.properties deleted file mode 100755 index 541deecb31..0000000000 --- a/developers/netbeans_ide_java_hint_settings/org.netbeans.modules.java.testrunner.ui.hints.CreateTestClassHint.properties +++ /dev/null @@ -1 +0,0 @@ -enabled=false