sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi/src/com/nokia/carbide/cpp/internal/pi/analyser/AnalyserDataProcessor.java
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:32:31 +0200
changeset 2 b9ab3b238396
child 5 844b047e260d
permissions -rw-r--r--
Initial version of Performance Investigator under EPL

/*
 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of the License "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.carbide.cpp.internal.pi.analyser;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.progress.IProgressService;

import com.nokia.carbide.cpp.internal.pi.manager.PluginInitialiser;
import com.nokia.carbide.cpp.internal.pi.model.FunctionResolver;
import com.nokia.carbide.cpp.internal.pi.model.ParsedTraceData;
import com.nokia.carbide.cpp.internal.pi.model.RefinableTrace;
import com.nokia.carbide.cpp.internal.pi.model.TraceDataRepository;
import com.nokia.carbide.cpp.internal.pi.plugin.model.AbstractPiPlugin;
import com.nokia.carbide.cpp.internal.pi.plugin.model.ITrace;
import com.nokia.carbide.cpp.internal.pi.plugin.model.IVisualizable;
import com.nokia.carbide.cpp.internal.pi.test.AnalysisInfoHandler;
import com.nokia.carbide.cpp.internal.pi.test.IProvideTraceAdditionalInfo;
import com.nokia.carbide.cpp.internal.pi.visual.GenericTraceGraph;
import com.nokia.carbide.cpp.internal.pi.visual.GraphDrawRequest;
import com.nokia.carbide.cpp.internal.pi.visual.PICompositePanel;
import com.nokia.carbide.cpp.pi.editors.PIPageEditor;
import com.nokia.carbide.cpp.pi.importer.SampleImporter;
import com.nokia.carbide.cpp.pi.util.GeneralMessages;
import com.nokia.carbide.cpp.pi.util.PIExceptionRuntime;


/*
 * Class for abstracting data processing core routine for open and import
 */

public class AnalyserDataProcessor {
	// whether the profile file was read correctly
	public static int STATE_OK				= 0;
	public static int STATE_IMPORTING		= 1;
	public static int STATE_OPENING			= 2;
	public static int STATE_TIMESTAMP		= 3;
	public static int STATE_CANCELED		= 4;
	public static int STATE_INVALID			= 5;
	public static int TOTAL_PROGRESS_COUNT	= 10000;

	static AnalyserDataProcessor instance = null;

	// following states should be cleanup for every run
	
	// There should be only one progress monitor used by data processor
	// regardless the task, and we don't want to expose public interface
	// that juggle around progress monitor, to avoid messy situation of
	// multiple progress indicator
	static IProgressMonitor mp = null;
	static Exception lastException = null;
	private static int analyserDataProcessorState = STATE_INVALID;
		
	private AnalyserDataProcessor() {
		// singleton
	}
	
	public static AnalyserDataProcessor getInstance() {
		if (instance == null) {
			instance = new AnalyserDataProcessor();
		}
		return instance;
	}
	
	// return whether the processed data file was successfully read
	public int getState() {
		return analyserDataProcessorState;
	}
	
	public void setImportFailed() {
		analyserDataProcessorState = STATE_INVALID;
	}
	
	private void setProgressMonitor (IProgressMonitor progressMonitor) {
		mp = progressMonitor;
	}
	
	private IProgressMonitor getProgressMonitor() {
		return mp;
	}
		
	public Exception getLastException() {
		return lastException;
	}
	
