trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/engine/propertydialog/RunInstrumenterCallback.java
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Tue, 24 Aug 2010 14:01:48 +0300
changeset 16 72f198be1c1d
parent 10 ed1c9f64298a
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:
*
* Dialog callback to process instrumentation
*
*/
package com.nokia.tracebuilder.engine.propertydialog;

import java.util.ArrayList;
import java.util.Iterator;

import com.nokia.tracebuilder.engine.CheckListDialogEntry;
import com.nokia.tracebuilder.engine.SourceContextManager;
import com.nokia.tracebuilder.engine.TraceBuilderDialogs;
import com.nokia.tracebuilder.engine.TraceBuilderGlobals;
import com.nokia.tracebuilder.engine.TraceObjectPropertyDialog;
import com.nokia.tracebuilder.engine.TraceObjectPropertyDialogTemplate;
import com.nokia.tracebuilder.engine.TraceBuilderDialogs.CheckListDialogParameters;
import com.nokia.tracebuilder.engine.TraceBuilderDialogs.CheckListDialogType;
import com.nokia.tracebuilder.engine.TraceBuilderErrorCodes.StringErrorParameters;
import com.nokia.tracebuilder.engine.TraceBuilderErrorCodes.TraceBuilderErrorCode;
import com.nokia.tracebuilder.engine.source.SourceEngine;
import com.nokia.tracebuilder.engine.source.SourceProperties;
import com.nokia.tracebuilder.engine.utils.TraceUtils;
import com.nokia.tracebuilder.model.Trace;
import com.nokia.tracebuilder.model.TraceBuilderException;
import com.nokia.tracebuilder.model.TraceGroup;
import com.nokia.tracebuilder.model.TraceModel;
import com.nokia.tracebuilder.model.TraceModelExtension;
import com.nokia.tracebuilder.model.TraceObjectModifier;
import com.nokia.tracebuilder.model.TraceObjectUtils;
import com.nokia.tracebuilder.project.FormattingUtils;
import com.nokia.tracebuilder.source.SourceContext;
import com.nokia.tracebuilder.source.SourceParser;

/**
 * Dialog callback to process instrumentation
 * 
 */
public final class RunInstrumenterCallback extends PropertyDialogCallback {

	/**
	 * Duplicate name changed warning
	 */
	private static final String DUPLICATE_NAME_CHANGED = Messages
			.getString("RunInstrumenterCallback.DuplicateName"); //$NON-NLS-1$

	/**
	 * Source engine for trace additions
	 */
	private SourceEngine sourceEngine;

	/**
	 * Context manager
	 */
	private SourceContextManager contextManager;

	/**
	 * Instrumenter ID
	 */
	private String instrumenterID;

