Package org.sleuthkit.autopsy.timeline

Source Code of org.sleuthkit.autopsy.timeline.TimeLineController$AutopsyIngestJobListener

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

import java.awt.HeadlessException;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.NumberFormat;
import java.time.ZoneId;
import java.util.Collection;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.TimeZone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import javafx.application.Platform;
import javafx.beans.Observable;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.ReadOnlyListProperty;
import javafx.beans.property.ReadOnlyListWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.Immutable;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Interval;
import org.joda.time.ReadablePeriod;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import static org.sleuthkit.autopsy.casemodule.Case.Events.CURRENT_CASE;
import static org.sleuthkit.autopsy.casemodule.Case.Events.DATA_SOURCE_ADDED;
import org.sleuthkit.autopsy.coreutils.History;
import org.sleuthkit.autopsy.coreutils.LoggedTask;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.timeline.events.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.events.db.EventsRepository;
import org.sleuthkit.autopsy.timeline.events.type.EventType;
import org.sleuthkit.autopsy.timeline.filters.Filter;
import org.sleuthkit.autopsy.timeline.filters.TypeFilter;
import org.sleuthkit.autopsy.timeline.utils.IntervalUtils;
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD;
import org.sleuthkit.autopsy.timeline.zooming.EventTypeZoomLevel;
import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;

/** Controller in the MVC design along with model = {@link FilteredEventsModel}
* and views = {@link TimeLineView}. Forwards interpreted user gestures form
* views to model. Provides model to view. Is entry point for timeline module.
*
* Concurrency Policy:<ul>
* <li>Since filteredEvents is internally synchronized, only compound access to
* it needs external synchronization</li>
* * <li>Since eventsRepository is internally synchronized, only compound
* access to it needs external synchronization <li>
* <li>Other state including listeningToAutopsy, mainFrame, viewMode, and the
* listeners should only be accessed with this object's intrinsic lock held
* </li>
* <ul>
*/
public class TimeLineController {

    private static final Logger LOGGER = Logger.getLogger(TimeLineController.class.getName());

    private static final String DO_REPOPULATE_MESSAGE = "The events databse was prevously populated while ingest was running.\n" + "Some events may not have been populated or may have been populated inaccurately.\n" + "Do you want to repopulate the events database now?";

    private static final ReadOnlyObjectWrapper<TimeZone> timeZone = new ReadOnlyObjectWrapper<>(TimeZone.getDefault());

    public static ZoneId getTimeZoneID() {
        return timeZone.get().toZoneId();
    }

    public static DateTimeFormatter getZonedFormatter() {
        return DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss").withZone(getJodaTimeZone());
    }

    public static DateTimeZone getJodaTimeZone() {
        return DateTimeZone.forTimeZone(getTimeZone().get());
    }

    public static ReadOnlyObjectProperty<TimeZone> getTimeZone() {
        return timeZone.getReadOnlyProperty();
    }

    private final ExecutorService executor = Executors.newSingleThreadExecutor();

    private final ReadOnlyListWrapper<Task<?>> tasks = new ReadOnlyListWrapper<>(FXCollections.observableArrayList());

    private final ReadOnlyDoubleWrapper progress = new ReadOnlyDoubleWrapper(-1);

    private final ReadOnlyStringWrapper message = new ReadOnlyStringWrapper();

    private final ReadOnlyStringWrapper taskTitle = new ReadOnlyStringWrapper();

    synchronized public ReadOnlyListProperty<Task<?>> getTasks() {
        return tasks.getReadOnlyProperty();
    }

    synchronized public ReadOnlyDoubleProperty getProgress() {
        return progress.getReadOnlyProperty();
    }

    synchronized public ReadOnlyStringProperty getMessage() {
        return message.getReadOnlyProperty();
    }

    synchronized public ReadOnlyStringProperty getTaskTitle() {
        return taskTitle.getReadOnlyProperty();
    }

    @GuardedBy("this")
    private TimeLineTopComponent mainFrame;

    //are the listeners currently attached
    @GuardedBy("this")
    private boolean listeningToAutopsy = false;

    private final PropertyChangeListener caseListener;

