crashanalysis/crashanalyser/com.nokia.s60tools.crashanalyser/src/com/nokia/s60tools/crashanalyser/model/CrashFileManager.java
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Tue, 20 Apr 2010 14:41:43 +0300
changeset 4 615035072f7e
parent 0 5ad7ad99af01
permissions -rw-r--r--
Crash Analyser Carbide extension v1.3

/*
* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/

package com.nokia.s60tools.crashanalyser.model;

import java.io.*;
import java.util.*;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.swt.widgets.Display;
import com.nokia.s60tools.crashanalyser.data.*;
import com.nokia.s60tools.crashanalyser.interfaces.*;
import com.nokia.s60tools.crashanalyser.containers.Thread;

/**
 * This class is responsible for providing crash files to MainView's content provider.
 * This class read workspace specific crash files from disk and prepares them for main view. 
 *
 */
public class CrashFileManager extends Job {
	List<CrashFileBundle> crashFiles = null;
	INewCrashFilesObserver filesObserver = null;
	ErrorLibrary errorLibrary = null;
	ILock accessLock = null;
	boolean restart = false;
	boolean jobRunning = false;
	
	/**
	 * Constructor
	 * @param observer observer for new files
	 */
	public CrashFileManager(INewCrashFilesObserver observer) {
		super("CrashAnalyser - Reading Files");
		filesObserver = observer;
		accessLock = Job.getJobManager().newLock();
		setPriority(Job.LONG);
		setUser(false);
	}
	
	protected IStatus run(IProgressMonitor monitor) {
		accessLock.acquire();
		try {
			jobRunning = true;
			// create array for crash files if it doesn't exist yet
			if (crashFiles == null) {
				crashFiles = new ArrayList<CrashFileBundle>();
			// array exists, remove non-existing files
			} else {
				
				// remove no longer existing files
				for (int i = 0; i < crashFiles.size(); i++) {
					CrashFileBundle file = crashFiles.get(i);
					if (!file.exists()) {
						crashFiles.remove(i);
						i--;
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			accessLock.release();
		}
		
		// get crash files folder e.g. C:\My_Workspace\.metadata\.plugins\com.nokia.s60tools.crashanalyser\CrashFiles
		File cFilesFolder = new File(DecoderEngine.getCrashFilesFolder());
		if (cFilesFolder.exists() && cFilesFolder.isDirectory()) {
			// get crash file folders (CrashFiles are under numeric folders, e.g. ..\CrashFiles\1, ...\CrashFiles\2, etc.
			File[] folders = cFilesFolder.listFiles();
			if (folders != null) {
				// go through all folders
				for (int j = 0; j < folders.length; j++) {
					File cFolder = folders[j];
					if (cFolder.isDirectory()) {
						accessLock.acquire();
						try {
							// create dummy bundle for comparing purposes
							CrashFileBundle dummy = CrashFileBundle.createDummyBundle(cFolder.getAbsolutePath());
							// if array already contains this bundle, remove it and add it again, so that data is updated 
							if (crashFiles.contains(dummy)) {
								accessLock.release();
								CrashFileBundle bundle = new CrashFileBundle(cFolder.getAbsolutePath(), errorLibrary);
								if (bundle.hasFiles()) {
									accessLock.acquire();
									crashFiles.remove(dummy);
									crashFiles.add(bundle);
								}
							// array doesn't contain this bundle, add it
							} else {
								accessLock.release();
								CrashFileBundle bundle = new CrashFileBundle(cFolder.getAbsolutePath(), errorLibrary);
								if (bundle.hasFiles()) {
									accessLock.acquire();
									crashFiles.add(bundle);
								}
							}
						} catch (Exception e) {
							e.printStackTrace();
						} finally {
							accessLock.release();
						}
					}
				}
			}
		}
		
		// notify observer to update it's view
		filesObserver.crashFilesUpdated();
		
		accessLock.acquire();
		// we have received new files while reading files, 
		// read files immediately again
		if (restart) {
			restart = false;
			accessLock.release();
			reSchedule();
		} else {
			jobRunning = false;
			accessLock.release();
		}
		
		return Status.OK_STATUS;
	}

	/**
	 * Schedules job asynchronously
	 */
	void reSchedule() {
		Runnable refreshRunnable = new Runnable(){
			public void run(){
				schedule(100);
			}
		};
		
		Display.getDefault().asyncExec(refreshRunnable);        		
	}
	
	/**
	 * Returns all read crash files. Can also return "No files"-bundle or "Waiting"-bundle.
	 * @param library error library
	 * @return list of crash files
	 */
	public CrashFileBundle[] getCrashFiles(ErrorLibrary library) {
		try {
			// do nothing until we get a valid ErrorLibrary, return "Waiting"-bundle
			if (library == null) {
				CrashFileBundle[] cFiles = new CrashFileBundle[1];
				cFiles[0] = new CrashFileBundle(false);
				return cFiles;
			}
			
			// crash files has not yet been read, start reading process,
			// and return "reading files"-bundle.
			if (crashFiles == null) {
				errorLibrary = library;
				reSchedule();
				CrashFileBundle[] cFiles = new CrashFileBundle[1];
				cFiles[0] = new CrashFileBundle(false);
				return cFiles;
			// files are up to date, return files
			} else {
				accessLock.acquire();
				try {
					// there are no files, return "No files"-bundle
					if (crashFiles.isEmpty()) {
						CrashFileBundle[] cFiles = new CrashFileBundle[1];
						cFiles[0] = new CrashFileBundle(true);
						return cFiles;
					// there are files, return them
					} else {
						return crashFiles.toArray(new CrashFileBundle[crashFiles.size()]);
					}
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					accessLock.release();
				}
				
				// if something went wrong, return "No files"-bundle 
				CrashFileBundle[] cFiles = new CrashFileBundle[1];
				cFiles[0] = new CrashFileBundle(true);
				return cFiles;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * Returns threads in one crash file
	 */
	public CrashFileBundle[] getThreads(CrashFileBundle crashFile) {
	
		List<CrashFileBundle> threadBundles = new ArrayList<CrashFileBundle>();
		List<Thread> threads = crashFile.getThreads();
		for(Thread thread : threads) {
			if(crashFile.isFullyDecoded())
				threadBundles.add(new CrashFileBundle(crashFile.getCrashFile(), crashFile.getOriginatingDirectory(), thread));
			else if(crashFile.isPartiallyDecoded())
				threadBundles.add(new CrashFileBundle(crashFile.getSummaryFile(), crashFile.getOriginatingDirectory(), thread));			
		}
		return threadBundles.toArray(new CrashFileBundle[threadBundles.size()]);
	}
	
	/**
	 * Returns the number of threads totally in all processes.
	 * @param crashFilebundle Crash file
	 * @return number of threads in the crash file
	 */
	public int getTotalThreadCount(CrashFileBundle crashFileBundle) {
		return crashFileBundle.getTotalThreadCount();
	}
	

	/**
	 * Starts reading all files from files system
	 */
	public void refresh() {
		accessLock.acquire();
		try {
			// if we are currently reading files, 
			if (jobRunning) {
				restart = true;
			// we are not reading files at the moment, schedule job
			} else {
				if (errorLibrary != null) {
					reSchedule();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			accessLock.release();
		}
	}
}