	/**
	 * Creates a new instrumenter callback
	 * 
	 * @param model
	 *            the trace model
	 * @param sourceEngine
	 *            the source engine
	 * @param contextManager
	 *            the source context manager
	 * @param instrumenterID
	 *            the instrumenter ID
	 */
	public RunInstrumenterCallback(TraceModel model, SourceEngine sourceEngine,
			SourceContextManager contextManager, String instrumenterID) {
		super(model);
		this.sourceEngine = sourceEngine;
		this.contextManager = contextManager;
		this.instrumenterID = instrumenterID;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.tracebuilder.engine.PropertyDialogManagerCallback#
	 *      okSelected(com.nokia.tracebuilder.engine.TraceObjectPropertyDialog)
	 */
	public void okSelected(TraceObjectPropertyDialog dialog)
			throws TraceBuilderException {
		String groupName = dialog.getTarget();
		// If group does not exist, it will be created
		TraceGroup group = model.findGroupByName(groupName);
		int groupId = 0;
		if (group == null) {
			groupId = FormattingUtils.getGroupID(model, groupName);
			model.getVerifier().checkTraceGroupProperties(model, null, groupId,
					groupName);
		}
		Iterator<SourceContext> contexts = showFunctionQueryDialog(dialog);
		if (contexts != null) {
			String oldCategory = TraceBuilderGlobals.getEvents()
					.setEventCategory("Instrumenter"); //$NON-NLS-1$
			contextManager.setInstrumenterID(instrumenterID);
			model.startProcessing();
			try {
				// Group is created if it does not exist
				if (group == null && contexts.hasNext()) {
					group = model.getFactory().createTraceGroup(groupId,
							groupName, null);
				}
				while (contexts.hasNext()) {
					SourceContext context = contexts.next();
					contextManager.setContext(context);
					processContext(dialog, group, context);
				}
			} finally {
				model.processingComplete();
				// These must be reset even if errors occurs
				contextManager.setContext(null);
				contextManager.setInstrumenterID(""); //$NON-NLS-1$
				TraceBuilderGlobals.getEvents().setEventCategory(oldCategory);
			}
		}
	}

	/**
	 * Shows the function tree view, which can be used to select the functions
	 * to be instrumented
	 * 
	 * @param dialog
	 *            the property dialog
	 * @return the iterator of functions to be instrumented
	 * @throws TraceBuilderException
	 *             if instrumenter fails
	 */
	private Iterator<SourceContext> showFunctionQueryDialog(
			TraceObjectPropertyDialog dialog) throws TraceBuilderException {
		Iterator<SourceContext> retval = null;
		CheckListDialogEntry root = createFunctionQueryDialogTree(dialog);
		if (root.hasChildren()) {
			ArrayList<CheckListDialogEntry> rootItems = new ArrayList<CheckListDialogEntry>();
			rootItems.add(root);
			CheckListDialogParameters params = new CheckListDialogParameters();
			params.dialogType = CheckListDialogType.INSTRUMENT_FILES;
			params.rootItems = rootItems;
			params.expandLevel = 1;
			params.showRoot = false;
			int res = TraceBuilderGlobals.getDialogs().showCheckList(params);
			if (res == TraceBuilderDialogs.OK) {
				retval = getCheckedContexts(root);
			}
		} else {
			StringErrorParameters sp = new StringErrorParameters();
			sp.string = dialog.getTemplate().getTitle();
			throw new TraceBuilderException(
					TraceBuilderErrorCode.NO_FUNCTIONS_TO_INSTRUMENT_WITH_TEMPLATE,
					sp);
		}
		return retval;
	}

	/**
	 * Creates the tree for the query dialog
	 * 
	 * @param dialog
	 *            the property dialog
	 * @return the root of the tree
	 */
	private CheckListDialogEntry createFunctionQueryDialogTree(
			TraceObjectPropertyDialog dialog) {
		TraceObjectPropertyDialogTemplate template = dialog.getTemplate();
		CheckListDialogEntry root = new CheckListDialogEntry();
		// Tells the dialog to go through children and check those that are
		// checked
		root.setChecked(true);
		for (SourceProperties source : sourceEngine) {
			ArrayList<String> nonSourceFiles = sourceEngine.getNonSourceFiles();
			if (!nonSourceFiles.contains(source.getFilePath()+ source.getFileName())) {
				addSourceToList(template, root, source);
			}
		}
		return root;
	}

	/**
	 * Adds a source to the query dialog tree
	 * 
	 * @param template
	 *            the template from the property dialog
	 * @param root
	 *            the root entry
	 * @param source
	 *            the source properties
	 */
	private void addSourceToList(TraceObjectPropertyDialogTemplate template,
			CheckListDialogEntry root, SourceProperties source) {
		if (!source.isReadOnly()) {
			SourceParser parser = source.getSourceEditor();
			CheckListDialogEntry sourceEntry = new CheckListDialogEntry();
			sourceEntry.setObject(source.getFileName());
			Iterator<SourceContext> contexts = parser.getContexts();
			while (contexts.hasNext()) {
				addContextToList(template, sourceEntry, contexts.next());
			}
			if (sourceEntry.hasChildren()) {
				root.addChild(sourceEntry);
			}
		}
	}

	/**
	 * Adds a context to the query dialog tree
	 * 
	 * @param template
	 *            the template from the property dialog
	 * @param sourceEntry
	 *            the source where the context is to be added
	 * @param context
	 *            the source context to be added
	 */
	private void addContextToList(TraceObjectPropertyDialogTemplate template,
			CheckListDialogEntry sourceEntry, SourceContext context) {
		boolean available = true;
		if (template instanceof ContextBasedTemplate) {
			available = ((ContextBasedTemplate) template)
					.isAvailableInContext(context);
		}
		if (available) {
			CheckListDialogEntry contextEntry = new CheckListDialogEntry();
			contextEntry.setObject(context);
			contextEntry.setChecked(true);
			sourceEntry.addChild(contextEntry);
		}
	}

	/**
	 * Gets the checked contexts from the query tree
	 * 
	 * @param root
	 *            the root of the tree
	 * @return iterator of checked contexts
	 */
	private Iterator<SourceContext> getCheckedContexts(CheckListDialogEntry root) {
		ArrayList<SourceContext> contextList = new ArrayList<SourceContext>();
		for (CheckListDialogEntry entry : root) {
			for (CheckListDialogEntry context : entry) {
				if (context.isChecked()) {
					contextList.add((SourceContext) context.getObject());
				}
			}
		}
		Iterator<SourceContext> retval;
		if (!contextList.isEmpty()) {
			retval = contextList.iterator();
		} else {
			retval = null;
		}
		return retval;
	}

	/**
	 * Processes the given context
	 * 
	 * @param dialog
	 *            the flags from the dialog
	 * @param group
	 *            the target trace group
	 * @param context
	 *            the context to be processed
	 */
	private void processContext(TraceObjectPropertyDialog dialog,
			TraceGroup group, SourceContext context) {
		try {
			int id = group.getNextTraceID();
			String name = TraceUtils.convertName(formatTrace(dialog.getName(),
					context));
			String value = formatTrace(dialog.getValue(), context);
			TraceObjectModifier nameModifier = TraceObjectUtils
					.modifyDuplicateTraceName(group.getModel(), name);
			group.getModel().getVerifier().checkTraceProperties(group, null,
					id, nameModifier.getData(), value);
			TraceModelExtension[] extArray = createExtensions(group, dialog);
			Trace trace = group.getModel().getFactory().createTrace(group, id,
					nameModifier.getData(), value, extArray);
			if (nameModifier.hasChanged()) {
				TraceBuilderGlobals.getEvents().postWarningMessage(
						DUPLICATE_NAME_CHANGED + name, trace);
			}
			sourceEngine.insertTrace(trace, sourceEngine
					.getSourceOfContext(context), context.getOffset());
			TraceUtils.multiplyTrace(trace, context.getOffset(), sourceEngine);

			SourceProperties properties = sourceEngine
					.getSourceOfContext(context);
			String fileName = context.getFileName();
			if (fileName != null) {
				String headerFileName = TraceBuilderGlobals.getHeaderFileName(fileName);
				sourceEngine.addInclude(properties, headerFileName);
			}

		} catch (TraceBuilderException e) {
			TraceBuilderGlobals.getEvents().postError(e);
		}
	}

	/**
	 * Formats the trace specified into instrumenter dialog
	 * 
	 * @param format
	 *            the formatting
	 * @param context
	 *            the context where trace is added
	 * @return the formatted trace
	 */
	private String formatTrace(String format, SourceContext context) {
		String cname = context.getClassName();
		String fname = context.getFunctionName();
		return TraceUtils.formatTrace(format, cname, fname);
	}
}