    private final PropertyChangeListener ingestJobListener = new AutopsyIngestJobListener();

    private final PropertyChangeListener ingestModuleListener = new AutopsyIngestModuleListener();

    @GuardedBy("this")
    private final ReadOnlyObjectWrapper<VisualizationMode> viewMode = new ReadOnlyObjectWrapper<>(VisualizationMode.COUNTS);

    synchronized public ReadOnlyObjectProperty<VisualizationMode> getViewMode() {
        return viewMode.getReadOnlyProperty();
    }

    @GuardedBy("filteredEvents")
    private final FilteredEventsModel filteredEvents;

    @GuardedBy("eventsRepository")
    private final EventsRepository eventsRepository;

    @GuardedBy("this")
    private final ZoomParams InitialZoomState;

    @GuardedBy("this")
    private final History<ZoomParams> historyManager = new History<>();

    //all members should be access with the intrinsict lock of this object held
    //selected events (ie shown in the result viewer)
    @GuardedBy("this")
    private final ObservableList<Long> selectedEventIDs = FXCollections.<Long>synchronizedObservableList(FXCollections.<Long>observableArrayList());

    /**
     * @return an unmodifiable list of the selected event ids
     */
    synchronized public ObservableList<Long> getSelectedEventIDs() {
        return selectedEventIDs;
    }

    @GuardedBy("this")
    private final ReadOnlyObjectWrapper<Interval> selectedTimeRange = new ReadOnlyObjectWrapper<>();

    /**
     * @return a read only view of the selected interval.
     */
    synchronized public ReadOnlyObjectProperty<Interval> getSelectedTimeRange() {
        return selectedTimeRange.getReadOnlyProperty();
    }

    public ReadOnlyBooleanProperty getNewEventsFlag() {
        return newEventsFlag.getReadOnlyProperty();
    }

    private final ReadOnlyBooleanWrapper needsHistogramRebuild = new ReadOnlyBooleanWrapper(false);

    public ReadOnlyBooleanProperty getNeedsHistogramRebuild() {
        return needsHistogramRebuild.getReadOnlyProperty();
    }

    synchronized public ReadOnlyBooleanProperty getCanAdvance() {
        return historyManager.getCanAdvance();
    }

    synchronized public ReadOnlyBooleanProperty getCanRetreat() {
        return historyManager.getCanRetreat();
    }
    private final ReadOnlyBooleanWrapper newEventsFlag = new ReadOnlyBooleanWrapper(false);

    public TimeLineController() {
        //initalize repository and filteredEvents on creation
        eventsRepository = new EventsRepository(historyManager.currentState());

        filteredEvents = eventsRepository.getEventsModel();
        InitialZoomState = new ZoomParams(filteredEvents.getSpanningInterval(),
                EventTypeZoomLevel.BASE_TYPE,
                Filter.getDefaultFilter(),
                DescriptionLOD.SHORT);
        historyManager.advance(InitialZoomState);

        //persistent listener instances
        caseListener = new AutopsyCaseListener();
    }

    /** @return a shared events model */
    public FilteredEventsModel getEventsModel() {
        return filteredEvents;
    }

    public void applyDefaultFilters() {
        pushFilters(Filter.getDefaultFilter());
    }

    public void zoomOutToActivity() {
        Interval boundingEventsInterval = filteredEvents.getBoundingEventsInterval();
        advance(filteredEvents.getRequestedZoomParamters().get().withTimeRange(boundingEventsInterval));
    }

