crashanalysis/crashanalyser/com.nokia.s60tools.crashanalyser/src/com/nokia/s60tools/crashanalyser/files/SummaryFile.java
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Tue, 24 Aug 2010 14:01:48 +0300
changeset 16 72f198be1c1d
parent 4 615035072f7e
permissions -rw-r--r--
Crash Analyser Carbide Extension 1.4.0

/*
* 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.files;

import java.util.*;
import java.io.*;
import javax.xml.parsers.*;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.*;
import org.w3c.dom.*;
import org.xml.sax.*;

import com.nokia.s60tools.crashanalyser.containers.OstTrace;
import com.nokia.s60tools.crashanalyser.containers.RegisterDetails;
import com.nokia.s60tools.crashanalyser.containers.CodeSegment;
import com.nokia.s60tools.crashanalyser.containers.Message;
import com.nokia.s60tools.crashanalyser.containers.EventLog;
import com.nokia.s60tools.crashanalyser.containers.Process;
import com.nokia.s60tools.crashanalyser.containers.RegisterSet;
import com.nokia.s60tools.crashanalyser.containers.Register;
import com.nokia.s60tools.crashanalyser.containers.Summary;
import com.nokia.s60tools.crashanalyser.containers.Symbol;
import com.nokia.s60tools.crashanalyser.containers.Thread;
import com.nokia.s60tools.crashanalyser.containers.Stack;
import com.nokia.s60tools.crashanalyser.data.*;
import com.nokia.s60tools.crashanalyser.model.*;
import com.nokia.s60tools.crashanalyser.plugin.CrashAnalyserPlugin;

/**
 * A summary file is a crash file which has not been fully decoded.
 * A summary file has been decoded without symbol information and it therefore
 * does not contain stack information. A summary file is a base class for CrashFile. 
 *
 */
public class SummaryFile extends CrashAnalyserFile implements IEditorInput, Cloneable {

	public enum ContentType {CRASH, REGMSG, REPORT};

	// XML tags
	public static final String TAG_SYMBOL_SET = "symbol_set";
	public static final String TAG_SYMBOL = "symbol";
	public static final String TAG_SOURCE = "source";
	public static final String TAG_PROCESS = "process";
	public static final String TAG_THREAD = "thread";
	public static final String TAG_STACK = "stack";
	public static final String TAG_SEG_STACKS = "seg_stacks";
	public static final String TAG_ID = "id";
	public static final String TAG_STACK_ENTRY = "stack_entry";
	public static final String TAG_CODESEG = "codeseg";
	public static final String TAG_REGISTER_SET = "register_set";
	public static final String TAG_SEG_EVENT_LOG = "seg_event_log";
	public static final String TAG_SEG_TRACES = "seg_traces";
	public static final String TAG_MESSAGE = "message";
	public static final String TAG_VI_ENTRY = "vi_entry";
	public static final String TAG_SOURCE_INFO = "source_info";
	public static final String TAG_TYPE = "type";
	public static final String TAG_SEGMENT = "segment";
	public static final String TAG_MAJOR = "major";
	public static final String TAG_MINOR = "minor";

	// data from xml file
	protected Map<Integer, Process> processes = null;
	protected Map<Integer, Message> messages = null;
	protected Map<Integer, Stack> stacks = null;
	protected Map<Integer, RegisterSet> registerSets = null;
	protected List<RegisterDetails> registerDetails = null;
	protected EventLog eventLog = null;
	protected OstTrace ostTrace = null;
	protected Summary crashSummary = null;
	protected String sourceFileType = "";
	protected String sourceFileName = "";
	protected String sourceFilePath = "";

	
	/**
	 * Constructor
	 * @param filePath file path to this crash file
	 * @param library error library
	 */
	protected SummaryFile(String filePath, ErrorLibrary library) {
		super(filePath, library);
	}
	
	/**
	 * Constructor
	 * @param filePath file path to this crash file
	 * @param library error library
	 */
	protected SummaryFile(String filePath, ErrorLibrary library, Thread thread) {
		super(filePath, library);
		threadInfo = thread;
	}

