Autopsy  4.17.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
IngestJob.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2014-2018 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.ingest;
20 
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Date;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.atomic.AtomicInteger;
30 import java.util.concurrent.atomic.AtomicLong;
31 import java.util.logging.Level;
32 import org.openide.util.NbBundle;
34 import org.sleuthkit.datamodel.AbstractFile;
35 import org.sleuthkit.datamodel.Content;
36 import org.sleuthkit.datamodel.DataSource;
37 
42 public final class IngestJob {
43 
44  /*
45  * An ingest job can be cancelled for various reasons.
46  */
47  public enum CancellationReason {
48 
49  NOT_CANCELLED(NbBundle.getMessage(IngestJob.class, "IngestJob.cancelReason.notCancelled.text")),
50  USER_CANCELLED(NbBundle.getMessage(IngestJob.class, "IngestJob.cancelReason.cancelledByUser.text")),
51  INGEST_MODULES_STARTUP_FAILED(NbBundle.getMessage(IngestJob.class, "IngestJob.cancelReason.ingestModStartFail.text")),
52  OUT_OF_DISK_SPACE(NbBundle.getMessage(IngestJob.class, "IngestJob.cancelReason.outOfDiskSpace.text")),
53  SERVICES_DOWN(NbBundle.getMessage(IngestJob.class, "IngestJob.cancelReason.servicesDown.text")),
54  CASE_CLOSED(NbBundle.getMessage(IngestJob.class, "IngestJob.cancelReason.caseClosed.text"));
55 
56  private final String displayName;
57 
58  private CancellationReason(String displayName) {
59  this.displayName = displayName;
60  }
61 
62  public String getDisplayName() {
63  return displayName;
64  }
65  }
66 
70  enum Mode {
71  BATCH,
72  STREAMING
73  }
74 
75  private static final Logger logger = Logger.getLogger(IngestJob.class.getName());
76  private final static AtomicLong nextId = new AtomicLong(0L);
77  private final long id;
78  private final List<Content> dataSources = new ArrayList<>();
79  private final List<AbstractFile> files = new ArrayList<>();
80  private final Mode ingestMode;
81  private final Map<Long, IngestJobPipeline> ingestJobPipelines;
82  private final AtomicInteger incompleteJobsCount;
83  private final IngestJobSettings settings;
85 
93  IngestJob(Collection<Content> dataSources, IngestJobSettings settings) {
94  this.id = IngestJob.nextId.getAndIncrement();
95  this.settings = settings;
96  this.ingestJobPipelines = new ConcurrentHashMap<>();
97  this.ingestMode = Mode.BATCH;
98  this.dataSources.addAll(dataSources);
99  incompleteJobsCount = new AtomicInteger(dataSources.size());
100  cancellationReason = CancellationReason.NOT_CANCELLED;
101  }
102 
112  IngestJob(Content dataSource, List<AbstractFile> files, IngestJobSettings settings) {
113  this(Arrays.asList(dataSource), settings);
114  this.files.addAll(files);
115  }
116 
123  IngestJob(DataSource dataSource, Mode ingestMode, IngestJobSettings settings) {
124  this.id = IngestJob.nextId.getAndIncrement();
125  this.ingestJobPipelines = new ConcurrentHashMap<>();
126  this.dataSources.add(dataSource);
127  this.settings = settings;
128  this.ingestMode = ingestMode;
129  incompleteJobsCount = new AtomicInteger(1);
130  cancellationReason = CancellationReason.NOT_CANCELLED;
131  }
132 
138  public long getId() {
139  return this.id;
140  }
141 
149  boolean hasIngestPipeline() {
150  return (!settings.getEnabledIngestModuleTemplates().isEmpty());
151  }
152 
158  void addStreamingIngestFiles(List<Long> fileObjIds) {
159  if (ingestJobPipelines.isEmpty()) {
160  logger.log(Level.SEVERE, "Attempted to add streaming ingest files with no IngestJobPipeline");
161  return;
162  }
163  // Streaming ingest jobs will only have one data source
164  IngestJobPipeline streamingIngestPipeline = ingestJobPipelines.values().iterator().next();
165  streamingIngestPipeline.addStreamingIngestFiles(fileObjIds);
166  }
167 
171  void processStreamingIngestDataSource() {
172  if (ingestJobPipelines.isEmpty()) {
173  logger.log(Level.SEVERE, "Attempted to start data source ingest with no IngestJobPipeline");
174  return;
175  }
176  // Streaming ingest jobs will only have one data source
177  IngestJobPipeline streamingIngestPipeline = ingestJobPipelines.values().iterator().next();
178  streamingIngestPipeline.processStreamingIngestDataSource();
179  }
180 
187  List<IngestModuleError> start() {
188 
189  /*
190  * Set up the pipeline(s)
191  */
192  if (files.isEmpty()) {
193  for (Content dataSource : dataSources) {
194  IngestJobPipeline ingestJobPipeline = new IngestJobPipeline(this, dataSource, settings);
195  this.ingestJobPipelines.put(ingestJobPipeline.getId(), ingestJobPipeline);
196  }
197  } else {
198  IngestJobPipeline ingestJobPipeline = new IngestJobPipeline(this, dataSources.get(0), files, settings);
199  this.ingestJobPipelines.put(ingestJobPipeline.getId(), ingestJobPipeline);
200  }
201  incompleteJobsCount.set(ingestJobPipelines.size());
202 
203  /*
204  * Try to start each data source ingest job. Note that there is an
205  * assumption here that if there is going to be a module
206  * startup failure, it will be for the first ingest job pipeline.
207  *
208  * TODO (RC): Consider separating module start up from pipeline startup
209  * so that no processing is done if this assumption is false.
210  */
211  List<IngestModuleError> errors = new ArrayList<>();
212  for (IngestJobPipeline ingestJobPipeline : this.ingestJobPipelines.values()) {
213  errors.addAll(ingestJobPipeline.start());
214  if (errors.isEmpty() == false) {
215  break;
216  }
217  }
218 
219  /*
220  * Handle start up success or failure.
221  */
222  if (errors.isEmpty()) {
223  for (IngestJobPipeline dataSourceJob : this.ingestJobPipelines.values()) {
224  IngestManager.getInstance().fireDataSourceAnalysisStarted(id, dataSourceJob.getId(), dataSourceJob.getDataSource());
225  }
226  } else {
227  cancel(CancellationReason.INGEST_MODULES_STARTUP_FAILED);
228  }
229 
230  return errors;
231  }
232 
238  Mode getIngestMode() {
239  return ingestMode;
240  }
241 
248  return new ProgressSnapshot(true);
249  }
250 
258  public ProgressSnapshot getSnapshot(boolean getIngestTasksSnapshot) {
259  return new ProgressSnapshot(getIngestTasksSnapshot);
260  }
261 
268  List<Snapshot> getDataSourceIngestJobSnapshots() {
269  List<Snapshot> snapshots = new ArrayList<>();
270  this.ingestJobPipelines.values().stream().forEach((dataSourceJob) -> {
271  snapshots.add(dataSourceJob.getSnapshot(true));
272  });
273  return snapshots;
274  }
275 
284  @Deprecated
285  public void cancel() {
287  }
288 
297  public void cancel(CancellationReason reason) {
298  this.cancellationReason = reason;
299  this.ingestJobPipelines.values().stream().forEach((job) -> {
300  job.cancel(reason);
301  });
302  }
303 
310  return this.cancellationReason;
311  }
312 
319  public boolean isCancelled() {
320  return (CancellationReason.NOT_CANCELLED != this.cancellationReason);
321  }
322 
329  void ingestJobPipelineFinished(IngestJobPipeline ingestJobPipeline) {
330  IngestManager ingestManager = IngestManager.getInstance();
331  if (!ingestJobPipeline.isCancelled()) {
332  ingestManager.fireDataSourceAnalysisCompleted(id, ingestJobPipeline.getId(), ingestJobPipeline.getDataSource());
333  } else {
334  IngestManager.getInstance().fireDataSourceAnalysisCancelled(id, ingestJobPipeline.getId(), ingestJobPipeline.getDataSource());
335  }
336  if (incompleteJobsCount.decrementAndGet() == 0) {
337  ingestManager.finishIngestJob(this);
338  }
339  }
340 
344  public final class ProgressSnapshot {
345 
346  private final List<DataSourceProcessingSnapshot> dataSourceProcessingSnapshots;
348  private boolean fileIngestRunning;
349  private Date fileIngestStartTime;
350  private final boolean jobCancelled;
352 
357  public final class DataSourceProcessingSnapshot {
358 
359  private final Snapshot snapshot;
360 
362  this.snapshot = snapshot;
363  }
364 
371  public String getDataSource() {
372  return snapshot.getDataSource();
373  }
374 
381  public boolean isCancelled() {
382  return snapshot.isCancelled();
383  }
384 
391  return snapshot.getCancellationReason();
392  }
393 
401  public List<String> getCancelledDataSourceIngestModules() {
402  return snapshot.getCancelledDataSourceIngestModules();
403  }
404 
405  }
406 
410  private ProgressSnapshot(boolean getIngestTasksSnapshot) {
411  dataSourceModule = null;
412  fileIngestRunning = false;
413  fileIngestStartTime = null;
414  dataSourceProcessingSnapshots = new ArrayList<>();
415  for (IngestJobPipeline pipeline : ingestJobPipelines.values()) {
416  Snapshot snapshot = pipeline.getSnapshot(getIngestTasksSnapshot);
417  dataSourceProcessingSnapshots.add(new DataSourceProcessingSnapshot(snapshot));
418  if (null == dataSourceModule) {
419  DataSourceIngestPipeline.PipelineModule module = snapshot.getDataSourceLevelIngestModule();
420  if (null != module) {
421  dataSourceModule = new DataSourceIngestModuleHandle(ingestJobPipelines.get(snapshot.getJobId()), module);
422  }
423  }
424  if (snapshot.getFileIngestIsRunning()) {
425  fileIngestRunning = true;
426  }
427  Date childFileIngestStartTime = snapshot.getFileIngestStartTime();
428  if (null != childFileIngestStartTime && (null == fileIngestStartTime || childFileIngestStartTime.before(fileIngestStartTime))) {
429  fileIngestStartTime = childFileIngestStartTime;
430  }
431  }
432  this.jobCancelled = isCancelled();
434  }
435 
443  return this.dataSourceModule;
444  }
445 
452  public boolean fileIngestIsRunning() {
453  return this.fileIngestRunning;
454  }
455 
461  public Date fileIngestStartTime() {
462  return new Date(this.fileIngestStartTime.getTime());
463  }
464 
471  public boolean isCancelled() {
472  return this.jobCancelled;
473  }
474 
481  return this.jobCancellationReason;
482  }
483 
489  public List<DataSourceProcessingSnapshot> getDataSourceSnapshots() {
490  return Collections.unmodifiableList(this.dataSourceProcessingSnapshots);
491  }
492 
493  }
494 
500  public static class DataSourceIngestModuleHandle {
501 
502  private final IngestJobPipeline ingestJobPipeline;
503  private final DataSourceIngestPipeline.PipelineModule module;
504  private final boolean cancelled;
505 
514  private DataSourceIngestModuleHandle(IngestJobPipeline ingestJobPipeline, DataSourceIngestPipeline.PipelineModule module) {
515  this.ingestJobPipeline = ingestJobPipeline;
516  this.module = module;
517  this.cancelled = ingestJobPipeline.currentDataSourceIngestModuleIsCancelled();
518  }
519 
526  public String displayName() {
527  return this.module.getDisplayName();
528  }
529 
536  public Date startTime() {
537  return this.module.getProcessingStartTime();
538  }
539 
546  public boolean isCancelled() {
547  return this.cancelled;
548  }
549 
555  public void cancel() {
567  if (this.ingestJobPipeline.getCurrentDataSourceIngestModule() == this.module) {
568  this.ingestJobPipeline.cancelCurrentDataSourceIngestModule();
569  }
570  }
571 
572  }
573 
574 }
DataSourceIngestModuleHandle(IngestJobPipeline ingestJobPipeline, DataSourceIngestPipeline.PipelineModule module)
Definition: IngestJob.java:514
static synchronized IngestManager getInstance()
final DataSourceIngestPipeline.PipelineModule module
Definition: IngestJob.java:503
final AtomicInteger incompleteJobsCount
Definition: IngestJob.java:82
void cancel(CancellationReason reason)
Definition: IngestJob.java:297
DataSourceIngestModuleHandle runningDataSourceIngestModule()
Definition: IngestJob.java:442
List< DataSourceProcessingSnapshot > getDataSourceSnapshots()
Definition: IngestJob.java:489
final IngestJob.CancellationReason jobCancellationReason
Definition: IngestJob.java:351
CancellationReason getCancellationReason()
Definition: IngestJob.java:309
final Map< Long, IngestJobPipeline > ingestJobPipelines
Definition: IngestJob.java:81
final List< Content > dataSources
Definition: IngestJob.java:78
final List< AbstractFile > files
Definition: IngestJob.java:79
static final AtomicLong nextId
Definition: IngestJob.java:76
ProgressSnapshot(boolean getIngestTasksSnapshot)
Definition: IngestJob.java:410
volatile CancellationReason cancellationReason
Definition: IngestJob.java:84
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
ProgressSnapshot getSnapshot(boolean getIngestTasksSnapshot)
Definition: IngestJob.java:258
final IngestJobSettings settings
Definition: IngestJob.java:83
final List< DataSourceProcessingSnapshot > dataSourceProcessingSnapshots
Definition: IngestJob.java:346

Copyright © 2012-2021 Basis Technology. Generated on: Tue Jan 19 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.