	private void importNewAnalysis(Hashtable<Integer,String> traceFileNames, int uid) throws InterruptedException, InvocationTargetException {
		analyserDataProcessorState = STATE_IMPORTING;
		final int workUnitsForImport = TOTAL_PROGRESS_COUNT * 60 / 100;
		int workUnitsLeft = workUnitsForImport * 99 / 100;
		
		checkCancelledThrowIE();
			
		// loop through all the plugins associated with traces
		Enumeration<AbstractPiPlugin> enumer = PluginInitialiser.getPluginInstances(uid, "com.nokia.carbide.cpp.internal.pi.plugin.model.ITrace"); //$NON-NLS-1$
		Enumeration<AbstractPiPlugin> tmpEnum = PluginInitialiser.getPluginInstances(uid, "com.nokia.carbide.cpp.internal.pi.plugin.model.ITrace"); //$NON-NLS-1$
		int numberOfPlugins = 0;
		while (tmpEnum.hasMoreElements()) {
			numberOfPlugins++;
			tmpEnum.nextElement();
		}
		while (enumer.hasMoreElements())
    	{
    		ITrace plugin = (ITrace)enumer.nextElement();
    		int traceId = plugin.getTraceId();
    		AbstractPiPlugin p = (AbstractPiPlugin)plugin;
    		
    		// map trace plugins to this analysis data
    		NpiInstanceRepository.getInstance().addPlugin(uid, p);
    		if (traceId != -1)
    		{
    			String fileName = traceFileNames.get(traceId);
    			if (fileName != null)
    			{
    				File traceFile = new File(fileName);
    				if (traceFile.exists()) 
						if (traceFile.getName().endsWith(".dat"))  //$NON-NLS-1$
							ProfileReader.getInstance().readTraceFile(plugin, traceFile, this,uid);
    			}
    		}
            // assume this load takes 39%
    		getProgressMonitor().worked((workUnitsForImport * 39 / 100) / numberOfPlugins);
    		checkCancelledThrowIE();
            workUnitsLeft -= (workUnitsForImport * 39 / 100) / numberOfPlugins;
    	}
		getProgressMonitor().worked((workUnitsForImport * 60 / 100) - workUnitsLeft);
		checkCancelledThrowIE();
		workUnitsLeft = (workUnitsForImport * 60 / 100);
    	
		// refine any traces whose addresses can be refined
		Iterator<ParsedTraceData> traces = TraceDataRepository.getInstance().getTraceCollectionIter(uid);
    	if (traces == null) {
    		throw new InvocationTargetException(new PIExceptionRuntime(Messages.getString("AnalyserDataProcessor.0") + uid + Messages.getString("AnalyserDataProcessor.1")));     //$NON-NLS-1$ //$NON-NLS-2$
    	}
    	while (traces.hasNext())
    	{
    		ParsedTraceData trace = (ParsedTraceData)traces.next();
    		// for those trace data items that can be refined
    		if (trace.traceData instanceof RefinableTrace)
    		{
    			Iterator<ParsedTraceData> traces2 = TraceDataRepository.getInstance().getTraceCollectionIter(uid);
    		
    			while (traces2.hasNext())
    			{
    				ParsedTraceData trace2 = traces2.next();

    				// refine with other resolvers but not with own (which has been used already)
    				if (!trace2.equals(trace) && trace2.functionResolvers != null)
    				{
    					for (int i = 0; i < trace2.functionResolvers.length; i++)
    					{
    						FunctionResolver fr = trace2.functionResolvers[i];
    						System.out.println(Messages.getString("AnalyserDataProcessor.2") + trace.traceData.getClass().getName() + Messages.getString("AnalyserDataProcessor.3") + fr.getResolverString());     //$NON-NLS-1$ //$NON-NLS-2$

    						((RefinableTrace)trace.traceData).refineTrace(fr);
    					}
    				}
    				checkCancelledThrowIE();
    			}
    			
    			// after all refinement is done, do any final touches to the samples
    			((RefinableTrace)trace.traceData).finalizeTrace();
    		}
    		getProgressMonitor().worked(workUnitsLeft / 2);
    		checkCancelledThrowIE();
    		workUnitsLeft -= workUnitsLeft / 2;
    	}
    	// Should move resolver out of trace, PI only need resolver in import phase, trace is more of a
    	// core data in NPI file; before that, we would just strip all resolvers here
    	Iterator<ParsedTraceData> tracesItr = TraceDataRepository.getInstance().getTraceCollectionIter(uid);
    	while (tracesItr.hasNext()) {
    		ParsedTraceData ptd = tracesItr.next();
    		ptd.functionResolvers = null;
    	}
    	System.gc();
	}
	