    boolean rebuildRepo() {
        if (IngestManager.getInstance().isIngestRunning()) {
            //confirm timeline during ingest
            if (showIngestConfirmation() != JOptionPane.YES_OPTION) {
                return false;
            }
        }
        LOGGER.log(Level.INFO, "Beginning generation of timeline");
        try {
            SwingUtilities.invokeLater(() -> {
                if (mainFrame != null) {
                    mainFrame.close();
                }
            });
            final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
            final long lastObjId = sleuthkitCase.getLastObjectId();
            final long lastArtfID = getCaseLastArtifactID(sleuthkitCase);
            final Boolean injestRunning = IngestManager.getInstance().isIngestRunning();
            //TODO: verify this locking is correct? -jm
            synchronized (eventsRepository) {
                eventsRepository.rebuildRepository(() -> {

                    synchronized (eventsRepository) {
                        eventsRepository.recordLastObjID(lastObjId);
                        eventsRepository.recordLastArtifactID(lastArtfID);
                        eventsRepository.recordWasIngestRunning(injestRunning);
                    }
                    synchronized (TimeLineController.this) {
                        needsHistogramRebuild.set(true);
                        needsHistogramRebuild.set(false);
                        showWindow();
                    }

                    Platform.runLater(() -> {
                        newEventsFlag.set(false);
                        TimeLineController.this.showFullRange();
                    });
                });
            }
        } catch (TskCoreException ex) {
            LOGGER.log(Level.SEVERE, "Error when generating timeline, ", ex);
            return false;
        }
        return true;
    }

    public void showFullRange() {
        synchronized (filteredEvents) {
            pushTimeRange(filteredEvents.getSpanningInterval());
        }
    }

    synchronized public void closeTimeLine() {
        if (mainFrame != null) {
            listeningToAutopsy = false;
            IngestManager.getInstance().removeIngestModuleEventListener(ingestModuleListener);
            IngestManager.getInstance().removeIngestJobEventListener(ingestJobListener);
            Case.removePropertyChangeListener(caseListener);
            mainFrame.close();
            mainFrame.setVisible(false);
            mainFrame = null;
        }
    }

    /** show the timeline window and prompt for rebuilding database */
    synchronized void openTimeLine() {

        // listen for case changes (specifically images being added, and case changes).
        if (Case.isCaseOpen() && !listeningToAutopsy) {
            IngestManager.getInstance().addIngestModuleEventListener(ingestModuleListener);
            IngestManager.getInstance().addIngestJobEventListener(ingestJobListener);
            Case.addPropertyChangeListener(caseListener);
            listeningToAutopsy = true;
        }

        try {
            long timeLineLastObjectId = eventsRepository.getLastObjID();

            boolean rebuildingRepo = false;
            if (timeLineLastObjectId == -1) {
                rebuildingRepo = rebuildRepo();
            }
            if (rebuildingRepo == false
                    && eventsRepository.getWasIngestRunning()) {
                if (showLastPopulatedWhileIngestingConfirmation() == JOptionPane.YES_OPTION) {
                    rebuildingRepo = rebuildRepo();
                }
            }
            final SleuthkitCase sleuthkitCase = Case.getCurrentCase().getSleuthkitCase();
            if ((rebuildingRepo == false)
                    && (sleuthkitCase.getLastObjectId() != timeLineLastObjectId
                    || getCaseLastArtifactID(sleuthkitCase) != eventsRepository.getLastArtfactID())) {
                rebuildingRepo = outOfDatePromptAndRebuild();
            }

            if (rebuildingRepo == false) {
                showWindow();
                showFullRange();
            }

        } catch (TskCoreException ex) {
            LOGGER.log(Level.SEVERE, "Error when generating timeline, ", ex);
        } catch (HeadlessException | MissingResourceException ex) {
            LOGGER.log(Level.SEVERE, "Unexpected error when generating timeline, ", ex);
        }
    }

    @SuppressWarnings("deprecation")
    private long getCaseLastArtifactID(final SleuthkitCase sleuthkitCase) {
        long caseLastArtfId = -1;
        try (ResultSet runQuery = sleuthkitCase.runQuery("select Max(artifact_id) as max_id from blackboard_artifacts")) {
            while (runQuery.next()) {
                caseLastArtfId = runQuery.getLong("max_id");
            }
            sleuthkitCase.closeRunQuery(runQuery);
        } catch (SQLException ex) {
            Exceptions.printStackTrace(ex);
        }
        return caseLastArtfId;
    }

    /**
     * request a time range the same length as the given period and centered
     * around the middle of the currently selected range
     *
     * @param period
     */
    synchronized public void pushPeriod(ReadablePeriod period) {
        synchronized (filteredEvents) {
            final DateTime middleOf = IntervalUtils.middleOf(filteredEvents.timeRange().get());
            pushTimeRange(IntervalUtils.getIntervalAround(middleOf, period));
        }
    }

