org.sleuthkit.autopsy.casemodule.RecentCases.java Source code

Java tutorial

Introduction

Here is the source code for org.sleuthkit.autopsy.casemodule.RecentCases.java

Source

/*
 * Autopsy Forensic Browser
 *
 * Copyright 2011-2014 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.casemodule;

import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JMenuItem;
import org.apache.commons.lang.ArrayUtils;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.Presenter;
import org.openide.filesystems.FileUtil;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.Logger;

/**
 * The action in this class is to clear the list of "Recent Cases". The
 * constructor is called when the autopsy is running. All the method to create
 * and modify the properties file are within this class
 */
final class RecentCases extends CallableSystemAction implements Presenter.Menu {

    static final int LENGTH = 6;
    static final String NAME_PROP_KEY = "LBL_RecentCase_Name"; //NON-NLS
    static final String PATH_PROP_KEY = "LBL_RecentCase_Path"; //NON-NLS
    static final RecentCase BLANK_RECENTCASE = new RecentCase("", "");

    private final static RecentCases INSTANCE = new RecentCases();

    private Deque<RecentCase> recentCases; // newest case is last case

    /**
     * Gets the instance of the RecentCases singleton.
     *
     *
     * @return INSTANCE the RecentCases singleton
     */
    static public RecentCases getInstance() {
        INSTANCE.refreshRecentCases();
        return INSTANCE;
    }