	private void loadExistingAnalysis(final Composite parent, final String analysisFilename, final String displayName, final int uid) throws InvocationTargetException, InterruptedException {
		assertThrowITE(NpiInstanceRepository.getInstance().activeUid() == uid, Messages.getString("AnalyserDataProcessor.4"));   //$NON-NLS-1$
		
		// do the loading part with indicator in non-UI thread
		final IProgressMonitor pm = getProgressMonitor();
		pm.worked(1);
		class LoadRunnable implements Runnable {
			IOException myIOE = null;
			InterruptedException myIE  =null;
			
			public void handleException () throws InvocationTargetException, InterruptedException {
				if (myIOE != null) {
					String reason = Messages.getString("AnalyserDataProcessor.12") + analysisFilename; //$NON-NLS-1$
					if (myIOE.getMessage() != null) {
						reason += " " + myIOE.getMessage(); //$NON-NLS-1$
					}
					assertThrowITE(myIOE, reason);
				}
				if (myIE != null) {
					throw myIE;
				}
			}
			
			public void run() {
				try {
					ProfileReader.getInstance().loadAnalysisFile(analysisFilename, displayName, pm, uid);
				} catch (IOException e) {
					myIOE = e;
				} catch (InterruptedException e) {
					myIE = e;
				}	
			}
		}
		LoadRunnable loadRunnable = new LoadRunnable();
		new Thread(loadRunnable).run();
		loadRunnable.handleException();
		checkCancelledThrowIE();
		
		processTraceDrawAndResize(parent, false);
	}
	
	// called by createPage() of PIPageEditor
	public void openNpiForPIPageEditor(final URI analysisFileURI, final Composite parent, final int uid) {
		boolean isImport = analyserDataProcessorState == STATE_IMPORTING;
		final String displayName = new java.io.File(analysisFileURI).getName();
		
		if (isImport && getProgressMonitor() != null) {
			//import is already wrapped in runnable, and we should have progressmonitor
			getProgressMonitor().setTaskName(Messages.getString("AnalyserDataProcessor.5") + displayName);   //$NON-NLS-1$
			try {
				analyserDataProcessorState = STATE_OPENING;
				// by saying isImport true, we assume trace is set up proper in repository
				processTraceDrawAndResize(parent, true);
				analyserDataProcessorState = STATE_OK;
				if (false)
				internalOpenNPI (analysisFileURI, parent, uid);
			} catch (InvocationTargetException e) {
				analyserDataProcessorState = STATE_INVALID;
				String error = Messages.getString("AnalyserDataProcessor.6") + e.getTargetException().getMessage() + Messages.getString("AnalyserDataProcessor.7");   //$NON-NLS-1$ //$NON-NLS-2$
				if (e.getTargetException().getStackTrace() != null) {
					StringWriter sw = new StringWriter ();
					PrintWriter pw = new PrintWriter(sw);
					e.getTargetException().printStackTrace(pw);
					error += sw.toString() + "\n"; //$NON-NLS-1$
				}
				GeneralMessages.showErrorMessage(error);
			} catch (InterruptedException e) {
				String error = Messages.getString("AnalyserDataProcessor.8") + e.getMessage() + Messages.getString("AnalyserDataProcessor.9");   //$NON-NLS-1$ //$NON-NLS-2$
				analyserDataProcessorState = STATE_CANCELED;
			} catch (Exception e) {
				analyserDataProcessorState = STATE_INVALID;
				String error = Messages.getString("AnalyserDataProcessor.6") + e.getMessage() + Messages.getString("AnalyserDataProcessor.7");   //$NON-NLS-1$ //$NON-NLS-2$
				if (e.getStackTrace() != null) {
					StringWriter sw = new StringWriter ();
					PrintWriter pw = new PrintWriter(sw);
					e.printStackTrace(pw);
					error += sw.toString() + "\n"; //$NON-NLS-1$
				}
				GeneralMessages.showErrorMessage(error);
			}
		} else {
			setUp();
			//open need to be wrapped in runnable, and we should set progressmonitor
			IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
			IRunnableWithProgress runnable= new IRunnableWithProgress() {

				public void run(IProgressMonitor progressMonitor)
				throws InvocationTargetException, InterruptedException {
					setProgressMonitor(progressMonitor);
					progressMonitor.beginTask(Messages.getString("AnalyserDataProcessor.10") + displayName, AnalyserDataProcessor.TOTAL_PROGRESS_COUNT * 20 / 100); //$NON-NLS-1$
					internalOpenNPI (analysisFileURI, parent, uid);
				}

			};
			
			try {
				progressService.busyCursorWhile(runnable);
			} catch (InvocationTargetException e) {
				analyserDataProcessorState = STATE_INVALID;
			} catch (InterruptedException e) {
				analyserDataProcessorState = STATE_CANCELED;
			}
		}
		
		getProgressMonitor().done();
	}
	