    synchronized public void pushZoomOutTime() {
        final Interval timeRange = filteredEvents.timeRange().get();
        long toDurationMillis = timeRange.toDurationMillis() / 4;
        DateTime start = timeRange.getStart().minus(toDurationMillis);
        DateTime end = timeRange.getEnd().plus(toDurationMillis);
        pushTimeRange(new Interval(start, end));
    }

    synchronized public void pushZoomInTime() {
        final Interval timeRange = filteredEvents.timeRange().get();
        long toDurationMillis = timeRange.toDurationMillis() / 4;
        DateTime start = timeRange.getStart().plus(toDurationMillis);
        DateTime end = timeRange.getEnd().minus(toDurationMillis);
        pushTimeRange(new Interval(start, end));
    }

    synchronized public void setViewMode(VisualizationMode visualizationMode) {
        if (viewMode.get() != visualizationMode) {
            viewMode.set(visualizationMode);
        }
    }

    public void selectEventIDs(Collection<Long> events) {
        final LoggedTask<Interval> selectEventIDsTask = new LoggedTask<Interval>("Select Event IDs", true) {
            @Override
            protected Interval call() throws Exception {
                return filteredEvents.getSpanningInterval(events);
            }

            @Override
            protected void succeeded() {
                super.succeeded();
                try {
                    synchronized (TimeLineController.this) {
                        selectedTimeRange.set(get());
                        selectedEventIDs.setAll(events);
                    }
                } catch (InterruptedException ex) {
                    Logger.getLogger(FilteredEventsModel.class
                            .getName()).log(Level.SEVERE, getTitle() + " interrupted unexpectedly", ex);
                } catch (ExecutionException ex) {
                    Logger.getLogger(FilteredEventsModel.class
                            .getName()).log(Level.SEVERE, getTitle() + " unexpectedly threw " + ex.getCause(), ex);
                }
            }
        };

        monitorTask(selectEventIDsTask);
    }

    /**
     * private method to build gui if necessary and make it visible.
     */
    synchronized private void showWindow() {
        if (mainFrame == null) {
            LOGGER.log(Level.WARNING, "Tried to show timeline with invalid window. Rebuilding GUI.");
            mainFrame = (TimeLineTopComponent) WindowManager.getDefault().findTopComponent("TimeLineTopComponent");
            if (mainFrame == null) {
                mainFrame = new TimeLineTopComponent();
            }
            mainFrame.setController(this);
        }
        SwingUtilities.invokeLater(() -> {
            mainFrame.open();
            mainFrame.setVisible(true);
            mainFrame.toFront();
        });
    }

    synchronized public void pushEventTypeZoom(EventTypeZoomLevel typeZoomeLevel) {
        ZoomParams currentZoom = filteredEvents.getRequestedZoomParamters().get();
        if (currentZoom == null) {
            advance(InitialZoomState.withTypeZoomLevel(typeZoomeLevel));
        } else if (currentZoom.hasTypeZoomLevel(typeZoomeLevel) == false) {
            advance(currentZoom.withTypeZoomLevel(typeZoomeLevel));
        }
    }

    synchronized public void pushTimeRange(Interval timeRange) {
//        timeRange = this.filteredEvents.getSpanningInterval().overlap(timeRange);
        ZoomParams currentZoom = filteredEvents.getRequestedZoomParamters().get();
        if (currentZoom == null) {
            advance(InitialZoomState.withTimeRange(timeRange));
        } else if (currentZoom.hasTimeRange(timeRange) == false) {
            advance(currentZoom.withTimeRange(timeRange));
        }
    }

