updates of gui and codacy items

This commit is contained in:
Greg DiCristofaro
2020-03-02 14:39:08 -05:00
parent 83acf735fa
commit 0dfead3699
12 changed files with 208 additions and 99 deletions
@@ -19,7 +19,7 @@
package org.sleuthkit.autopsy.centralrepository.datamodel;
/**
*
* the database choices available for central repo
*/
public class CentralRepoDbChoice {
public static final CentralRepoDbChoice DISABLED = new CentralRepoDbChoice("Disabled", CentralRepoPlatforms.DISABLED);
@@ -23,7 +23,6 @@ import java.sql.SQLException;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
@@ -38,12 +37,12 @@ public class CentralRepoDbManager {
private static CentralRepoDbChoice SAVED_CHOICE = null;
private static volatile CentralRepoDbChoice SAVED_CHOICE = null;
/**
* Save the selected platform to the config file.
*/
public static CentralRepoDbChoice saveDbChoice(CentralRepoDbChoice choice) {
public static synchronized CentralRepoDbChoice saveDbChoice(CentralRepoDbChoice choice) {
choice = (choice == null) ? CentralRepoDbChoice.DISABLED : choice;
SAVED_CHOICE = choice;
ModuleSettings.setConfigSetting("CentralRepository", "db.selectedPlatform", choice.getSettingKey());
@@ -53,7 +52,7 @@ public class CentralRepoDbManager {
/**
* Load the selectedPlatform boolean from the config file, if it is set.
*/
public static CentralRepoDbChoice getSavedDbChoice() {
public static synchronized CentralRepoDbChoice getSavedDbChoice() {
if (SAVED_CHOICE == null) {
String selectedPlatformString = ModuleSettings.getConfigSetting("CentralRepository", "db.selectedPlatform"); // NON-NLS
SAVED_CHOICE = fromKey(selectedPlatformString);
@@ -352,6 +351,7 @@ public class CentralRepoDbManager {
// Even if we fail to close the existing connections, make sure that we
// save the new connection settings, so an Autopsy restart will correctly
// start with the new settings.
CentralRepoDbUtil.setUseCentralRepo(selectedDbChoice != CentralRepoDbChoice.DISABLED);
saveDbChoice(selectedDbChoice);
CentralRepoDbConnectivityManager selectedDbSettings = getSelectedSettings();
@@ -19,7 +19,7 @@
package org.sleuthkit.autopsy.centralrepository.datamodel;
/**
*
* describes the possible database types for central repo
*/
public enum CentralRepoPlatforms {
DISABLED,
@@ -1,14 +1,30 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*
* Autopsy Forensic Browser
*
* Copyright 2012-2020 Basis Technology Corp.
*
* Copyright 2012 42six Solutions.
* Contact: aebadirad <at> 42six <dot> com
* Project Contact/Architect: carrier <at> sleuthkit <dot> 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.centralrepository.datamodel;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.core.UserPreferencesException;
import org.sleuthkit.autopsy.coreutils.Logger;
@@ -18,8 +34,7 @@ import org.sleuthkit.autopsy.coreutils.TextConverterException;
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
/**
*
* @author gregd
* handles saving and loading of postgres settings for central repo
*/
public class CentralRepoPostgresSettingsUtil {
private final static Logger LOGGER = Logger.getLogger(CentralRepoPostgresSettingsUtil.class.getName());
@@ -68,13 +83,18 @@ public class CentralRepoPostgresSettingsUtil {
private static void handleTry(TryHandler handler) {
try {
handler.op();
handler.operation();
}
catch (CentralRepoException e) {
LOGGER.log(Level.WARNING, "There was an error in converting central repo postgres settings", e);
}
catch (CentralRepoException e) {}
}
/**
* an action that potentially throws an exception
*/
private interface TryHandler {
public void op() throws CentralRepoException;
void operation() throws CentralRepoException;
}
@@ -1,7 +1,20 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
* Central Repository
*
* Copyright 2015-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.centralrepository.datamodel;
@@ -10,7 +23,7 @@ import java.util.regex.Pattern;
/**
*
* @author gregd
* POJO for postgres settings
*/
public class PostgresConnectionSettings {
private final static String DB_NAMES_REGEX = "[a-z][a-z0-9_]*"; // only lower case
@@ -1,23 +1,38 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
* Central Repository
*
* Copyright 2015-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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.centralrepository.datamodel;
/**
*
* @author gregd
* interface to load or save postgres settings
*/
public interface PostgresSettingsLoader {
PostgresConnectionSettings loadSettings();
void saveSettings(PostgresConnectionSettings settings);
public static PostgresSettingsLoader CUSTOM_LOADER = new Custom();
public static PostgresSettingsLoader MULTIUSER_LOADER = new MultiUser();
PostgresSettingsLoader CUSTOM_LOADER = new Custom();
PostgresSettingsLoader MULTIUSER_LOADER = new MultiUser();
static class Custom implements PostgresSettingsLoader {
/**
* loads and saves custom postgres settings
*/
class Custom implements PostgresSettingsLoader {
@Override
public PostgresConnectionSettings loadSettings() {
return CentralRepoPostgresSettingsUtil.loadCustomSettings();
@@ -30,13 +45,21 @@ public interface PostgresSettingsLoader {
}
static class MultiUser implements PostgresSettingsLoader {
/**
* loads multi user postgres settings to be used with central repo
* NOTE: does not save settings on save operation as this is merely a proxy
*/
class MultiUser implements PostgresSettingsLoader {
@Override
public PostgresConnectionSettings loadSettings() {
return CentralRepoPostgresSettingsUtil.loadMultiUserSettings();
}
/**
* no need to save since this is just a proxy to multi user settings
* @param settings the settings to save
*/
@Override
public void saveSettings(PostgresConnectionSettings settings) {}
}
@@ -33,7 +33,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener;
import org.sleuthkit.autopsy.core.RuntimeProperties;
@@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.HeadlessException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -50,8 +51,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
import org.sleuthkit.autopsy.centralrepository.datamodel.DatabaseTestResult;
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepoFactory;
import org.sleuthkit.autopsy.core.UserPreferences;
/**
@@ -66,16 +65,15 @@ public class EamDbSettingsDialog extends JDialog {
private static final DbChoiceRenderer DB_CHOICE_RENDERER = new DbChoiceRenderer();
private static boolean isDbChoiceSelectable(CentralRepoDbChoice item) {
if (item == CentralRepoDbChoice.POSTGRESQL_MULTIUSER && !UserPreferences.getIsMultiUserModeEnabled()) {
return false;
}
else {
return true;
}
return (item != CentralRepoDbChoice.POSTGRESQL_MULTIUSER || UserPreferences.getIsMultiUserModeEnabled());
}
/**
* handles displaying and rendering drop down menu for database choices in central repo
*/
private static class DbChoiceRenderer extends BasicComboBoxRenderer {
private static final long serialVersionUID = 1L;
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
@@ -94,6 +92,9 @@ public class EamDbSettingsDialog extends JDialog {
private final TextBoxChangedListener textBoxChangedListener;
private final CentralRepoDbManager manager = new CentralRepoDbManager();
public EamDbSettingsDialog() {
this(null);
}
/**
* Creates new form EamDbSettingsDialog
@@ -102,7 +103,7 @@ public class EamDbSettingsDialog extends JDialog {
"EamDbSettingsDialog.lbSingleUserSqLite.text=SQLite should only be used by one examiner at a time.",
"EamDbSettingsDialog.lbDatabaseType.text=Database Type :",
"EamDbSettingsDialog.fcDatabasePath.title=Select location for central_repository.db"})
public EamDbSettingsDialog() {
public EamDbSettingsDialog(CentralRepoDbChoice initialMenuItem) {
super((JFrame) WindowManager.getDefault().getMainWindow(),
Bundle.EamDbSettingsDialog_title_text(),
true);
@@ -129,24 +130,24 @@ public class EamDbSettingsDialog extends JDialog {
}
});
setupDbChoice();
customizeComponents();
setupDbChoice(initialMenuItem);
valid();
display();
}
private void setupDbChoice() {
private void setupDbChoice(CentralRepoDbChoice initialMenuItem) {
// setup initially selected item
CentralRepoDbChoice toSelect =
CentralRepoDbChoice toSelect = (initialMenuItem == null) ?
(Arrays.asList(CentralRepoDbChoice.DB_CHOICES).contains(manager.getSelectedDbChoice())) ?
manager.getSelectedDbChoice() :
CentralRepoDbChoice.DB_CHOICES[0];
cbDatabaseType.setSelectedItem(toSelect);
CentralRepoDbChoice.DB_CHOICES[0] :
initialMenuItem;
// set the renderer so item is unselectable if inappropriate
cbDatabaseType.setRenderer(DB_CHOICE_RENDERER);
changeDbSelection(toSelect);
}
@@ -188,22 +189,7 @@ public class EamDbSettingsDialog extends JDialog {
manager.createDb();
}
catch (CentralRepoException e) {
// in the event that there is a failure to connect, notify user with corresponding message
String errorMessage = "";
if (manager == null || manager.getSelectedDbChoice() == null) {
errorMessage = "";
}
else if (manager.getSelectedDbChoice().getDbPlatform() == CentralRepoPlatforms.POSTGRESQL) {
errorMessage = Bundle.EamDbSettingsDialog_okButton_createPostgresDbError_message();
}
else if (manager.getSelectedDbChoice().getDbPlatform() == CentralRepoPlatforms.SQLITE) {
errorMessage = Bundle.EamDbSettingsDialog_okButton_createSQLiteDbError_message();
}
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
errorMessage,
Bundle.EamDbSettingsDialog_okButton_createDbError_title(),
JOptionPane.WARNING_MESSAGE);
onPromptStatusError(manager);
}
if (dialog != null)
@@ -213,6 +199,28 @@ public class EamDbSettingsDialog extends JDialog {
return (manager.getStatus() == DatabaseTestResult.TESTEDOK);
}
/**
* when an error occurs while going through promptTestStatusWarning, this method is called
* @param manager1 the manager to use as service class
* @throws HeadlessException
*/
private static void onPromptStatusError(CentralRepoDbManager manager1) {
// in the event that there is a failure to connect, notify user with corresponding message
String errorMessage = "";
if (manager1 == null || manager1.getSelectedDbChoice() == null) {
errorMessage = "";
} else if (manager1.getSelectedDbChoice().getDbPlatform() == CentralRepoPlatforms.POSTGRESQL) {
errorMessage = Bundle.EamDbSettingsDialog_okButton_createPostgresDbError_message();
} else if (manager1.getSelectedDbChoice().getDbPlatform() == CentralRepoPlatforms.SQLITE) {
errorMessage = Bundle.EamDbSettingsDialog_okButton_createSQLiteDbError_message();
}
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
errorMessage,
Bundle.EamDbSettingsDialog_okButton_createDbError_title(),
JOptionPane.WARNING_MESSAGE);
}
/**
@@ -575,15 +583,20 @@ public class EamDbSettingsDialog extends JDialog {
private void cbDatabaseTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbDatabaseTypeActionPerformed
CentralRepoDbChoice selectedItem = (CentralRepoDbChoice) cbDatabaseType.getSelectedItem();
changeDbSelection(selectedItem);
}//GEN-LAST:event_cbDatabaseTypeActionPerformed
private void changeDbSelection(CentralRepoDbChoice selectedItem) {
if (isDbChoiceSelectable(selectedItem)) {
manager.setSelctedDbChoice(selectedItem);
cbDatabaseType.setSelectedItem(selectedItem);
}
else {
cbDatabaseType.setSelectedItem(manager.getSelectedDbChoice());
}
customizeComponents();
}//GEN-LAST:event_cbDatabaseTypeActionPerformed
}
private void updateFullDbPath() {
dataBaseFileTextArea.setText(tfDatabasePath.getText() + File.separator + SqliteCentralRepoSettings.DEFAULT_DBNAME);
@@ -43,8 +43,8 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.PostgresCentralRepoSettings;
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.HeadlessException;
import java.util.MissingResourceException;
import java.util.logging.Level;
/**
@@ -53,7 +53,10 @@ import java.util.logging.Level;
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
private static interface OnSettingsChangeListener {
/**
* listener to handle when settings change and an instance of this class needs to be notified.
*/
private interface OnSettingsChangeListener {
void onSettingsChange();
}
@@ -83,7 +86,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
ingestJobEventListener = new IngestJobEventPropertyChangeListener();
// most recently created panel will receive update events
GlobalSettingsPanel.setSettingsChangeListener(() -> GlobalSettingsPanel.this.load());
GlobalSettingsPanel.setSettingsChangeListener(() -> load());
initComponents();
customizeComponents();
addIngestJobEventsListener();
@@ -107,8 +110,18 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
updateDatabase(this);
}
private static boolean invokeCrChoice(Component parent) {
EamDbSettingsDialog dialog = new EamDbSettingsDialog();
/**
* invokes central repository database choice selection as well as input for necessary configuration
* @param parent the parent component for displaying dialogs
* @param initialSelection if non-null, the menu item will be set to this choice; if null,
* the currently selected db choice will be selected
* @return true if there was a change
*/
private static boolean invokeCrChoice(Component parent, CentralRepoDbChoice initialSelection) {
EamDbSettingsDialog dialog = (initialSelection != null) ?
new EamDbSettingsDialog(initialSelection) :
new EamDbSettingsDialog();
if (dialog.wasConfigurationChanged()) {
updateDatabase(parent);
return true;
@@ -128,8 +141,9 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
* @param muCurrentlySelected if multi user settings are currently enabled as of most recent change
*/
@NbBundle.Messages({
"GlobalSettingsPanel.onMultiUserChange.enable.title=Enable Central Repository?",
"GlobalSettingsPanel.onMultiUserChange.enable.description=Do you want to enable Central Repository using these settings?",
"GlobalSettingsPanel.onMultiUserChange.enable.title=Use with Central Repository?",
"GlobalSettingsPanel.onMultiUserChange.enable.description=Do you want to update the Central Repository to use this PostgreSQL database?",
"GlobalSettingsPanel.onMultiUserChange.enable.description2=The Central Repository stores hash values and accounts from past cases.",
"GlobalSettingsPanel.onMultiUserChange.disabledMu.title=Central Repository Change Necessary",
"GlobalSettingsPanel.onMultiUserChange.disabledMu.description=Since mult-user cases have been disabled, 'PostgreSQL using multi-user settings' is no longer a valid option for Central Repository. Would you like to choose another Central Repository database?"
})
@@ -139,48 +153,77 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
if (!muPreviouslySelected && muCurrentlySelected) {
SwingUtilities.invokeLater(() -> {
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(parent,
NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.enable.description"),
"<html><body>" +
"<div style='width: 400px;'>" +
"<p>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.enable.description") + "</p>" +
"<p style='margin-top: 10px'>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.enable.description2") + "</p>" +
"</div>" +
"</body></html>",
NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.enable.title"),
JOptionPane.YES_NO_OPTION)) {
// setup database for CR
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.POSTGRESQL_MULTIUSER);
HandleDbChange(parent);
handleDbChange(parent);
}
});
}
// moving from selected to not selected && 'PostgreSQL using multi-user settings' is selected
else if (muPreviouslySelected && !muCurrentlySelected && crMultiUser) {
SwingUtilities.invokeLater(() -> {
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(parent,
"<html><body>" +
"<div style='width: 400px;'>" +
"<p>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.disabledMu.description") + "</p>" +
"</div>" +
"</body></html>",
NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.disabledMu.title"),
JOptionPane.YES_NO_OPTION)) {
// present user with central repository choice
invokeCrChoice(parent);
}
else {
// disable central repository
CentralRepoDbUtil.setUseCentralRepo(false);
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.DISABLED);
}
GlobalSettingsPanel.onSettingsChange();
askForCentralRepoDbChoice(parent);
});
}
// changing multi-user settings connection && 'PostgreSQL using multi-user settings' is selected
else if (muPreviouslySelected && muCurrentlySelected && crMultiUser) {
// test databse for CR change
HandleDbChange(parent);
handleDbChange(parent);
}
}
/**
* when a user must select a new database other than using database from multi user settings
* @param parent the parent component to use for displaying dialogs in reference
*/
private static void askForCentralRepoDbChoice(Component parent) {
// disable central repository until user makes choice
CentralRepoDbUtil.setUseCentralRepo(false);
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.DISABLED);
Object[] options = {
"Use SQLite",
"Configure PostgreSQL",
"Disable Central Repository"
};
int result = JOptionPane.showOptionDialog(
parent,
"<html><body>" +
"<div style='width: 400px;'>" +
"<p>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.disabledMu.description") + "</p>" +
"</div>" +
"</body></html>",
NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.disabledMu.title"),
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE,
null,
options,
options[0]
);
if (JOptionPane.YES_OPTION == result) {
invokeCrChoice(parent, CentralRepoDbChoice.SQLITE);
}
else if (JOptionPane.NO_OPTION == result) {
invokeCrChoice(parent, CentralRepoDbChoice.POSTGRESQL_CUSTOM);
}
GlobalSettingsPanel.onSettingsChange();
}
private static void HandleDbChange(Component parent) {
private static void handleDbChange(Component parent) {
boolean successful = EamDbSettingsDialog.testStatusAndCreate(parent, new CentralRepoDbManager());
if (successful) {
updateDatabase(parent);
@@ -540,7 +583,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private void bnDbConfigureActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDbConfigureActionPerformed
store();
boolean changed = invokeCrChoice(this);
boolean changed = invokeCrChoice(this, null);
if (changed) {
load(); // reload db settings content and update buttons
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
@@ -34,7 +34,6 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import java.awt.Cursor;
import java.util.logging.Level;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.core.UserPreferencesException;
@@ -763,10 +762,7 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
private static boolean areCaseDbConnectionEqual(CaseDbConnectionInfo a, CaseDbConnectionInfo b) {
if (a == null || b == null) {
if (a == null && b == null)
return true;
else
return false;
return (a == null && b == null);
}
return