	public Object clone() {
		SummaryFile newSummaryFile = null;
		try {
			// Just shallow copy (i.e. no need to read information from file)
			newSummaryFile = (SummaryFile) super.clone();
		} catch (CloneNotSupportedException ex) {
			// ignore
		}
		return newSummaryFile;
	}
	
	

	/**
	 * Returns the file type of this crash file.
	 * @return "Decoded File"
	 */
	public String getFileType() {
		return "Partially Decoded File";
	}
	
	public String getSourceFileType() {
		return sourceFileType;
	}
	
	public String getSourceFileName() {
		return sourceFileName;
	}
	
	public String getSourceFilePath() {
		return sourceFilePath;
	}
	
	
	public void setThread(Thread thread) {
		threadInfo = thread;
		panicCategory = threadInfo.getExitCategory();
		panicCode = threadInfo.getExitReason();
		threadName = threadInfo.getFullName();
	}
	
	public List<Stack> getStandAloneStacks() {
		if (stacks != null && !stacks.isEmpty()) {
			return new ArrayList<Stack>(stacks.values());
		}
		
		return null;
	}
	
	public List<RegisterSet> getStandAloneRegisterSets() {
		if (registerSets != null && !registerSets.isEmpty()) {
			return new ArrayList<RegisterSet>(registerSets.values());
		}
		
		return null;
	}
	