    synchronized public boolean pushDescrLOD(DescriptionLOD newLOD) {
        Map<EventType, Long> eventCounts = filteredEvents.getEventCounts(filteredEvents.getRequestedZoomParamters().get().getTimeRange());
        final Long count = eventCounts.values().stream().reduce(0l, Long::sum);

        boolean shouldContinue = true;
        if (newLOD == DescriptionLOD.FULL && count > 10_000) {

            int showConfirmDialog = JOptionPane.showConfirmDialog(mainFrame,
                    "You are about to show details for " + NumberFormat.getInstance().format(count) + " events. This might be very slow or even crash Autopsy.\n\nDo you want to continue?",
                    "",
                    JOptionPane.YES_NO_OPTION);

            shouldContinue = (showConfirmDialog == JOptionPane.YES_OPTION);
        }

        if (shouldContinue) {
            ZoomParams currentZoom = filteredEvents.getRequestedZoomParamters().get();
            if (currentZoom == null) {
                advance(InitialZoomState.withDescrLOD(newLOD));
            } else if (currentZoom.hasDescrLOD(newLOD) == false) {
                advance(currentZoom.withDescrLOD(newLOD));
            }
        }
        return shouldContinue;
    }

    synchronized public void pushTimeAndType(Interval timeRange, EventTypeZoomLevel typeZoom) {
//        timeRange = this.filteredEvents.getSpanningInterval().overlap(timeRange);
        ZoomParams currentZoom = filteredEvents.getRequestedZoomParamters().get();
        if (currentZoom == null) {
            advance(InitialZoomState.withTimeAndType(timeRange, typeZoom));
        } else if (currentZoom.hasTimeRange(timeRange) == false && currentZoom.hasTypeZoomLevel(typeZoom) == false) {
            advance(currentZoom.withTimeAndType(timeRange, typeZoom));
        } else if (currentZoom.hasTimeRange(timeRange) == false) {
            advance(currentZoom.withTimeRange(timeRange));
        } else if (currentZoom.hasTypeZoomLevel(typeZoom) == false) {
            advance(currentZoom.withTypeZoomLevel(typeZoom));
        }
    }

    synchronized public void pushFilters(Filter filter) {
        ZoomParams currentZoom = filteredEvents.getRequestedZoomParamters().get();
        if (currentZoom == null) {
            advance(InitialZoomState.withFilter(filter.copyOf()));
        } else if (currentZoom.hasFilter(filter) == false) {
            advance(currentZoom.withFilter(filter.copyOf()));
        }
    }

    synchronized public ZoomParams advance() {
        return historyManager.advance();

    }

    synchronized public ZoomParams retreat() {
        return historyManager.retreat();
    }

    synchronized private void advance(ZoomParams newState) {
        historyManager.advance(newState);
    }

    public void selectTimeAndType(Interval interval, EventType type) {
        final Interval timeRange = filteredEvents.getSpanningInterval().overlap(interval);

        final LoggedTask<Collection<Long>> selectTimeAndTypeTask = new LoggedTask<Collection<Long>>("Select Time and Type", true) {
            @Override
            protected Collection< Long> call() throws Exception {
                synchronized (TimeLineController.this) {
                    return filteredEvents.getEventIDs(timeRange, new TypeFilter(type));
                }
            }

            @Override
            protected void succeeded() {
                super.succeeded();
                try {
                    synchronized (TimeLineController.this) {
                        selectedTimeRange.set(timeRange);
                        selectedEventIDs.setAll(get());
                    }
                } catch (InterruptedException ex) {
                    Logger.getLogger(FilteredEventsModel.class
                            .getName()).log(Level.SEVERE, getTitle() + " interrupted unexpectedly", ex);
                } catch (ExecutionException ex) {
                    Logger.getLogger(FilteredEventsModel.class
                            .getName()).log(Level.SEVERE, getTitle() + " unexpectedly threw " + ex.getCause(), ex);
                }
            }
        };

        monitorTask(selectTimeAndTypeTask);
    }

