diff -r 14dc2103a631 -r ed1c9f64298a trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/engine/TraceLocationMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/engine/TraceLocationMap.java Wed Jun 23 14:35:40 2010 +0300 @@ -0,0 +1,487 @@ +/* +* 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: +* +* Maps trace locations into traces and vice versa +* +*/ +package com.nokia.tracebuilder.engine; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import com.nokia.tracebuilder.engine.source.SourceProperties; +import com.nokia.tracebuilder.model.Trace; +import com.nokia.tracebuilder.model.TraceGroup; +import com.nokia.tracebuilder.model.TraceModel; +import com.nokia.tracebuilder.model.TraceObject; +import com.nokia.tracebuilder.source.SourceContext; + +/** + * Maps trace locations into traces and vice versa. + * + */ +public final class TraceLocationMap { + + /** + * List of unrelated traces + */ + private TraceLocationList unrelated = new TraceLocationList(); + + /** + * Parser groups + */ + private HashMap parserGroups = new HashMap(); + + /** + * The trace model + */ + private TraceModel model; + + /** + * Global list of locations, used for verification purposes with + * GLOBAL_LOCATION_ASSERTS configuration flag + */ + private ArrayList globalList; + + /** + * Flag which is set when "Source missing" error is shown. Prevents it to be + * shown again + */ + private boolean missingSourceErrorShown; + + /** + * Creates a location mapper + * + * @param model + * the trace model + */ + public TraceLocationMap(TraceModel model) { + if (TraceBuilderConfiguration.GLOBAL_LOCATION_ASSERTS) { + globalList = new ArrayList(); + } + this.model = model; + model.addModelListener(new LocationMapModelListener(this)); + model.addExtension(unrelated); + } + + /** + * Adds the locations from the source file to the map + * + * @param source + * properties of the source to be added + */ + public void addSource(SourceProperties source) { + for (TraceLocation location : source) { + if (TraceBuilderConfiguration.GLOBAL_LOCATION_ASSERTS) { + if (globalList.contains(location)) { + TraceBuilderGlobals.getEvents().postAssertionFailed( + "Location already in global list", //$NON-NLS-1$ + location.getConvertedName()); + } else { + globalList.add(location); + } + } + // Generates locationAdded event via TraceLocationListListener + addNewLocationToTrace(location); + } + removeFromStorage(source); + } + + /** + * Updates the locations based on the new source properties + * + * @param source + * the source properties of the updated source + */ + void updateSource(SourceProperties source) { + for (TraceLocation location : source) { + if (location.isDeleted()) { + // Generates locationRemoved event via TraceLocationListListener + locationDeleted(location); + } else if (location.isContentChanged()) { + locationContentChanged(location); + } else { + // Generates locationChanged events if offset or length has + // changed + location.notifyLocationChanged(); + } + } + checkGlobalValidity(); + } + + /** + * Removes the locations of the closed source properties + * + * @param source + * the source properties of the removed source + * @param path + * the file path as string + * @param name + * the file name + */ + public void removeSource(SourceProperties source, String path, + String name) { + missingSourceErrorShown = false; + for (TraceLocation location : source) { + if (TraceBuilderConfiguration.GLOBAL_LOCATION_ASSERTS) { + if (!globalList.remove(location)) { + TraceBuilderGlobals.getEvents().postAssertionFailed( + "Location not in global list", //$NON-NLS-1$ + location.getConvertedName()); + } + } + TraceLocationList list = location.getLocationList(); + if (list != null) { + addLastKnownLocation(source, location, list, path, name); + // Generates locationRemoved event via TraceLocationListListener + list.removeLocation(location); + } else { + if (TraceBuilderConfiguration.ASSERTIONS_ENABLED) { + TraceBuilderGlobals.getEvents().postAssertionFailed( + "Unassociated location on remove", //$NON-NLS-1$ + location.getConvertedName()); + } + } + } + } + + /** + * Converts a location to a last known location + * + * @param source + * the source file + * @param location + * the location + * @param list + * the location list + * @param path + * the file path as string + * @param name + * the file name + */ + public void addLastKnownLocation(SourceProperties source, + TraceLocation location, TraceLocationList list, String path, String name) { + TraceObject owner = list.getOwner(); + if (owner instanceof Trace) { + LastKnownLocationList pll = owner + .getExtension(LastKnownLocationList.class); + if (pll == null) { + pll = new LastKnownLocationList(); + owner.addExtension(pll); + } + if (path == null) { + path = source.getFilePath(); + } + if (name == null) { + name = source.getFileName(); + } + if (path != null && name != null) { + if (new File(path + name).exists()) { + String cname = null; + String mname = null; + SourceContext context = source.getSourceEditor() + .getContext(location.getOffset()); + if (context != null) { + cname = context.getClassName(); + mname = context.getFunctionName(); + } + LastKnownLocation loc = new LastKnownLocation(path, name, + location.getLineNumber(), cname, mname); + pll.addLocation(loc); + } else { + showSourceRemovedError(name); + } + } + } + } + + /** + * Shows source with traces removed error + * + * @param name + * the source name + */ + private void showSourceRemovedError(String name) { + // TODO: Add an error code for this and move message there + if (!missingSourceErrorShown) { + missingSourceErrorShown = true; + String msg = Messages + .getString("TraceLocationMap.SourceWithTraceRemoved"); //$NON-NLS-1$ + TraceBuilderGlobals.getEvents().postErrorMessage(msg, name, true); + } + } + + /** + * Removes locations from last known storage + * + * @param source + * the source file + */ + private void removeFromStorage(SourceProperties source) { + File f = new File(source.getFilePath() + source.getFileName()); + Iterator groups = model.getGroups(); + while (groups.hasNext()) { + Iterator traces = groups.next().getTraces(); + while (traces.hasNext()) { + LastKnownLocationList list = traces.next().getExtension( + LastKnownLocationList.class); + if (list != null) { + Iterator locs = list.iterator(); + while (locs.hasNext()) { + LastKnownLocation loc = (LastKnownLocation) locs + .next(); + File locf = new File(loc.getFilePath() + + loc.getFileName()); + if (f.equals(locf)) { + locs.remove(); + list.fireLocationRemoved(loc); + } + } + } + } + } + } + + /** + * Adds a location to trace or to the unrelated list if a trace cannot be + * found. + * + * @param location + * the location to be added + */ + private void addNewLocationToTrace(TraceLocation location) { + TraceLocationList list; + Trace trace = model.findTraceByName(location.getOriginalName()); + if (trace != null) { + list = trace.getExtension(TraceLocationList.class); + if (list == null) { + list = new TraceLocationList(); + trace.addExtension(list); + } + } else { + String name = location.getParserRule().getLocationParser() + .getLocationGroup(); + if (name == null) { + list = unrelated; + } else { + list = parserGroups.get(name); + if (list == null) { + list = new TraceLocationList(name); + model.addExtension(list); + parserGroups.put(name, list); + } + } + } + list.addLocation(location); + } + + /** + * Checks that all locations are valid. + * Posts assertion failed events if not valid + */ + private void checkGlobalValidity() { + if (TraceBuilderConfiguration.GLOBAL_LOCATION_ASSERTS) { + boolean failure = false; + for (int i = 0; i < globalList.size(); i++) { + TraceLocation loc = globalList.get(i); + if (loc.isDeleted()) { + TraceBuilderGlobals.getEvents().postAssertionFailed( + "Deleted location found", //$NON-NLS-1$ + loc.getConvertedName()); + failure = true; + } else if (loc.getLocationList() == null) { + TraceBuilderGlobals.getEvents().postAssertionFailed( + "Unassociated location found", //$NON-NLS-1$ + loc.getConvertedName()); + failure = true; + } else if (loc.getTag() == null) { + TraceBuilderGlobals.getEvents().postAssertionFailed( + "Untagged location found", loc.getConvertedName()); //$NON-NLS-1$ + failure = true; + } else if (loc.getLength() <= loc.getTag().length()) { + TraceBuilderGlobals.getEvents().postAssertionFailed( + "Unassociated location found", //$NON-NLS-1$ + loc.getConvertedName()); + failure = true; + } + } + if (failure) { + TraceBuilderGlobals.getEvents().postCriticalAssertionFailed( + "Invalid location(s) found", null); //$NON-NLS-1$ + } + } + } + + /** + * Processes a location which has been deleted + * + * @param location + * the location that was deleted + */ + private void locationDeleted(TraceLocation location) { + if (TraceBuilderConfiguration.GLOBAL_LOCATION_ASSERTS) { + if (!globalList.remove(location)) { + TraceBuilderGlobals.getEvents().postAssertionFailed( + "Location not in global list", //$NON-NLS-1$ + location.getConvertedName()); + } + } + TraceLocationList list = location.getLocationList(); + if (list != null) { + list.removeLocation(location); + } else { + if (TraceBuilderConfiguration.ASSERTIONS_ENABLED) { + TraceBuilderGlobals.getEvents().postCriticalAssertionFailed( + "Unassociated location on delete", //$NON-NLS-1$ + location.getConvertedName()); + } + } + } + + /** + * Processes a location that has content changed flag + * + * @param location + * the location to be processed + */ + private void locationContentChanged(TraceLocation location) { + // If location is new, it does not have a list + if (location.getLocationList() == null) { + if (TraceBuilderConfiguration.GLOBAL_LOCATION_ASSERTS) { + if (globalList.contains(location)) { + TraceBuilderGlobals.getEvents().postAssertionFailed( + "Location already in global list", //$NON-NLS-1$ + location.getConvertedName()); + } else { + globalList.add(location); + } + } + // Generates locationAdded event via TraceLocationListListener + addNewLocationToTrace(location); + } else if (location.isNameChanged()) { + // Generates locationRemoved to listeners of old list and + // locationAdded to listeners of new list + moveLocation(location); + // Generates content and validity changed events + location.notifyLocationChanged(); + } else if (location.isContentChanged()) { + // Generates content and validity changed events + location.notifyLocationChanged(); + } + } + + /** + * Moves a location from trace to another. Does nothing if the target trace + * is same as source trace + * + * @param location + * the location to be moved + */ + private void moveLocation(TraceLocation location) { + Trace trace = location.getTrace(); + Trace newTrace = model.findTraceByName(location.getOriginalName()); + // If the traces differ, this relocates the location + // to different location array + if (trace != newTrace) { + TraceLocationList list = location.getLocationList(); + // Removes from existing list and adds the existing list to the + // updates list + list.removeLocation(location); + // Adds to new list. If new list does not exist, it is created + if (newTrace != null) { + list = newTrace.getExtension(TraceLocationList.class); + if (list == null) { + list = new TraceLocationList(); + newTrace.addExtension(list); + } + } else { + list = unrelated; + } + list.addLocation(location); + } + } + + /** + * Returns the list of unrelated trace objects. + * + * @return list of unrelated traces + */ + TraceLocationList getUnrelatedTraces() { + return unrelated; + } + + /** + * Removes all location lists from the model + */ + public void clearAll() { + model.removeExtension(unrelated); + Iterator groups = model.getGroups(); + while (groups.hasNext()) { + TraceGroup group = groups.next(); + Iterator traces = group.getTraces(); + while (traces.hasNext()) { + Trace trace = traces.next(); + TraceLocationList list = trace + .getExtension(TraceLocationList.class); + trace.removeExtension(list); + } + } + } + + /** + * Moves the locations from trace to unrelated list + * + * @param trace + * the trace + */ + void moveToUnrelated(Trace trace) { + TraceLocationList list = trace.getExtension(TraceLocationList.class); + if (list != null) { + trace.removeExtension(list); + for (LocationProperties loc : list) { + unrelated.addLocation((TraceLocation) loc); + } + } + } + + /** + * Moves locations from unrelated to the given trace + * + * @param trace + * the trace + */ + void moveFromUnrelated(Trace trace) { + String name = trace.getName(); + TraceLocationList list = null; + Iterator itr = unrelated.iterator(); + while (itr.hasNext()) { + TraceLocation location = (TraceLocation) itr.next(); + if (name.equals(location.getOriginalName())) { + list = trace.getExtension(TraceLocationList.class); + if (list == null) { + list = new TraceLocationList(); + trace.addExtension(list); + } + // NOTE: This must replicate the behavior of + // TraceLocationList.removeLocation + itr.remove(); + unrelated.fireLocationRemoved(location); + list.addLocation(location); + } + } + } +}