From fc63d677402da5598a4548fa56576468fa9177ae Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 29 Jan 2018 12:15:39 -0500 Subject: [PATCH 1/3] Moved interesting file artifact creation logic. --- .../modules/filetypeid/FileTypeDetector.java | 53 +++--------- .../filetypeid/FileTypeIdIngestModule.java | 83 ++++++++++++++++--- 2 files changed, 85 insertions(+), 51 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java index c742110f6b..dafae9a42b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,22 +19,16 @@ package org.sleuthkit.autopsy.modules.filetypeid; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; -import java.util.logging.Level; import java.util.stream.Collectors; import org.apache.tika.Tika; import org.apache.tika.io.TikaInputStream; import org.apache.tika.mime.MimeTypes; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -48,8 +42,8 @@ import org.sleuthkit.datamodel.TskData; */ public class FileTypeDetector { - private static final Logger logger = Logger.getLogger(FileTypeDetector.class.getName()); - private static final Tika tika = new Tika(); + private static final Logger LOGGER = Logger.getLogger(FileTypeDetector.class.getName()); + private static final Tika TIKA = new Tika(); private static final int SLACK_FILE_THRESHOLD = 4096; private final List userDefinedFileTypes; private final List autopsyDefinedFileTypes; @@ -227,7 +221,7 @@ public class FileTypeDetector { ReadContentInputStream stream = new ReadContentInputStream(file); try (TikaInputStream tikaInputStream = TikaInputStream.get(stream)) { - String tikaType = tika.detect(tikaInputStream, file.getName()); + String tikaType = TIKA.detect(tikaInputStream, file.getName()); /* * Remove the Tika suffix from the MIME type name. @@ -270,52 +264,29 @@ public class FileTypeDetector { } /** - * Determines whether or not the a file matches a user-defined custom file - * type. If the file matches and corresponds to an interesting files type - * rule, this method has the side effect of creating an interesting files - * hit artifact and indexing that artifact for keyword search. + * Determines whether or not a file matches a user-defined custom file type. * * @param file The file to test. * - * @return The file type name string or null, if no match is detected. - * - * @throws TskCoreException + * @return The MIME type as a string if a match is found; otherwise null. */ private String detectUserDefinedType(AbstractFile file) { + String retValue = null; + for (FileType fileType : userDefinedFileTypes) { if (fileType.matches(file)) { - if (fileType.createInterestingFileHit()) { - try { - BlackboardArtifact artifact; - artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); - Collection attributes = new ArrayList<>(); - BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, FileTypeIdModuleFactory.getModuleName(), fileType.getInterestingFilesSetName()); - attributes.add(setNameAttribute); - BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType()); - attributes.add(ruleNameAttribute); - artifact.addAttributes(attributes); - try { - Case.getCurrentCase().getServices().getBlackboard().indexArtifact(artifact); - } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, String.format("Unable to index TSK_INTERESTING_FILE_HIT blackboard artifact %d (file obj_id=%d)", artifact.getArtifactID(), file.getId()), ex); //NON-NLS - } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Unable to create TSK_INTERESTING_FILE_HIT artifact for file (obj_id=%d)", file.getId()), ex); //NON-NLS - } - } - return fileType.getMimeType(); + retValue = fileType.getMimeType(); } } - return null; + return retValue; } /** - * Determines whether or not the a file matches a custom file type defined - * by Autopsy. + * Determines whether or not a file matches a custom file type defined by Autopsy. * * @param file The file to test. * - * @return The file type name string or null, if no match is detected. + * @return The MIME type as a string if a match is found; otherwise null. */ private String detectAutopsyDefinedType(AbstractFile file) { for (FileType fileType : autopsyDefinedFileTypes) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index 64650ed0c4..4e1843ccf3 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * - * Copyright 2013-2015 Basis Technology Corp. + * + * Copyright 2013-2018 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. @@ -18,9 +18,14 @@ */ package org.sleuthkit.autopsy.modules.filetypeid; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.IngestJobContext; @@ -29,17 +34,20 @@ import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.ingest.IngestModule.ProcessResult; import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import org.sleuthkit.datamodel.TskCoreException; /** * Detects the type of a file based on signature (magic) values. Posts results * to the blackboard. */ @NbBundle.Messages({ - "CannotRunFileTypeDetection=Unable to run file type detection." + "CannotRunFileTypeDetection=Unable to run file type detection." }) public class FileTypeIdIngestModule implements FileIngestModule { - private static final Logger logger = Logger.getLogger(FileTypeIdIngestModule.class.getName()); + private static final Logger LOGGER = Logger.getLogger(FileTypeIdIngestModule.class.getName()); private long jobId; private static final HashMap totalsForIngestJobs = new HashMap<>(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); @@ -59,7 +67,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { try { return new FileTypeDetector().isDetectable(mimeType); } catch (FileTypeDetector.FileTypeDetectorInitException ex) { - logger.log(Level.SEVERE, "Failed to create file type detector", ex); //NON-NLS + LOGGER.log(Level.SEVERE, "Failed to create file type detector", ex); //NON-NLS return false; } } @@ -91,15 +99,70 @@ public class FileTypeIdIngestModule implements FileIngestModule { */ try { long startTime = System.currentTimeMillis(); - file.setMIMEType(fileTypeDetector.detectMIMEType(file)); + String mimeType = fileTypeDetector.detectMIMEType(file); + file.setMIMEType(mimeType); + FileType fileType = detectUserDefinedFileType(file); + if (fileType != null && fileType.createInterestingFileHit()) { + createInterestingFileHit(file, fileType); + } addToTotals(jobId, (System.currentTimeMillis() - startTime)); return ProcessResult.OK; } catch (Exception e) { - logger.log(Level.WARNING, String.format("Error while attempting to determine file type of file %d", file.getId()), e); //NON-NLS + LOGGER.log(Level.WARNING, String.format("Error while attempting to determine file type of file %d", file.getId()), e); //NON-NLS return ProcessResult.ERROR; } } + /** + * Determines whether or not a file matches a user-defined custom file type. + * + * @param file The file to test. + * + * @return The file type if a match is found; otherwise null. + * + * @throws CustomFileTypesException If there is an issue getting an instance + * of CustomFileTypesManager. + */ + private FileType detectUserDefinedFileType(AbstractFile file) throws CustomFileTypesManager.CustomFileTypesException { + FileType retValue = null; + + CustomFileTypesManager customFileTypesManager = CustomFileTypesManager.getInstance(); + List fileTypesList = customFileTypesManager.getUserDefinedFileTypes(); + for (FileType fileType : fileTypesList) { + if (fileType.matches(file)) { + retValue = fileType; + } + } + + return retValue; + } + + /** + * Create an Interesting File hit using the specified file type rule. + * + * @param file The file from which to generate an artifact. + * @param fileType The file type rule for categorizing the hit. + */ + private void createInterestingFileHit(AbstractFile file, FileType fileType) { + try { + BlackboardArtifact artifact; + artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); + Collection attributes = new ArrayList<>(); + BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, FileTypeIdModuleFactory.getModuleName(), fileType.getInterestingFilesSetName()); + attributes.add(setNameAttribute); + BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType()); + attributes.add(ruleNameAttribute); + artifact.addAttributes(attributes); + try { + Case.getCurrentCase().getServices().getBlackboard().indexArtifact(artifact); + } catch (Blackboard.BlackboardException ex) { + LOGGER.log(Level.SEVERE, String.format("Unable to index TSK_INTERESTING_FILE_HIT blackboard artifact %d (file obj_id=%d)", artifact.getArtifactID(), file.getId()), ex); //NON-NLS + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, String.format("Unable to create TSK_INTERESTING_FILE_HIT artifact for file (obj_id=%d)", file.getId()), ex); //NON-NLS + } + } + @Override public void shutDown() { /** From 9c9d85a5029fa04cee893a130337dee66f386dc6 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 29 Jan 2018 12:21:45 -0500 Subject: [PATCH 2/3] Minor tweaks. --- .../modules/filetypeid/FileTypeDetector.java | 1 + .../filetypeid/FileTypeIdIngestModule.java | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java index dafae9a42b..21f16941ab 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java @@ -276,6 +276,7 @@ public class FileTypeDetector { for (FileType fileType : userDefinedFileTypes) { if (fileType.matches(file)) { retValue = fileType.getMimeType(); + break; } } return retValue; diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index 4e1843ccf3..13c68cd53f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -49,8 +49,8 @@ public class FileTypeIdIngestModule implements FileIngestModule { private static final Logger LOGGER = Logger.getLogger(FileTypeIdIngestModule.class.getName()); private long jobId; - private static final HashMap totalsForIngestJobs = new HashMap<>(); - private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); + private static final HashMap INGEST_JOB_TOTALS = new HashMap<>(); + private static final IngestModuleReferenceCounter REF_COUNTER = new IngestModuleReferenceCounter(); private FileTypeDetector fileTypeDetector; /** @@ -82,7 +82,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { @Override public void startUp(IngestJobContext context) throws IngestModuleException { jobId = context.getJobId(); - refCounter.incrementAndGet(jobId); + REF_COUNTER.incrementAndGet(jobId); try { fileTypeDetector = new FileTypeDetector(); } catch (FileTypeDetector.FileTypeDetectorInitException ex) { @@ -131,6 +131,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { for (FileType fileType : fileTypesList) { if (fileType.matches(file)) { retValue = fileType; + break; } } @@ -169,10 +170,10 @@ public class FileTypeIdIngestModule implements FileIngestModule { * If this is the instance of this module for this ingest job, post a * summary message to the ingest messages box. */ - if (refCounter.decrementAndGet(jobId) == 0) { + if (REF_COUNTER.decrementAndGet(jobId) == 0) { IngestJobTotals jobTotals; synchronized (this) { - jobTotals = totalsForIngestJobs.remove(jobId); + jobTotals = INGEST_JOB_TOTALS.remove(jobId); } if (jobTotals != null) { StringBuilder detailsSb = new StringBuilder(); @@ -201,15 +202,15 @@ public class FileTypeIdIngestModule implements FileIngestModule { * @param matchTimeInc Amount of time to add. */ private static synchronized void addToTotals(long jobId, long matchTimeInc) { - IngestJobTotals ingestJobTotals = totalsForIngestJobs.get(jobId); + IngestJobTotals ingestJobTotals = INGEST_JOB_TOTALS.get(jobId); if (ingestJobTotals == null) { ingestJobTotals = new IngestJobTotals(); - totalsForIngestJobs.put(jobId, ingestJobTotals); + INGEST_JOB_TOTALS.put(jobId, ingestJobTotals); } ingestJobTotals.matchTime += matchTimeInc; ingestJobTotals.numFiles++; - totalsForIngestJobs.put(jobId, ingestJobTotals); + INGEST_JOB_TOTALS.put(jobId, ingestJobTotals); } private static class IngestJobTotals { From dca73677b3208a76158c60a2b86229fe6e3670be Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 9 Feb 2018 23:35:34 -0500 Subject: [PATCH 3/3] Fixed merge. --- .../modules/filetypeid/FileTypeDetector.java | 12 ++++---- .../filetypeid/FileTypeIdIngestModule.java | 28 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java index f13dd8f223..795afd0838 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java @@ -42,8 +42,8 @@ import org.sleuthkit.datamodel.TskData; */ public class FileTypeDetector { - private static final Logger LOGGER = Logger.getLogger(FileTypeDetector.class.getName()); - private static final Tika TIKA = new Tika(); + private static final Logger logger = Logger.getLogger(FileTypeDetector.class.getName()); + private static final Tika tika = new Tika(); private static final int SLACK_FILE_THRESHOLD = 4096; private final List userDefinedFileTypes; private final List autopsyDefinedFileTypes; @@ -224,7 +224,7 @@ public class FileTypeDetector { ReadContentInputStream stream = new ReadContentInputStream(file); try (TikaInputStream tikaInputStream = TikaInputStream.get(stream)) { - String tikaType = TIKA.detect(tikaInputStream, file.getName()); + String tikaType = tika.detect(tikaInputStream, file.getName()); /* * Remove the Tika suffix from the MIME type name. @@ -367,7 +367,7 @@ public class FileTypeDetector { * * @throws TskCoreException if detection is required and there is a problem * writing the result to the case database. - * @deprecated Use detectMIMEType instead, and call AbstractFile.setMIMEType + * @deprecated Use getMIMEType instead, and call AbstractFile.setMIMEType * and AbstractFile.save to save the result to the file object and the * database. */ @@ -391,7 +391,7 @@ public class FileTypeDetector { * @throws TskCoreException if detection is required and there is a problem * writing the result to the case database. * - * @deprecated Use detectMIMEType instead, and call AbstractFile.setMIMEType + * @deprecated Use getMIMEType instead, and call AbstractFile.setMIMEType * and AbstractFile.save to save the result to the file object and the * database. */ @@ -413,7 +413,7 @@ public class FileTypeDetector { * were uncertain, octet-stream is returned. * * @throws TskCoreException - * @deprecated Use detectMIMEType instead. + * @deprecated Use getMIMEType instead. */ @Deprecated public String detect(AbstractFile file) throws TskCoreException { diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java index 13c68cd53f..be0bcdfbb3 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdIngestModule.java @@ -47,10 +47,10 @@ import org.sleuthkit.datamodel.TskCoreException; }) public class FileTypeIdIngestModule implements FileIngestModule { - private static final Logger LOGGER = Logger.getLogger(FileTypeIdIngestModule.class.getName()); + private static final Logger logger = Logger.getLogger(FileTypeIdIngestModule.class.getName()); private long jobId; - private static final HashMap INGEST_JOB_TOTALS = new HashMap<>(); - private static final IngestModuleReferenceCounter REF_COUNTER = new IngestModuleReferenceCounter(); + private static final HashMap totalsForIngestJobs = new HashMap<>(); + private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); private FileTypeDetector fileTypeDetector; /** @@ -67,7 +67,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { try { return new FileTypeDetector().isDetectable(mimeType); } catch (FileTypeDetector.FileTypeDetectorInitException ex) { - LOGGER.log(Level.SEVERE, "Failed to create file type detector", ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to create file type detector", ex); //NON-NLS return false; } } @@ -82,7 +82,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { @Override public void startUp(IngestJobContext context) throws IngestModuleException { jobId = context.getJobId(); - REF_COUNTER.incrementAndGet(jobId); + refCounter.incrementAndGet(jobId); try { fileTypeDetector = new FileTypeDetector(); } catch (FileTypeDetector.FileTypeDetectorInitException ex) { @@ -99,7 +99,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { */ try { long startTime = System.currentTimeMillis(); - String mimeType = fileTypeDetector.detectMIMEType(file); + String mimeType = fileTypeDetector.getMIMEType(file); file.setMIMEType(mimeType); FileType fileType = detectUserDefinedFileType(file); if (fileType != null && fileType.createInterestingFileHit()) { @@ -108,7 +108,7 @@ public class FileTypeIdIngestModule implements FileIngestModule { addToTotals(jobId, (System.currentTimeMillis() - startTime)); return ProcessResult.OK; } catch (Exception e) { - LOGGER.log(Level.WARNING, String.format("Error while attempting to determine file type of file %d", file.getId()), e); //NON-NLS + logger.log(Level.WARNING, String.format("Error while attempting to determine file type of file %d", file.getId()), e); //NON-NLS return ProcessResult.ERROR; } } @@ -157,10 +157,10 @@ public class FileTypeIdIngestModule implements FileIngestModule { try { Case.getCurrentCase().getServices().getBlackboard().indexArtifact(artifact); } catch (Blackboard.BlackboardException ex) { - LOGGER.log(Level.SEVERE, String.format("Unable to index TSK_INTERESTING_FILE_HIT blackboard artifact %d (file obj_id=%d)", artifact.getArtifactID(), file.getId()), ex); //NON-NLS + logger.log(Level.SEVERE, String.format("Unable to index TSK_INTERESTING_FILE_HIT blackboard artifact %d (file obj_id=%d)", artifact.getArtifactID(), file.getId()), ex); //NON-NLS } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, String.format("Unable to create TSK_INTERESTING_FILE_HIT artifact for file (obj_id=%d)", file.getId()), ex); //NON-NLS + logger.log(Level.SEVERE, String.format("Unable to create TSK_INTERESTING_FILE_HIT artifact for file (obj_id=%d)", file.getId()), ex); //NON-NLS } } @@ -170,10 +170,10 @@ public class FileTypeIdIngestModule implements FileIngestModule { * If this is the instance of this module for this ingest job, post a * summary message to the ingest messages box. */ - if (REF_COUNTER.decrementAndGet(jobId) == 0) { + if (refCounter.decrementAndGet(jobId) == 0) { IngestJobTotals jobTotals; synchronized (this) { - jobTotals = INGEST_JOB_TOTALS.remove(jobId); + jobTotals = totalsForIngestJobs.remove(jobId); } if (jobTotals != null) { StringBuilder detailsSb = new StringBuilder(); @@ -202,15 +202,15 @@ public class FileTypeIdIngestModule implements FileIngestModule { * @param matchTimeInc Amount of time to add. */ private static synchronized void addToTotals(long jobId, long matchTimeInc) { - IngestJobTotals ingestJobTotals = INGEST_JOB_TOTALS.get(jobId); + IngestJobTotals ingestJobTotals = totalsForIngestJobs.get(jobId); if (ingestJobTotals == null) { ingestJobTotals = new IngestJobTotals(); - INGEST_JOB_TOTALS.put(jobId, ingestJobTotals); + totalsForIngestJobs.put(jobId, ingestJobTotals); } ingestJobTotals.matchTime += matchTimeInc; ingestJobTotals.numFiles++; - INGEST_JOB_TOTALS.put(jobId, ingestJobTotals); + totalsForIngestJobs.put(jobId, ingestJobTotals); } private static class IngestJobTotals {