<commit_before>/*
 * Autopsy Forensic Browser
 *
 * Copyright 2013-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.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;

import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitJNI;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.TskException;

/*
 * A background task that adds the given image to 
 * database using the Sleuthkit JNI interface.
 * 
 * It updates the given ProgressMonitor as it works through adding the image,
 * and et the end, calls the specified Callback.
 */
 class AddImageTask implements Runnable {

        private final Logger logger = Logger.getLogger(AddImageTask.class.getName());
        
        private final Case currentCase;
        
        // true if the process was requested to cancel
        private final Object lock = new Object();   // synchronization object for cancelRequested
        private volatile boolean cancelRequested = false;
        
        //true if revert has been invoked.
        private boolean reverted = false;
        
        // true if there was a critical error in adding the data source
        private boolean hasCritError = false;
        
        private final List<String> errorList = new ArrayList<>();
        
        private final DataSourceProcessorProgressMonitor progressMonitor;
        private final DataSourceProcessorCallback callbackObj;
        
        private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
        
        private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess;
        private Thread dirFetcher;
   
        private final String imagePath;
        String timeZone;
        boolean noFatOrphans;
          
        /*
         * A thread that updates the progressMonitor with the name of the 
         * directory currently being processed  by the AddImageTask 
         */
        private class CurrentDirectoryFetcher implements Runnable {

            DataSourceProcessorProgressMonitor progressMonitor;
            SleuthkitJNI.CaseDbHandle.AddImageProcess process;

            CurrentDirectoryFetcher(DataSourceProcessorProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) {
                this.progressMonitor = aProgressMonitor;
                this.process = proc;
            }

            /**
             * @return the currently processing directory
             */
            @Override
            public void run() {
                try {
                    while (!Thread.currentThread().isInterrupted()) { 
                        String currDir = process.currentDirectory();
                        if (currDir != null) {
                            if (!currDir.isEmpty() ) {
                                progressMonitor.setProgressText(
                                        NbBundle.getMessage(this.getClass(), "AddImageTask.run.progress.adding",
                                                            currDir));
                            }
                        }
                        // this sleep here prevents the UI from locking up 
                        // due to too frequent updates to the progressMonitor above
                        Thread.sleep(500);
                    }
                } catch (InterruptedException ie) {
                    // nothing to do, thread was interrupted externally  
                    // signaling the end of AddImageProcess 
                }
            }
        }
    
        public AddImageTask(String imgPath, String tz, boolean noOrphans, DataSourceProcessorProgressMonitor aProgressMonitor, DataSourceProcessorCallback cbObj ) {
           
            currentCase = Case.getCurrentCase();
            
            this.imagePath = imgPath;
            this.timeZone = tz;
            this.noFatOrphans = noOrphans;
            
            this.callbackObj = cbObj;
            this.progressMonitor = aProgressMonitor;
        }

        /**
         * Starts the addImage process, but does not commit the results.
         *
         * @return
         *
         * @throws Exception
         */
        @Override
        public void run() {
             
            errorList.clear();
           
            //lock DB for writes in this thread
            SleuthkitCase.acquireExclusiveLock();
             
            addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
            dirFetcher = new Thread( new CurrentDirectoryFetcher(progressMonitor, addImageProcess));
          
            try {
                progressMonitor.setIndeterminate(true);
                progressMonitor.setProgress(0);
               
                dirFetcher.start();
                
                addImageProcess.run(new String[]{this.imagePath});
                
            } catch (TskCoreException ex) {
                logger.log(Level.SEVERE, "Core errors occurred while running add image. ", ex); //NON-NLS
                //critical core/system error and process needs to be interrupted
                hasCritError = true;
                errorList.add(ex.getMessage());
            } catch (TskDataException ex) {
                logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); //NON-NLS
                errorList.add(ex.getMessage());
            } 

            // handle addImage done
            postProcess();
            
            // unclock the DB 
            SleuthkitCase.releaseExclusiveLock();
        }

        /**<commit_msg>Update AddImageTask for non-static case db locking API<commit_after>/*
 * Autopsy Forensic Browser
 *
 * Copyright 2013-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.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;

import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitJNI;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.TskException;

/*
 * A background task that adds the given image to 
 * database using the Sleuthkit JNI interface.
 * 
 * It updates the given ProgressMonitor as it works through adding the image,
 * and et the end, calls the specified Callback.
 */
 class AddImageTask implements Runnable {

        private final Logger logger = Logger.getLogger(AddImageTask.class.getName());
        
        private final Case currentCase;
        
        // true if the process was requested to cancel
        private final Object lock = new Object();   // synchronization object for cancelRequested
        private volatile boolean cancelRequested = false;
        
        //true if revert has been invoked.
        private boolean reverted = false;
        
        // true if there was a critical error in adding the data source
        private boolean hasCritError = false;
        
        private final List<String> errorList = new ArrayList<>();
        
        private final DataSourceProcessorProgressMonitor progressMonitor;
        private final DataSourceProcessorCallback callbackObj;
        
        private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
        
        private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess;
        private Thread dirFetcher;
   
        private final String imagePath;
        String timeZone;
        boolean noFatOrphans;
          
        /*
         * A thread that updates the progressMonitor with the name of the 
         * directory currently being processed  by the AddImageTask 
         */
        private class CurrentDirectoryFetcher implements Runnable {

            DataSourceProcessorProgressMonitor progressMonitor;
            SleuthkitJNI.CaseDbHandle.AddImageProcess process;

            CurrentDirectoryFetcher(DataSourceProcessorProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) {
                this.progressMonitor = aProgressMonitor;
                this.process = proc;
            }

            /**
             * @return the currently processing directory
             */
            @Override
            public void run() {
                try {
                    while (!Thread.currentThread().isInterrupted()) { 
                        String currDir = process.currentDirectory();
                        if (currDir != null) {
                            if (!currDir.isEmpty() ) {
                                progressMonitor.setProgressText(
                                        NbBundle.getMessage(this.getClass(), "AddImageTask.run.progress.adding",
                                                            currDir));
                            }
                        }
                        // this sleep here prevents the UI from locking up 
                        // due to too frequent updates to the progressMonitor above
                        Thread.sleep(500);
                    }
                } catch (InterruptedException ie) {
                    // nothing to do, thread was interrupted externally  
                    // signaling the end of AddImageProcess 
                }
            }
        }
    
        public AddImageTask(String imgPath, String tz, boolean noOrphans, DataSourceProcessorProgressMonitor aProgressMonitor, DataSourceProcessorCallback cbObj ) {
           
            currentCase = Case.getCurrentCase();
            
            this.imagePath = imgPath;
            this.timeZone = tz;
            this.noFatOrphans = noOrphans;
            
            this.callbackObj = cbObj;
            this.progressMonitor = aProgressMonitor;
        }

        /**
         * Starts the addImage process, but does not commit the results.
         *
         * @return
         *
         * @throws Exception
         */
        @Override
        public void run() {             
            errorList.clear();           
            try {
                currentCase.getSleuthkitCase().acquireExclusiveLock();
                addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
                dirFetcher = new Thread( new CurrentDirectoryFetcher(progressMonitor, addImageProcess));
                try {
                    progressMonitor.setIndeterminate(true);
                    progressMonitor.setProgress(0);
                    dirFetcher.start();
                    addImageProcess.run(new String[]{this.imagePath});
                } catch (TskCoreException ex) {
                    logger.log(Level.SEVERE, "Core errors occurred while running add image. ", ex); //NON-NLS
                    hasCritError = true;
                    errorList.add(ex.getMessage());
                } catch (TskDataException ex) {
                    logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); //NON-NLS
                    errorList.add(ex.getMessage());
                } 
                postProcess();
            } finally {
                currentCase.getSleuthkitCase().releaseExclusiveLock();
            }
        }

        /**
{'fraction_non_alphanumeric': 0.06858936043036462, 'fraction_numerical': 0.002390914524805738, 'mean_word_length': 1.9097826086956522, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3519981', 'n_tokens_mistral': 3265, 'n_tokens_neox': 3121, 'n_words': 913}