    synchronized public void monitorTask(final Task<?> task) {
        if (task != null) {
            Platform.runLater(() -> {

                //is this actually threadsafe, could we get a finished task stuck in the list?
                task.stateProperty().addListener((Observable observable) -> {
                    switch (task.getState()) {
                        case READY:
                        case RUNNING:
                        case SCHEDULED:
                            break;
                        case SUCCEEDED:
                        case CANCELLED:
                        case FAILED:
                            tasks.remove(task);
                            if (tasks.isEmpty() == false) {
                                progress.bind(tasks.get(0).progressProperty());
                                message.bind(tasks.get(0).messageProperty());
                                taskTitle.bind(tasks.get(0).titleProperty());
                            }
                            break;
                    }
                });
                tasks.add(task);
                progress.bind(task.progressProperty());
                message.bind(task.messageProperty());
                taskTitle.bind(task.titleProperty());
                switch (task.getState()) {
                    case READY:
                        executor.submit(task);
                        break;
                    case SCHEDULED:
                    case RUNNING:
                    case SUCCEEDED:
                    case CANCELLED:
                    case FAILED:
                        break;
                }
            });
        }
    }

    static synchronized public void setTimeZone(TimeZone timeZone) {
        TimeLineController.timeZone.set(timeZone);
    }

    Interval getSpanningInterval(Collection<Long> eventIDs) {
        return filteredEvents.getSpanningInterval(eventIDs);

    }

    /**
     * prompt the user to rebuild and then rebuild if the user chooses to
     */
    synchronized public boolean outOfDatePromptAndRebuild() {
        return showOutOfDateConfirmation() == JOptionPane.YES_OPTION
                ? rebuildRepo()
                : false;
    }

    synchronized int showLastPopulatedWhileIngestingConfirmation() {
        return JOptionPane.showConfirmDialog(mainFrame,
                DO_REPOPULATE_MESSAGE,
                "re populate events?",
                JOptionPane.YES_NO_OPTION,
                JOptionPane.QUESTION_MESSAGE);

    }

    synchronized int showOutOfDateConfirmation() throws MissingResourceException, HeadlessException {
        return JOptionPane.showConfirmDialog(mainFrame,
                NbBundle.getMessage(TimeLineController.class,
                        "Timeline.propChg.confDlg.timelineOOD.msg"),
                NbBundle.getMessage(TimeLineController.class,
                        "Timeline.propChg.confDlg.timelineOOD.details"),
                JOptionPane.YES_NO_OPTION);
    }

    synchronized int showIngestConfirmation() throws MissingResourceException, HeadlessException {
        return JOptionPane.showConfirmDialog(mainFrame,
                NbBundle.getMessage(TimeLineController.class,
                        "Timeline.initTimeline.confDlg.genBeforeIngest.msg"),
                NbBundle.getMessage(TimeLineController.class,
                        "Timeline.initTimeline.confDlg.genBeforeIngest.details"),
                JOptionPane.YES_NO_OPTION);
    }

    private class AutopsyIngestModuleListener implements PropertyChangeListener {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
                case CONTENT_CHANGED:
//                    ((ModuleContentEvent)evt.getOldValue())????
                    //ModuleContentEvent doesn't seem to provide any usefull information...
                    break;
                case DATA_ADDED:
//                    Collection<BlackboardArtifact> artifacts = ((ModuleDataEvent) evt.getOldValue()).getArtifacts();
                    //new artifacts, insert them into db
                    break;
                case FILE_DONE:
//                    Long fileID = (Long) evt.getOldValue();
                    //update file (known status) for file with id
                    Platform.runLater(() -> {
                        newEventsFlag.set(true);
                    });
                    break;
            }
        }
    }

    @Immutable
    private class AutopsyIngestJobListener implements PropertyChangeListener {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            switch (IngestManager.IngestJobEvent.valueOf(evt.getPropertyName())) {
                case CANCELLED:
                case COMPLETED:
                    //if we are doing incremental updates, drop this
                    outOfDatePromptAndRebuild();
                    break;
            }
        }
    }

    @Immutable
    private class AutopsyCaseListener implements PropertyChangeListener {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            switch (Case.Events.valueOf(evt.getPropertyName())) {
                case DATA_SOURCE_ADDED:
//                    Content content = (Content) evt.getNewValue();
                    //if we are doing incremental updates, drop this
                    outOfDatePromptAndRebuild();
                    break;
                case CURRENT_CASE:
                    OpenTimelineAction.invalidateController();
                    closeTimeLine();
                    break;
            }
        }
    }
}
TOP

Related Classes of org.sleuthkit.autopsy.timeline.TimeLineController$AutopsyIngestJobListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.