    /**
     * the constructor
     */
    private RecentCases() {

        for (int i = 0; i < LENGTH; i++) {
            try {
                if (ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, nameKey(i)) == null) {
                    ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, nameKey(i), "");
                }
                if (ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, pathKey(i)) == null) {
                    ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, pathKey(i), "");
                }
            } catch (Exception e) {

            }
        }

        // Load recentCases from properties
        recentCases = new LinkedList<RecentCase>();

        for (int i = 0; i < LENGTH; i++) {
            final RecentCase rc = new RecentCase(getName(i), getPath(i));
            if (!rc.equals(BLANK_RECENTCASE)) {
                recentCases.add(rc);
            }
        }

        refreshRecentCases();
    }

    private static void validateCaseIndex(int i) {
        if (i < 0 || i >= LENGTH) {
            throw new IllegalArgumentException(
                    NbBundle.getMessage(RecentCases.class, "RecentCases.exception.caseIdxOutOfRange.msg", i));
        }
    }

    private static String nameKey(int i) {
        validateCaseIndex(i);
        return NAME_PROP_KEY + Integer.toString(i + 1);
    }

    private static String pathKey(int i) {
        validateCaseIndex(i);
        return PATH_PROP_KEY + Integer.toString(i + 1);
    }

    private String getName(int i) {
        try {
            return ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, nameKey(i));
        } catch (Exception e) {
            return null;
        }
    }

    private String getPath(int i) {
        try {
            return ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, pathKey(i));
        } catch (Exception e) {
            return null;
        }
    }

    private void setName(int i, String name) {
        ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, nameKey(i), name);
    }

    private void setPath(int i, String path) {
        ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, pathKey(i), path);
    }

    private void setRecentCase(int i, RecentCase rc) {
        setName(i, rc.name);
        setPath(i, rc.path);
    }

    private static final class RecentCase {

        String name, path;

        /**
         * @param name The case name or "" if a blank placeholder case
         * @param path A normalized path (via FileUtil.normalizePath(path)) or
         *             "" if a blank placeholder case
         */
        private RecentCase(String name, String path) {
            this.name = name;
            this.path = path;
        }

        /**
         * Used when creating RecentCases with external data. The path must be
         * normalized so that duplicate cases always have the same path.
         *
         * @param name       The case name.
         * @param unsafePath The (potentially un-normalized) case path.
         *
         * @return The created RecentCase.s
         */
        static RecentCase createSafe(String name, String unsafePath) {
            return new RecentCase(name, FileUtil.normalizePath(unsafePath));
        }

        /**
         * Does this case exist or was it manually deleted or moved?
         *
         * @return true if the case exists, false otherwise
         */
        boolean exists() {
            return !(name.equals("") || path.equals("") || !new File(path).exists());
        }

        // netbeans autogenerated hashCode
        @Override
        public int hashCode() {
            int hash = 7;
            hash = 13 * hash + (this.name != null ? this.name.hashCode() : 0);
            hash = 13 * hash + (this.path != null ? this.path.hashCode() : 0);
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final RecentCase other = (RecentCase) obj;
            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
                return false;
            }
            if ((this.path == null) ? (other.path != null) : !this.path.equals(other.path)) {
                return false;
            }
            return true;
        }
    }

    /**
     * Refresh the current list of cases, removing any cases that no longer
     * exist.
     */
    private void refreshRecentCases() {
        List<RecentCase> toDelete = new ArrayList<RecentCase>();
        for (RecentCase rc : recentCases) {
            if (!rc.exists()) {
                toDelete.add(rc);
            }
        }
        for (RecentCase deleteMe : toDelete) {
            removeRecentCase(deleteMe.name, deleteMe.path);
        }
    }

    private void storeRecentCases() throws IOException {
        int i = 0;

        // store however many recent cases exist
        for (RecentCase rc : recentCases) {
            setRecentCase(i, rc);
            i++;
        }

        // set the rest to blanks
        while (i < LENGTH) {
            setRecentCase(i, BLANK_RECENTCASE);
            i++;
        }

    }

    /**
     * Gets a menu item that can present this action in a JMenu.
     *
     * @return menuItem the representation menu item for this action
     */
    @Override
    public JMenuItem getMenuPresenter() {
        return new UpdateRecentCases();
    }

    /**
     * This action is used to clear all the recent cases menu options.
     *
     * @param e the action event
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        UpdateRecentCases.hasRecentCase = false;

        recentCases.clear();

        try {
            // clear the properties file
            storeRecentCases();
        } catch (Exception ex) {
            Logger.getLogger(RecentCases.class.getName()).log(Level.WARNING,
                    "Error: Could not clear the properties file.", ex); //NON-NLS
        }
    }

    private void addRecentCase(RecentCase rc) {
        // remove the case if it's already in the list
        recentCases.remove(rc);

        // make space if it's needed
        if (recentCases.size() == LENGTH) {
            recentCases.remove();
        }

        recentCases.add(rc);
    }

    /**
     * Adds a recent case to the top of the list. If the case is already in the
     * list, it will be removed before the new entry is added.
     *
     * @param name       the name of the recent case to be added
     * @param unsafePath the (potentially un-normalized) path of the case config
     *                   file
     */
    public void addRecentCase(String name, String unsafePath) {
        RecentCase rc = RecentCase.createSafe(name, unsafePath);

        addRecentCase(rc);

        this.getMenuPresenter().setVisible(true); // invoke the contructor again

        try {
            storeRecentCases();
        } catch (Exception ex) {
            Logger.getLogger(RecentCases.class.getName()).log(Level.WARNING,
                    "Error: Could not update the properties file.", ex); //NON-NLS
        }
    }

    /**
     * This method is used to update the name and path of a RecentCase.
     *
     * @param oldName the old recent case name
     * @param oldPath the old recent case config file path
     * @param newName the new recent case name
     * @param newPath the new recent case config file path
     *
     * @throws Exception
     */
    public void updateRecentCase(String oldName, String oldPath, String newName, String newPath) throws Exception {
        RecentCase oldRc = RecentCase.createSafe(oldName, oldPath);
        RecentCase newRc = RecentCase.createSafe(newName, newPath);

        // remove all instances of the old recent case
        recentCases.removeAll(Arrays.asList(oldRc));

        addRecentCase(newRc);

        this.getMenuPresenter().setVisible(true); // invoke the contructor again

        try {
            storeRecentCases();
        } catch (Exception ex) {
            Logger.getLogger(RecentCases.class.getName()).log(Level.WARNING,
                    "Error: Could not update the properties file.", ex); //NON-NLS
        }
    }

    /**
     * Gets the total number of recent cases
     *
     * @return total total number of recent cases
     */
    public int getTotalRecentCases() {
        return recentCases.size();
    }

    /**
     * This method is used to remove the selected name and path of the
     * RecentCase
     *
     * @param name the case name to be removed from the recent case
     * @param path the config file path to be removed from the recent case
     */
    public void removeRecentCase(String name, String path) {
        RecentCase rc = RecentCase.createSafe(name, path);

        // remove all instances of the old recent case
        recentCases.removeAll(Arrays.asList(rc));

        this.getMenuPresenter().setVisible(true); // invoke the contructor again

        // write the properties file
        try {
            storeRecentCases();
        } catch (Exception ex) {
            Logger.getLogger(RecentCases.class.getName()).log(Level.WARNING,
                    "Error: Could not update the properties file.", ex); //NON-NLS
        }
    }

    /**
     * Gets the recent case names.
     *
     * @return caseNames An array String[LENGTH - 1], newest case first, with any
     * extra spots filled with ""
     */
    public String[] getRecentCaseNames() {
        String[] caseNames = new String[LENGTH];

        Iterator<RecentCase> mostRecentFirst = recentCases.descendingIterator();
        int i = 0;
        String currentCaseName = null;
        try {
            currentCaseName = Case.getCurrentCase().getName();
        } catch (IllegalStateException ex) {
            // in case there is no current case.
        }

        while (mostRecentFirst.hasNext()) {
            String name = mostRecentFirst.next().name;
            if ((currentCaseName != null && !name.equals(currentCaseName)) || currentCaseName == null) {
                // exclude currentCaseName from the caseNames[]
                caseNames[i] = name;
                i++;
            }
        }

        while (i < caseNames.length) {
            caseNames[i] = "";
            i++;
        }

        // return last 5 case names
        return (String[]) ArrayUtils.subarray(caseNames, 0, LENGTH - 1);
    }

    /**
     * Gets the recent case paths.
     *
     * @return casePaths An array String[LENGTH - 1], newest case first, with any
     * extra spots filled with ""
     */
    public String[] getRecentCasePaths() {
        String[] casePaths = new String[LENGTH];
        String currentCasePath = null;
        try {
            currentCasePath = Case.getCurrentCase().getCaseMetadata().getFilePath().toString();
        } catch (IllegalStateException ex) {
            // in case there is no current case.
        }

        Iterator<RecentCase> mostRecentFirst = recentCases.descendingIterator();
        int i = 0;
        while (mostRecentFirst.hasNext()) {
            String path = mostRecentFirst.next().path;
            if ((currentCasePath != null && !path.equals(currentCasePath)) || currentCasePath == null) {
                // exclude currentCasePath from the casePaths[]
                casePaths[i] = path;
                i++;
            }
        }

        while (i < casePaths.length) {
            casePaths[i] = "";
            i++;
        }

        // return last 5 case paths
        return (String[]) ArrayUtils.subarray(casePaths, 0, LENGTH - 1);
    }

    /**
     * This method does nothing. Use the actionPerformed instead of this method.
     */
    @Override
    public void performAction() {
    }

    /**
     * Gets the name of this action. This may be presented as an item in a menu.
     *
     * @return actionName
     */
    @Override
    public String getName() {
        //return NbBundle.getMessage(RecentCases.class, "CTL_RecentCases");
        return NbBundle.getMessage(RecentCases.class, "RecentCases.getName.text");
    }

    /**
     * Gets the HelpCtx associated with implementing object
     *
     * @return HelpCtx or HelpCtx.DEFAULT_HELP
     */
    @Override
    public HelpCtx getHelpCtx() {
        return HelpCtx.DEFAULT_HELP;
    }
}