	private void internalOpenNPI(final URI analysisFileURI, final Composite parent, final int uid) throws InvocationTargetException, InterruptedException {
	
		analyserDataProcessorState = STATE_OPENING;
		
		if (analysisFileURI == null) {
			assertThrowITE(false, Messages.getString("AnalyserDataProcessor.11")); //$NON-NLS-1$
			return;
		}
		
		String filePath = null;
		String displayName = null;
		
		filePath = analysisFileURI.getPath();
		displayName = new java.io.File(analysisFileURI).getName();
		
		loadExistingAnalysis(parent, filePath, displayName, uid);
		analyserDataProcessorState = STATE_OK;

	}
		
	public void importSaveAndOpen(final IFile analysisFile, boolean pollTillNpiSaved) {
		analyserDataProcessorState = STATE_IMPORTING;
		setProgressMonitor(null);
		
		final int uid = NpiInstanceRepository.getInstance().register(null);

		setUp();
		IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
		IRunnableWithProgress runnableImportAndSave = new IRunnableWithProgress() {

			public void run(IProgressMonitor progressMonitor)
					throws InvocationTargetException, InterruptedException {
				setProgressMonitor(progressMonitor);
				progressMonitor.beginTask(Messages.getString("AnalyserDataProcessor.17") + analysisFile.getName(), TOTAL_PROGRESS_COUNT);   //$NON-NLS-1$
				// open a profile data file that should contain at least thread/address information

				// import new .dat
				assertThrowITE(SampleImporter.getInstance().validate(), Messages.getString("AnalyserDataProcessor.18"));	  //$NON-NLS-1$
				
				// invoke analysis-specific plugin instances
				PluginInitialiser.invokePluginInstances(uid, "com.nokia.carbide.cpp.internal.pi.plugin.model.ITrace"); //$NON-NLS-1$

				StreamFileParser stp;
				try {
					stp = new StreamFileParser(new File(SampleImporter.getInstance().getDatFileName()));
					Hashtable<Integer,String> traceFileNames = new Hashtable<Integer,String>();
					ArrayList<File> tracesForCleanUp = new ArrayList<File>();

					// loop through all the plugins associated with traces and note their trace IDs names
					Enumeration<AbstractPiPlugin> enumer = PluginInitialiser.getPluginInstances(uid, "com.nokia.carbide.cpp.internal.pi.plugin.model.ITrace"); //$NON-NLS-1$
					while (enumer.hasMoreElements())
					{
						File tempFile;
						ITrace plugin = (ITrace)enumer.nextElement();
						int traceId = plugin.getTraceId();
						if (traceId != -1)
						{
							try {
								tempFile = stp.getTempFileForTraceType(traceId);
								if (tempFile != null)
								{
									tempFile.deleteOnExit();
									traceFileNames.put(traceId, tempFile.getAbsolutePath());
									tracesForCleanUp.add(tempFile);
								}

							} catch (IOException e) {
								throw new InvocationTargetException(e, Messages.getString("AnalyserDataProcessor.25")); //$NON-NLS-1$
							}
						}
					}
					
					// import a new analysis
					importNewAnalysis(traceFileNames, uid);

					// clean up temp file for each trace
					for (File traceFile : tracesForCleanUp) {
						traceFile.delete();
					}
				} catch (IOException e) {
					throw new InvocationTargetException(e, Messages.getString("AnalyserDataProcessor.26") + SampleImporter.getInstance().getDatFileName()); //$NON-NLS-1$
				}

				if (progressMonitor.isCanceled()) {
					throw new InterruptedException(Messages.getString("AnalyserDataProcessor.19"));   //$NON-NLS-1$
				}

				// give the .NPI file null contents
				byte[] b = new byte[0];
				try {
					analysisFile.create(new ByteArrayInputStream(b), true, null);
					// make sure we can open an input stream to the trace file
					analysisFile.getContents();
				} catch (CoreException e) {
					throw new InvocationTargetException(e, Messages.getString("AnalyserDataProcessor.14") + analysisFile.getName()); //$NON-NLS-1$
				}
				
				// extract additional info from importer
				int numberOfTraces = 0;
				Iterator<ParsedTraceData> enuTraces = TraceDataRepository.getInstance().getTraceCollectionIter(uid);
				AnalysisInfoHandler handler = NpiInstanceRepository.getInstance().activeUidGetAnalysisInfoHandler();

				// for all traces exist in .dat set up their additional info
			    while (enuTraces.hasNext()) {
			    	Object object = enuTraces.next();

			    	numberOfTraces++;
			    	
			    	if (object instanceof ParsedTraceData) {
			    		ParsedTraceData parsedTraceData = (ParsedTraceData) object;
			    		if (parsedTraceData.traceData != null) {
				    		Class traceClass = parsedTraceData.traceData.getClass();

							// this code is clumsy because the plugin, not the trace, has the trace ID info
				    		Enumeration<AbstractPiPlugin> enuPlugins = PluginInitialiser.getPluginInstances(uid, "com.nokia.carbide.cpp.internal.pi.plugin.model.ITrace"); //$NON-NLS-1$
							while (enuPlugins.hasMoreElements())
							{
								ITrace plugin = (ITrace)enuPlugins.nextElement();
								// only do when trace exist in .data
								if (traceClass == plugin.getTraceClass()) {
							    	if (plugin instanceof IProvideTraceAdditionalInfo) {
										((IProvideTraceAdditionalInfo)plugin).setupInfoHandler(handler);						    		
							    	}
								}
							}			
			    		}
			    	}
			    }
				
				// refresh so project know the update done by Java(non-Eclipse API)
				try {
					analysisFile.refreshLocal(0, null);
				} catch (CoreException e) {
					throw new InvocationTargetException(e, Messages.getString("AnalyserDataProcessor.15") + analysisFile.getName()); //$NON-NLS-1$
				}		
			}
		};
		
		IRunnableWithProgress runnableOpen = new IRunnableWithProgress() {

			public void run(IProgressMonitor arg0)
					throws InvocationTargetException, InterruptedException {
				// open the saved file
				if (analysisFile.exists() && AnalyserDataProcessor.getInstance().getState() == STATE_IMPORTING ) {
						// open the file itself
					
					// need to open in UI context
					Display.getDefault().syncExec(new Runnable() {

						public void run() {
							IEditorPart editor = null;
							try {
								editor = IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() , analysisFile, true);
							} catch (PartInitException e) {
								try {
									assertThrowITE(e, analysisFile.getName() + Messages.getString("AnalyserDataProcessor.24")); //$NON-NLS-1$
								} catch (InvocationTargetException e1) {
									//already set data structure proper, do nothing
								}
							}
							if (AnalyserDataProcessor.getInstance().getState() == STATE_CANCELED) {
								// close the editor file view
								editor.getSite().getPage().closeEditor(editor, false);
							} else if (AnalyserDataProcessor.getInstance().getState() != STATE_OK ) {
								// close the editor file view
								editor.getSite().getPage().closeEditor(editor, false);
							}							
						}
					});
				}
			}
			
		};
		