	/**
	 * Checks whether this file contains any error or warning messages.
	 * @return true if file contains errors or warning, otherwise false is returned
	 */
	public boolean containsErrorsOrWarnings() {
		List<Message> msgs = getMessages();
		if (msgs != null && !msgs.isEmpty()) {
			for (int i = 0; i < msgs.size(); i++) {
				if (Message.MessageTypes.ERROR.equals(msgs.get(i).getMessageType()) ||
					Message.MessageTypes.WARNING.equals(msgs.get(i).getMessageType()))
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Returns the content type of the file.
	 * @return Returns crash/registration/report. If not found returns crash. 
	 */
	public ContentType getContentType() {
		List<Message> msgs = getMessages();
		if (msgs != null && !msgs.isEmpty()) {
			for (int i = 0; i < msgs.size(); i++) {
				if (Message.MessageTypes.MESSAGE.equals(msgs.get(i).getMessageType()) &&
						msgs.get(i).getTitle().equals("MobileCrash content type")) {
					if(msgs.get(i).getMessage().equals("registration")) 
						return ContentType.REGMSG;
					else if (msgs.get(i).getMessage().equals("report")) 
						return ContentType.REPORT;
				}
			}
		}
		// Returns crash by default.
		return ContentType.CRASH; 
	}

	/**
	 * Returns all messages
	 * @return all messages
	 */
	public List<Message> getMessages() {
		List<Message> msgs = new ArrayList<Message>();
		
		if (messages != null)
			msgs.addAll(messages.values());
		
		return msgs;
	}

	/**
	 * Reads crash file
	 * @param file crash file
	 * @param library error library
	 * @return read crash file or null
	 */
	public static SummaryFile read(File file, ErrorLibrary library) {
		if (file == null || !file.exists() || !file.isFile())
			return null;
		
		SummaryFile summaryFile = new SummaryFile(file.getAbsolutePath(), library);
		summaryFile.doRead();
		return summaryFile;
	}
	
	/**
	 * Reads crash file
	 * @param folder where xml file is
	 * @param library error library
	 * @return read crash file or null
	 */
	public static SummaryFile read(String folder, ErrorLibrary library) {
		String summaryFile = findFile(folder,"xml");
		
		// summary file doesn't exist
		if (summaryFile == null)
			return null;
		
		SummaryFile file = new SummaryFile(summaryFile, library);
		file.doRead();
		return file;
	}

	/**
	 * Reads crash file
	 * @param folder where xml file is
	 * @param library error library
	 * @param thread thread
	 * @return read crash file or null
	 */
	public static SummaryFile read(String folder, ErrorLibrary library, Thread thread) {
		String summaryFile = findFile(folder,"xml");
		
		// summary file doesn't exist
		if (summaryFile == null)
			return null;
		
		SummaryFile file = new SummaryFile(summaryFile, library, thread);
		file.doRead();
		return file;
	}
	
		/**
	 * Writes crash file into text or html file
	 * @param filePathWithoutFileName file path where file is to be written to
	 * @param html if false a .txt file is created. if true a .html file is created
	 */
	public void writeTo(String filePathWithoutFileName, boolean html) {
		File file = new File(FileOperations.addSlashToEnd(filePathWithoutFileName) + 
								FileOperations.getFileNameWithoutExtension(fileName) + ".txt");
		if (html)
			file = new File(FileOperations.addSlashToEnd(filePathWithoutFileName) + 
								FileOperations.getFileNameWithoutExtension(fileName) + ".html");
		writeTo(file);
	}
	
	/**
	 * Writes crash file into a file
	 * @param file file to be written to (.xml, .crashxml, .html, . txt, etc)
	 */
	public void writeTo(File file) {
		try {
			// file is saved as .xml or .crashxml
			if (file.getName().endsWith(CrashAnalyserFile.OUTPUT_FILE_EXTENSION) ||
					file.getName().endsWith("."+CrashAnalyserFile.SUMMARY_FILE_EXTENSION)) {
				FileOperations.copyFile(new File(filePath), file, true);
			// file is saved as .txt or .html
			} else {
				BufferedWriter out = null;
				try {
					// Create file 
					FileWriter fstream = new FileWriter(file, false);
					out = new BufferedWriter(fstream);
					
					// check whether we are writing an html file
					boolean html = false;
					if (file.getName().toLowerCase().endsWith(".htm") ||
							file.getName().toLowerCase().endsWith(".html"))
						html = true;
					
					// if html file, write html start tags
					if (html)
						writeHtmlStart(out);

					// write crash analyser file version data
					writeVersion(out);

					String panicDescription = "";

					// write process & thread summary
					Process process = getCrashedProcess();
					if (process != null) {
						writeLine(out, "Process", process.getName());

						Thread thread = process.getFirstThread();
						if (thread != null) {
							writeLine(out, "Thread", thread.getFullName());
							writeLine(out, "Stack Pointer", thread.getStackPointer());
							writeLine(out, "Link Register", thread.getLinkRegister());
							writeLine(out, "Program Counter", thread.getProgramCounter());
							panicDescription = thread.getPanicDescription();
						}
					} else if (threadInfo != null) {
						Process threadProcess = getProcessByThread(threadInfo.getId());
						
						if (threadProcess != null)
							writeLine(out, "Process", threadProcess.getName());
						
						writeLine(out, "Thread", threadInfo.getFullName());
						writeLine(out, "Stack Pointer", threadInfo.getStackPointer());
						writeLine(out, "Link Register", threadInfo.getLinkRegister());
						writeLine(out, "Program Counter", threadInfo.getProgramCounter());
						panicDescription = threadInfo.getPanicDescription();						
					}
					
					// write crash summary to file
					if (crashSummary != null) {
						crashSummary.writeTo(out);
						out.newLine();
					}

					if (html)
						writeLine(out, "</pre><A HREF=\"#STACKPOINTER\">Current Stack Pointer</A><pre>");
					
					// write panic description if panic description exists. Panic description
					// is written only to html file (not to .txt)
					if (!"".equals(panicDescription) && html) {
						writeLine(out, "</pre><h2>Panic Description</h2>");
						writeLine(out, panicDescription);
						writeLine(out, "<pre>");
					}
					
					List<Message> msgs = getMessages();
					// write errors and warnings to file
					if (msgs != null && !msgs.isEmpty()) {
						for (int i = 0; i < msgs.size(); i++) {
							msgs.get(i).writeTo(out);
						}
						out.newLine();
					}
					
					// write event log to file
					if (eventLog != null)
						eventLog.writeTo(out);					
						
					// write OST trace to file
					if (ostTrace != null)
						ostTrace.writeTo(out);					

					// write process data to file
					if (process != null) {
						process.writeTo(out, Process.StackItems.ALL, html);
						out.newLine();
					}

					// if html file, write html end tags
					if (html)
						writeHtmlEnd(out);
					
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					if (out != null)
						out.close();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Writes CrashAnalyser version information.
	 * @param out where to write
	 * @throws IOException
	 */
	void writeVersion(BufferedWriter out) throws IOException {
		String version = (String) CrashAnalyserPlugin.getDefault().getBundle().getHeaders().get("Bundle-Version"); //$NON-NLS-1$
		out.write("Crash Report Created with Crash Analyser Carbide Extension " + version);
		out.newLine();
		out.write("----------------------------------------------------------------");
		out.newLine();
		out.newLine();
	}
	
	/**
	 * Writes html start tags
	 * @param out where to write
	 * @throws IOException
	 */
	void writeHtmlStart(BufferedWriter out) throws IOException {
		out.write("<html><head><title>Crash File</title></head><body><pre>");
		out.newLine();
	}
	
	/**
	 * Writes html end tags
	 * @param out where to write
	 * @throws IOException
	 */
	void writeHtmlEnd(BufferedWriter out) throws IOException {
		out.newLine();
		out.write("</pre></body></html>");
		out.newLine();
	}
	
	void writeLine(BufferedWriter out, String header, String value) throws IOException {
		if (!"".equals(value)) {
			out.write(String.format(Summary.FORMAT, header, value));
			out.newLine();
		}
	}

	void writeLine(BufferedWriter out, String line) throws IOException {
		out.write(line);
		out.newLine();
	}

	/**
	 * Reads the file location of the given xml file
	 * @param xmlFilePath path to xml file
	 * @return file location or "".
	 */
	public static String getSourceFilePath(String xmlFilePath) {

		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			dbf.setValidating(false);

			// Using factory get an instance of document builder
			DocumentBuilder db = dbf.newDocumentBuilder();

			// As we are not validating we must create a EntityResolver that 
			// returns a dummy DTD. Without this we get an error message 
			// about missing MobileCrashXmlSchema.dtd.
			db.setEntityResolver(new EntityResolver()
	        {
	            public InputSource resolveEntity(String publicId, String systemId)
	                throws SAXException, IOException
	            {
	                return new InputSource(new StringReader(""));
	            }
	        });
			
			// parse using builder to get DOM representation of the XML file
			Document dom = db.parse(xmlFilePath);
			 
			// get the root element
			Element docEle = dom.getDocumentElement();		
			
			// read source file name
			NodeList nl = docEle.getElementsByTagName(TAG_SOURCE);
			if (nl != null && nl.getLength() > 0) {
				String sourcePath = XmlUtils.getNodeValue(nl.item(0));
				if (sourcePath != null && !"".equals(sourcePath)) {
					File f = new File(sourcePath);
					if (f.exists() && f.isFile()) {
						return sourcePath;
					}
				}
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
		
		return "";
	}
	
	@Override
	protected void doRead() {
		super.doRead();
		
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setValidating(false);

		try {

			// Using factory get an instance of document builder
			DocumentBuilder db = dbf.newDocumentBuilder();

			// As we are not validating we must create a EntityResolver that 
			// returns a dummy DTD. Without this we get an error message 
			// about missing MobileCrashXmlSchema.dtd.
			db.setEntityResolver(new EntityResolver()
	        {
	            public InputSource resolveEntity(String publicId, String systemId)
	                throws SAXException, IOException
	            {
	                return new InputSource(new StringReader(""));
	            }
	        });

			// parse using builder to get DOM representation of the XML file
			Document dom = db.parse(filePath);
			 
			// get the root element
			Element docEle = dom.getDocumentElement();		
			
			// read source file type
			NodeList nl = docEle.getElementsByTagName(TAG_SOURCE_INFO);
			if (nl != null && nl.getLength() > 0) {
				sourceFileType = XmlUtils.getTextValue((Element)nl.item(0), TAG_TYPE);
			}
			
			// read source file name
			nl = docEle.getElementsByTagName(TAG_SOURCE);
			if (nl != null && nl.getLength() > 0) {
				String sourcePath = XmlUtils.getNodeValue(nl.item(0));
				if (sourcePath != null && !"".equals(sourcePath)) {
					File f = new File(sourcePath);
					if (f.exists() && f.isFile()) {
						sourceFileName = f.getName();
						sourceFilePath = sourcePath;
					}
				}
			}
			
			messages = new HashMap<Integer, Message>();
			
			// check that is the xml file newer than what we support
			nl = docEle.getElementsByTagName(TAG_SEGMENT);
			if (nl != null && nl.getLength() > 0) {
				for (int i = 0; i < nl.getLength(); i++) {
					// if major number is larger than what we support, add an error to messages
					String major = XmlUtils.getTextValue((Element)nl.item(i), TAG_MAJOR);
					if (!"1".equals(major)) {
						messages.put(500, Message.newMessage(500, "Version Error", "XML file is newer than what is supported by this version of Crash Analyser.", Message.MessageTypes.ERROR));
						break;
					}
					// if minor number is larger than what we support, add a warning to messages
					String minor = XmlUtils.getTextValue((Element)nl.item(i), TAG_MINOR);
					if (!"00".equals(minor)) {
						messages.put(500, Message.newMessage(500, "Version Problem", "XML file has some new data which is not supported by this version of Crash Analyser.", Message.MessageTypes.WARNING));
						break;
					}
				}
			}
			
			// read summary data
			crashSummary = Summary.read(docEle);

			// read ROM id for this file
			if (crashSummary != null) {
				romId = crashSummary.getRomId();
			}
			
			// read event log
			nl = docEle.getElementsByTagName(TAG_SEG_EVENT_LOG);
			if (nl != null && nl.getLength() > 0) {
				eventLog = EventLog.read((Element)nl.item(0));
			}
			
			// read OST traces
			nl = docEle.getElementsByTagName(TAG_SEG_TRACES);
			if (nl != null && nl.getLength() > 0) {
				ostTrace = OstTrace.read((Element)nl.item(0));
			}

			// read messages from xml
			nl = docEle.getElementsByTagName(TAG_MESSAGE);
			if (nl != null && nl.getLength() > 0) {
				for (int i = 0; i < nl.getLength(); i++) {
					Element el = (Element)nl.item(i);
					Message message = Message.read(el);
					if (message != null)
						messages.put(message.getId(), message);
				}
			}			
			
			Map<Integer, CodeSegment> codeSegments = new HashMap<Integer, CodeSegment>();
			
			// read code segments
			nl = docEle.getElementsByTagName(TAG_CODESEG);
			if (nl != null && nl.getLength() > 0) {
				for (int i = 0; i < nl.getLength(); i++) {
					Element el = (Element)nl.item(i);
					CodeSegment codeSeg = CodeSegment.read(el, messages);
					if (codeSeg != null)
						codeSegments.put(codeSeg.getId(), codeSeg);
				}
			}

			Map<Integer, Symbol> symbols = new HashMap<Integer, Symbol>();

			// read symbols (Summary file won't have symbols, but this same method
			// is used by CrashFile)
			nl = docEle.getElementsByTagName(TAG_SYMBOL_SET);
			if(nl != null && nl.getLength() > 0) {
				// go throug all symbol_set tags
				for(int i = 0 ; i < nl.getLength(); i++) {
					// get the symbol_set element
					Element el = (Element)nl.item(i);
					NodeList childs = el.getChildNodes();
					// if symbol set has child nodes
					if (childs != null && childs.getLength() > 0) {
						String source = "";
						// go through all symbol_set child nodes
						for(int k = 0; k < childs.getLength(); k++) {
							Node child = childs.item(k);
							// if node is source node
							if (child.getNodeName() == TAG_SOURCE) {
								source = child.getFirstChild().getNodeValue();
							// if node is symbol node
							} else if (child.getNodeName() == TAG_SYMBOL) {
								Symbol symbol = Symbol.read((Element)child, source, codeSegments);
								if (symbol != null)
									symbols.put(symbol.getId(), symbol);
							}
						}
					}
				}
			}
					
			registerSets = new HashMap<Integer, RegisterSet>();
			Map<Integer, Register> allRegisters = new HashMap<Integer, Register>();
			
			// read register sets
			nl = docEle.getElementsByTagName(TAG_REGISTER_SET);
			if (nl != null && nl.getLength() > 0) {
				for (int i = 0; i < nl.getLength(); i++) {
					Element el = (Element)nl.item(i);
					RegisterSet registerSet = RegisterSet.read(el, symbols, messages);
					if (registerSet != null) {
						registerSets.put(registerSet.getId(),registerSet);
						
						// read all individual registers from sets
						List<Register> registers = registerSet.getRegisters();
						for (int j = 0; j < registers.size(); j++) {
							Register register = registers.get(j);
							if (!allRegisters.containsKey(register.getId())) {
								allRegisters.put(register.getId(), register);
							}
						}						
					}
				}
			}
			
			stacks = new HashMap<Integer, Stack>();
			
			// read stacks
			nl = docEle.getElementsByTagName(TAG_STACK);
			if (nl != null && nl.getLength() > 0) {
				for (int i = 0; i < nl.getLength(); i++) {
					Element el = (Element)nl.item(i);
					Stack stack = Stack.read(el, registerSets, allRegisters, symbols);
					if (stack != null)
						stacks.put(stack.getId(), stack);
				}
			}
			
			Map<Integer, Thread> threads = new HashMap<Integer, Thread>();
			
			// read threads
			nl = docEle.getElementsByTagName(TAG_THREAD);
			if (nl != null && nl.getLength() > 0) {
				for (int i = 0; i < nl.getLength(); i++) {
					Element el = (Element)nl.item(i);
					Thread thread = Thread.read(el, registerSets, symbols, stacks, errorLibrary);
					if (thread != null) {
						threads.put(thread.getId(), thread);
						stacks = thread.removeOwnStacks(stacks);
						registerSets = thread.removeOwnRegisterSets(registerSets);
					}
				}
			}
			
			processes = new HashMap<Integer, Process>();
			
			// read processes
			nl = docEle.getElementsByTagName(TAG_PROCESS);
			if (nl != null && nl.getLength() > 0) {
				for (int i = 0; i < nl.getLength(); i++) {
					Element el = (Element)nl.item(i);
					Process process = Process.read(el, threads, codeSegments);
					if (process != null)
						processes.put(process.getId(), process);
				}
			}
			
			registerDetails = new ArrayList<RegisterDetails>();
			
			// read register details
			nl = docEle.getElementsByTagName(TAG_VI_ENTRY);
			if (nl != null && nl.getLength() > 0) {
				for (int i = 0; i < nl.getLength(); i++) {
					Element el = (Element)nl.item(i);
					RegisterDetails details = RegisterDetails.read(el);
					if (details != null)
						registerDetails.add(details);
				}
			}

			// if xml contained crash date and time, parse them into this.time
			if (!"".equals(crashSummary.getCrashDate()) && !"".equals(crashSummary.getCrashTime()))
				time = crashSummary.getCrashDate() + " " + crashSummary.getCrashTime();
			
			// set panic data
			Process process = getCrashedProcess();
			processCount = getProcessCount();
			if (process != null) {
				Thread firstThread = process.getFirstThread();
				if (firstThread != null) {
					panicCategory = firstThread.getExitCategory();
					panicCode = firstThread.getExitReason();
					threadName = firstThread.getFullName();
				}
			} else if (threadInfo != null) {
				panicCategory = threadInfo.getExitCategory();
				panicCode = threadInfo.getExitReason();
				threadName = threadInfo.getFullName();
			}

			formatDescription();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Formats a description for this crash. 
	 */
	public void formatDescription() {
		Thread thread = null;
		
		if (threadInfo != null) {
			thread = threadInfo;
		}
		// get the first thread of the first process
		else if (processes != null && !processes.isEmpty()) {
			thread = getCrashedThread();
		}

		if (thread != null) {
			description = HtmlFormatter.formatCrashFileDescription(crashSummary, getMessages(), thread);
			shortDescription = HtmlFormatter.formatCrashFileDescription(crashSummary, null, thread);
		}
	}
	
	public Summary getSummary() {
		return crashSummary;
	}
	
	/**
	 * Get crashed process
	 * 
	 * @return first process or null
	 */
	public Process getCrashedProcess() {
		if (threadInfo != null) {
			return null;
		}
		
		Process crashedProcess = null;
		if (processes != null && !processes.isEmpty()) {
			Process[] processesArray = processes.values().toArray(new Process[processes.values().size()]);
			for (Process process : processesArray) {
				for (Thread thread : process.getThreads()) {
					String exitType = thread.getExitType();
					if (exitType.equalsIgnoreCase("Panic") || exitType.equalsIgnoreCase("Exception")) {
						crashedProcess = process;
						break;
					}					
				}
			}
		}
		return crashedProcess;
	}
	
	/**
	 * Get crashed process
	 * 
	 * @return first crashed thread
	 */
	public Thread getCrashedThread() {
		if (threadInfo != null) {
			return null;
		}
		
		Thread crashedThread = null;
		if (processes != null && !processes.isEmpty()) {
			Process[] processesArray = processes.values().toArray(new Process[processes.values().size()]);
			for (Process process : processesArray) {
				for (Thread thread : process.getThreads()) {
					String exitType = thread.getExitType();
					if (exitType.equalsIgnoreCase("Panic") || exitType.equalsIgnoreCase("Exception")) {
						crashedThread = thread;
						break;
					}					
				}
			}
		}
		return crashedThread;
	}

	/**
	 * Get process by thread id
	 * 
	 * @return Found process or null
	 */
	public Process getProcessByThread(int threadId) {
		
		Process threadProcess = null;
		if (processes != null && !processes.isEmpty()) {
			Process[] processesArray = processes.values().toArray(new Process[processes.values().size()]);
			for (Process process : processesArray) {
				for (Thread thread : process.getThreads()) {
					//String exitType = thread.getExitType();
					if (thread.getId() == threadId) {
						threadProcess = process;
						break;
					}					
				}
			}
		}
		return threadProcess;
	}
	
	/**
	 * Get process count
	 * 
	 * @return the number of processes or -1 if not available
	 */
	public int getProcessCount()
	{
		if (processes == null) {
			processCount = -1;
		}
		else {
			processCount = processes.size();
		}
		return processCount;
	}
	
	/**
	 * Get process count
	 * 
	 * @return the number of threads or -1 if not available
	 */
	public int getTotalThreadCount()
	{
		totalThreadCount = 0;
		if (processes == null) {
			return  -1;
		}
		for(Process process : processes.values()) {
			totalThreadCount += process.getThreads().size();
		}
		return totalThreadCount;
	}
	
	/**
	 * Returns all threads
	 * 
	 * @return all threads in all processes
	 */
	public List<Thread> getThreads() {
		List<Thread> allThreads = new ArrayList<Thread>();
		for(Process process : processes.values()) {
			allThreads.addAll(process.getThreads());
		}
		return allThreads;
	}

	public EventLog getEventLog() {
		return eventLog;
	}
	
	public OstTrace getOstTrace() {
		return ostTrace;
	}

	public List<RegisterDetails> getRegisterDetails() {
		return registerDetails;
	}
	
	public boolean exists() {
		return true;
	}

	public ImageDescriptor getImageDescriptor() {
		return null;
	}

	public String getName() {
		return fileName;
	}

	public IPersistableElement getPersistable() {
		return null;
	}

	public String getToolTipText() {
		return "Partial Crash Analyser File";
	}

	@SuppressWarnings("unchecked")
	public Object getAdapter(Class adapter) {
		return null;
	}	
}