		try {
			progressService.busyCursorWhile(runnableImportAndSave);
		
			final WorkspaceJob saveNpi = new WorkspaceJob (Messages.getString("AnalyserDataProcessor.savingImportedFile")) { //$NON-NLS-1$

				public IStatus runInWorkspace(IProgressMonitor monitor)
						throws CoreException {
					try {
						ProfileReader.getInstance().writeAnalysisFile(analysisFile.getLocation().toString(), monitor, uid);
					} catch (InvocationTargetException e) {
						return new Status(IStatus.ERROR, "com.nokia.carbide.cpp.pi", Messages.getString("AnalyserDataProcessor.invocationTargetException"), e); //$NON-NLS-1$ //$NON-NLS-2$
					} catch (InterruptedException e) {
						return new Status(IStatus.CANCEL, "com.nokia.carbide.cpp.pi", Messages.getString("AnalyserDataProcessor.interruptedException"), e); //$NON-NLS-1$ //$NON-NLS-2$
					}
					return new Status(IStatus.OK, "com.nokia.carbide.cpp.pi", Messages.getString("AnalyserDataProcessor.ok"), null); //$NON-NLS-1$ //$NON-NLS-2$
				}
				
			};
		
			progressService.busyCursorWhile(runnableOpen);

			saveNpi.setPriority(Job.DECORATE);
			saveNpi.addJobChangeListener(new IJobChangeListener () {
				
				public void aboutToRun(IJobChangeEvent event) {
				}

				public void awake(IJobChangeEvent event) {
				}

				public void done(IJobChangeEvent event) {
					if (saveNpi.getResult().getSeverity()  != IStatus.OK) {
						HandleRunnableException (saveNpi.getResult().getException(), uid, analysisFile);
					}
				}

				public void running(IJobChangeEvent event) {
				}

				public void scheduled(IJobChangeEvent event) {
				}

				public void sleeping(IJobChangeEvent event) {
				}
				
			});
			
			saveNpi.schedule();
			
			if (pollTillNpiSaved) {
				while (saveNpi.getState() != Job.NONE) {
					// until it's done
				}
			}
			
		} catch (InvocationTargetException e) {
			HandleRunnableException(e, uid, analysisFile);
		} catch (InterruptedException e) {
			HandleRunnableException(e, uid, analysisFile);
		}							
	}
	
	private void HandleRunnableException(Throwable throwable, final int uid, IFile analysisFile) {
		NpiInstanceRepository.getInstance().unregister(uid);
		if (throwable instanceof InvocationTargetException) {
			String error = Messages.getString("AnalyserDataProcessor.20"); //$NON-NLS-1$
			if (throwable.getMessage() != null) {
				error += throwable.getMessage() + "\n"; //$NON-NLS-1$
			}
			error += Messages.getString("AnalyserDataProcessor.21");   //$NON-NLS-1$ //$NON-NLS-2$
			if (((InvocationTargetException)throwable).getTargetException().getStackTrace() != null) {
				StringWriter sw = new StringWriter ();
				PrintWriter pw = new PrintWriter(sw);
				((InvocationTargetException)throwable).printStackTrace(pw);
				error += sw.toString() + "\n"; //$NON-NLS-1$
			}
			GeneralMessages.showErrorMessage(error);
			analyserDataProcessorState = STATE_INVALID;
		} else if (throwable instanceof InterruptedException) {
			GeneralMessages.showErrorMessage(Messages.getString("AnalyserDataProcessor.22"));  //$NON-NLS-1$
			analyserDataProcessorState = STATE_CANCELED;
		} else {
			String error = Messages.getString("AnalyserDataProcessor.20"); //$NON-NLS-1$
			if (throwable.getStackTrace() != null) {
				StringWriter sw = new StringWriter ();
				PrintWriter pw = new PrintWriter(sw);
				((InvocationTargetException)throwable).printStackTrace(pw);
				error += sw.toString() + "\n"; //$NON-NLS-1$
			}
			GeneralMessages.showErrorMessage(error);
			analyserDataProcessorState = STATE_INVALID;		
		}
		// don't leave any garbage behind if we failed or bailed
		if (analysisFile != null && AnalyserDataProcessor.getInstance().getState() != STATE_OK ) {
			java.io.File javaFile = new java.io.File(analysisFile.getLocation().toString());
			boolean deleted = javaFile.delete();
				
			if (deleted == false){
				try {
					analysisFile.delete(true, null);
				} catch (CoreException ce) {
					ce.printStackTrace();
				}
			}

			try {
				// force Eclipse to be aware of the removed file by doing an IFile refresh
				analysisFile.refreshLocal(0, null);
			} catch (CoreException ce) {
				ce.printStackTrace();
			}
		}	
	}
	
	// standalone for save as
	public void saveAnalysis(final String filename, final int uid) throws InvocationTargetException, InterruptedException {
		IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
		IRunnableWithProgress runnable= new IRunnableWithProgress() {

			public void run(IProgressMonitor progressMonitor)
					throws InvocationTargetException, InterruptedException {
				saveAnalysisInternal(filename, uid);
			}
			
		};
		try {
			progressService.busyCursorWhile(runnable);
		} catch (InvocationTargetException e) {
			analyserDataProcessorState = STATE_INVALID;
		} catch (InterruptedException e) {
			analyserDataProcessorState = STATE_CANCELED;
		}
	}

	// save profiling data to NPI file
	private void saveAnalysisInternal(final String filename, final int uid) throws InvocationTargetException, InterruptedException {
		ProfileReader.getInstance().writeAnalysisFile(filename, getProgressMonitor(), uid);
	}
	
	private void processVisualizableItem(ITrace plugin)
	{
		IVisualizable visualizable = (IVisualizable)plugin;
		
		if (!visualizable.arePagesCreated())
		{
			// create any editor pages
			for (int i = 0; i < visualizable.getCreatePageCount(); i++)
			{
				int index = visualizable.getCreatePageIndex(i);
				ArrayList<ProfileVisualiser> pages = NpiInstanceRepository.getInstance().activeUidGetProfilePages();
				if (pages != null) {
					// if we don't care what the page index is, or the index is too big, add it to the end
					if ((index == PIPageEditor.NEXT_AVAILABLE_PAGE) || (index > pages.size())) {
						index = pages.size();
						
						// let the plugin know what index we assigned
						visualizable.setPageIndex(i, index);
					}
					
					ProfileVisualiser pV = visualizable.createPage(index);
					
					// add the page to the editor
					if (pV != null)
						pages.add(index, pV);					
				}
			}
		}
		
		int uid = NpiInstanceRepository.getInstance().activeUid();
		
		// determine how many graphs to draw (several may get added to the same page)
		for (int i = 0; i < visualizable.getGraphCount(); i++)
		{
			GraphDrawRequest gdr   = visualizable.getDrawRequest(i);
			GenericTraceGraph gtg  = visualizable.getTraceGraph(i);
			String title           = visualizable.getGraphTitle(i);
			int	pageNumber         = visualizable.getPageNumber(i);
			
			ProfileVisualiser page = NpiInstanceRepository.getInstance().getProfilePage(uid, pageNumber);

			if (gtg != null)
			{
				page.getTopComposite().addGraphComponent(gtg, title, visualizable.getClass(), gdr);
			}

			Integer lastSample = visualizable.getLastSample(i);
			if (lastSample != null)
			{
				page.setLastSampleX(lastSample.intValue());
			}
		}
	}
	
	private void processTraceDrawAndResize(final Composite parent, boolean isImport) {
		// if it is import, everything is already read in place, otherwise
		// setup those from object file read
		if (!isImport) {
			ProfileReader.getInstance().processDataReadFromNpiFile(this);
		}
		
		int uid = NpiInstanceRepository.getInstance().activeUid();
		
		// initialize trace and do visual
		ArrayList<AbstractPiPlugin> plugins = NpiInstanceRepository.getInstance().getPlugins(uid);
		for (final AbstractPiPlugin plugin : plugins) {
			if (plugin instanceof ITrace) {
				final ParsedTraceData parsedData = TraceDataRepository.getInstance().getTrace(uid, ((ITrace)plugin).getTraceClass());
				if (parsedData != null) {
					final ITrace pluginTrace = (ITrace)plugin;
					pluginTrace.initialiseTrace(parsedData.traceData);
	    			// do the graphic painting with indicator, SWT require it to be in UI thread
					if (plugin instanceof IVisualizable) {
						Display.getDefault().syncExec( new Runnable() {
							public void run() {
								processVisualizableItem(pluginTrace);
							}
		    			});	
					}
				}
			}
		}
		
		if (!isImport) {
			ProfileReader.getInstance().setAddtionalDataForRecordable();
		}
		
		ProfileReader.getInstance().setTraceMenus(NpiInstanceRepository.getInstance().getPlugins(uid), uid);
		// do the graphic painting with indicator, SWT require it to be in UI thread
		Display.getDefault().syncExec( new Runnable() {
			public void run() {
				parent.addPaintListener( new PaintListener () {
		  			
					public void paintControl(PaintEvent arg0) {

						if(parent.getBounds().width > 0) {
							ArrayList<ProfileVisualiser> pages = NpiInstanceRepository.getInstance().activeUidGetProfilePages();
							
							// make sure we are called after the pages have been created?
							if (pages.size() > 0) {
								for (final ProfileVisualiser page : pages) {
									// NOTE: This assumes that the first profile page has a graph
						        	final PICompositePanel visibleComposite = page.getTopComposite();
						        	visibleComposite.performZoomToGraph(visibleComposite, parent.getBounds().width);
						        	
						        	//TODO uncomment when performance issues relating to gfc are solved
						        	//Select whole graph
						        	//visibleComposite.selectWholeGraph();
								}
			
								// scale to whole trace only once
					        	parent.removePaintListener(this);
							}
						}
					}
		  		});
			}
		});
	}
	
	// This is for test automation, removing time stamps, so we can diff .npi
	public void importForStrippingTimeStamp(final Composite parent) {
		if (SampleImporter.getInstance().isStrippingTimeStamp()) {
			// had to do this monkey business for pi validation because
			// serialization is an untestable format
			// read file
			final SampleImporter sampleImporter = SampleImporter.getInstance();

			IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
			IRunnableWithProgress runnable= new IRunnableWithProgress() {

				public void run(IProgressMonitor progressMonitor)
						throws InvocationTargetException,
						InterruptedException {
					setProgressMonitor(progressMonitor);
					progressMonitor.beginTask(Messages.getString("AnalyserDataProcessor.23"), 100);   //$NON-NLS-1$
					try {
						int uid = NpiInstanceRepository.getInstance().activeUid();
						loadExistingAnalysis(parent, sampleImporter.getDatFileName(), sampleImporter.getDatFileName(), uid);
						// time stample differs for every save, take it out
						AnalysisInfoHandler infoHandler = NpiInstanceRepository.getInstance().activeUidGetAnalysisInfoHandler();
						if (infoHandler != null) {
							infoHandler.eraseTimeStamp();
						}
						// write file
						saveAnalysisInternal(sampleImporter.getPiFileName(), uid);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			};
			try {
				progressService.busyCursorWhile(runnable);
			} catch (InvocationTargetException e) {
				analyserDataProcessorState = STATE_INVALID;
				e.printStackTrace();
			} catch (InterruptedException e) {
				analyserDataProcessorState = STATE_CANCELED;
				e.printStackTrace();
			}
			setProgressMonitor(null);
		}
	}
	
	// catch all for any exception, so we can print an error stack trace page later
	private void assertThrowITE(boolean cond, String message) throws InvocationTargetException {
		if (!cond) {
			PIExceptionRuntime pire = new PIExceptionRuntime(message);	//$NON-NLS-1$
			InvocationTargetException ite = new InvocationTargetException(pire);
			lastException = ite;
			analyserDataProcessorState = STATE_INVALID;
			if (getProgressMonitor() != null) {
				getProgressMonitor().done();
			}
			GeneralMessages.showErrorMessage(message);
			throw ite;
		}
	}
	
	private void assertThrowITE(Exception e, String message) throws InvocationTargetException {
		InvocationTargetException ite;
		if (message != null) {
			ite = new InvocationTargetException(e, message);
		} else {
			ite = new InvocationTargetException(e);
		}
		lastException = ite;
		analyserDataProcessorState = STATE_INVALID;
		if (getProgressMonitor() != null) {
			getProgressMonitor().done();
		}
		GeneralMessages.showErrorMessage(message);
		throw ite;

	}

	
	// General handling for Cancel operation
	public void checkCancelledThrowIE() throws InterruptedException {
		if (getProgressMonitor() != null && getProgressMonitor().isCanceled()) {
			InterruptedException ie = new InterruptedException();
			analyserDataProcessorState = STATE_CANCELED;
			throw ie;
		}
	}
	
	private void setUp() {
		if (getProgressMonitor() != null) {
			getProgressMonitor().done();
			setProgressMonitor(null);
		}
		lastException = null;
		analyserDataProcessorState = STATE_OK;
	}
}