--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tracefw/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/model/TraceModel.java Mon Aug 23 15:29:36 2010 +0300
@@ -0,0 +1,997 @@
+/*
+* 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:
+*
+* Trace model is a collection of trace groups
+*
+*/
+package com.nokia.tracecompiler.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Properties;
+
+import com.nokia.tracecompiler.engine.TraceCompilerEngineGlobals;
+import com.nokia.tracecompiler.engine.TraceCompilerEngineErrorCodes.TraceCompilerErrorCode;
+import com.nokia.tracecompiler.engine.project.SortedProperties;
+import com.nokia.tracecompiler.project.FormattingUtils;
+import com.nokia.tracecompiler.source.SourceConstants;
+
+/**
+ * Trace model is a collection of trace groups. Listener interfaces can be
+ * attached to a trace model to receive change notifications when traces are
+ * added, removed or modified.
+ *
+ */
+public class TraceModel extends TraceObject implements Iterable<TraceGroup> {
+
+ /**
+ * Group property prefix
+ */
+ public final String GROUP_PROPERTY_PREFIX = "[GROUP]"; //$NON-NLS-1$
+
+ /**
+ * Trace property prefix
+ */
+ public final String TRACE_PROPERTY_PREFIX = "[TRACE]"; //$NON-NLS-1$
+
+ /**
+ * Obsolete property prefix
+ */
+ public final String OBSOLETE_PROPERTY_PREFIX = "[[OBSOLETE]]"; //$NON-NLS-1$
+
+ /**
+ * Group Id prefix
+ */
+ public final String GROUP_ID_PREFIX = "["; //$NON-NLS-1$
+
+ /**
+ * Group Id suffix
+ */
+ public final String GROUP_ID_SUFFIX = "]"; //$NON-NLS-1$
+
+ /**
+ * Factory object for creating other trace objects
+ */
+ private TraceObjectFactory factory;
+
+ /**
+ * Property verifier interface
+ */
+ private TraceObjectPropertyVerifier verifier;
+
+ /**
+ * List of trace groups
+ */
+ private ArrayList<TraceGroup> groups = new ArrayList<TraceGroup>();
+
+ /**
+ * List of traces, sorted by name
+ */
+ private ArrayList<Trace> tracesByName = new ArrayList<Trace>();
+
+ /**
+ * List of model listeners
+ */
+ private ArrayList<TraceModelListener> modelListeners = new ArrayList<TraceModelListener>();
+
+ /**
+ * List of extension listeners
+ */
+ private ArrayList<TraceModelExtensionListener> extensionListeners = new ArrayList<TraceModelExtensionListener>();
+
+ /**
+ * List of reset listeners
+ */
+ private ArrayList<TraceModelResetListener> resetListeners = new ArrayList<TraceModelResetListener>();
+
+ /**
+ * Processing listeners
+ */
+ private ArrayList<TraceProcessingListener> processingListeners = new ArrayList<TraceProcessingListener>();
+
+ /**
+ * List of constant tables
+ */
+ private ArrayList<TraceConstantTable> constantTables = new ArrayList<TraceConstantTable>();
+
+ /**
+ * Validity flag
+ */
+ private boolean valid;
+
+ /**
+ * Number of nested calls to startProcessing
+ */
+ private int isProcessing;
+
+ /**
+ * Model was changed during processing
+ */
+ private boolean modelChangedDuringProcessing;
+
+ /**
+ * Fixed Ids from fixed Ids definition file
+ */
+ private SortedProperties fixedIds;
+
+ /**
+ * Hex radix
+ */
+ public int HEX_RADIX = 16; // CodForChk_Dis_Magic
+
+ /**
+ * Constructor
+ *
+ * @param factory
+ * the rule factory
+ * @param verifier
+ * the property verifier
+ * @throws TraceCompilerException
+ */
+ public TraceModel(TraceObjectRuleFactory factory,
+ TraceObjectPropertyVerifier verifier) throws TraceCompilerException {
+ // Stored for callback purposes
+ setModel(this);
+ this.factory = new TraceObjectFactory(this, factory);
+ this.verifier = verifier;
+ }
+
+ /**
+ * Adds a new trace model listener to this model
+ *
+ * @param listener
+ * the new listener
+ */
+ public void addModelListener(TraceModelListener listener) {
+ modelListeners.add(listener);
+ }
+
+ /**
+ * Removes a trace model listener. Does nothing if the listener is not found
+ *
+ * @param listener
+ * the listener to be removed
+ */
+ public void removeModelListener(TraceModelListener listener) {
+ modelListeners.remove(listener);
+ }
+
+ /**
+ * Adds a new trace model extension listener to this model
+ *
+ * @param listener
+ * the new listener
+ */
+ public void addExtensionListener(TraceModelExtensionListener listener) {
+ extensionListeners.add(listener);
+ }
+
+ /**
+ * Removes a trace model extension listener. Does nothing if the listener is
+ * not found
+ *
+ * @param listener
+ * the listener to be removed
+ */
+ public void removeExtensionListener(TraceModelExtensionListener listener) {
+ extensionListeners.remove(listener);
+ }
+
+ /**
+ * Adds a new trace model reset listener to this model
+ *
+ * @param listener
+ * the new listener
+ */
+ public void addResetListener(TraceModelResetListener listener) {
+ resetListeners.add(listener);
+ }
+
+ /**
+ * Removes a trace model reset listener. Does nothing if the listener is not
+ * found
+ *
+ * @param listener
+ * the listener to be removed
+ */
+ public void removeResetListener(TraceModelResetListener listener) {
+ resetListeners.remove(listener);
+ }
+
+ /**
+ * Adds a new trace model listener to this model
+ *
+ * @param listener
+ * the new listener
+ */
+ public void addProcessingListener(TraceProcessingListener listener) {
+ processingListeners.add(listener);
+ }
+
+ /**
+ * Removes a processing listener. Does nothing if the listener is not found
+ *
+ * @param listener
+ * the listener to be removed
+ */
+ public void removeProcessingListener(TraceProcessingListener listener) {
+ processingListeners.remove(listener);
+ }
+
+ /**
+ * Returns highest group ID + 1. Can be used to create an unique ID for a
+ * new trace group.
+ *
+ * @return the next trace group ID
+ * @throws TraceCompilerException
+ */
+ public int getNextGroupID() throws TraceCompilerException {
+ int currentMaxGroupId = 0;
+ int nextGroupId = 0;
+ // Check if there are some fixed Ids
+ if (fixedIds != null) {
+ Enumeration<Object> keys = this.fixedIds.keys();
+ // Go through fixed Ids and check if there are fixed group Ids
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ if (key.startsWith(GROUP_PROPERTY_PREFIX)
+ || key.startsWith(OBSOLETE_PROPERTY_PREFIX
+ + GROUP_PROPERTY_PREFIX)) {
+ // Fixed group Id found. Try to covert it to int value.
+ String value = fixedIds.getProperty(key);
+ int fixedId = 0;
+ try {
+ fixedId = Integer.decode(value).intValue();
+ } catch (NumberFormatException e) {
+ // Corrupted. Get next group Id later on.
+ currentMaxGroupId = 0;
+ break;
+ }
+ // Check if found fixed Id is bigger than current max group
+ // Id
+ if (fixedId > currentMaxGroupId) {
+ currentMaxGroupId = fixedId;
+ }
+ }
+ }
+ }
+
+ // If there were fixed group Ids. Set next group Id to be current max
+ // group Id + 1
+ if (currentMaxGroupId != 0) {
+ nextGroupId = currentMaxGroupId + 1;
+ }
+
+ // Get current max group id in model
+ int maxGroupIdInModel = 0;
+ for (TraceGroup group : groups) {
+ int groupIdInModel = group.getID();
+ if (groupIdInModel > maxGroupIdInModel) {
+ maxGroupIdInModel = groupIdInModel;
+ }
+ }
+
+ // If next group Id is zero or smaller than current max group id in
+ // model + 1. Set it be same as current max group id in model + 1. This
+ // is done in case that we have added more than one new group after last
+ // fixed Id update
+ if (nextGroupId == 0 || nextGroupId < maxGroupIdInModel + 1) {
+ nextGroupId = maxGroupIdInModel + 1;
+ }
+
+ // Check that next group Id is not bigger than max group Id
+ if (nextGroupId > TraceCompilerEngineGlobals.MAX_GROUP_ID) {
+ throw new TraceCompilerException(
+ TraceCompilerErrorCode.RUN_OUT_OF_GROUP_IDS);
+ }
+
+ return nextGroupId;
+ }
+
+ /**
+ * Returns highest constant table ID + 1. Can be used to create an unique ID
+ * for a new constant table.
+ *
+ * @return the next constant table ID
+ */
+ public int getNextConstantTableID() {
+ int max = 0;
+ for (TraceConstantTable table : constantTables) {
+ int id = table.getID();
+ if (id > max) {
+ max = id;
+ }
+ }
+ return max + 1;
+ }
+
+ /**
+ * Removes a trace group from this model. Create groupRemoved event to model
+ * listeners
+ *
+ * @param group
+ * the group to be removed
+ * @throws TraceCompilerException
+ */
+ public void removeGroup(TraceGroup group) throws TraceCompilerException {
+ if (groups.remove(group)) {
+ notifyObjectRemoved(this, group);
+ group.reset();
+ }
+ }
+
+ /**
+ * Determines if this model contains any trace groups
+ *
+ * @return true if there are trace groups
+ */
+ public boolean hasGroups() {
+ return !groups.isEmpty();
+ }
+
+ /**
+ * Gets the number of trace groups
+ *
+ * @return trace group count
+ */
+ public int getGroupCount() {
+ return groups.size();
+ }
+
+ /**
+ * Returns the trace groups of this model
+ *
+ * @return the iterator over the groups
+ */
+ public Iterator<TraceGroup> getGroups() {
+ return groups.iterator();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Iterable#iterator()
+ */
+ public Iterator<TraceGroup> iterator() {
+ return groups.iterator();
+ }
+
+ /**
+ * Removes all trace groups and parameters from this model. Extensions are
+ * not removed. Notifies the reset listeners with modelResetting and
+ * modelReset
+ *
+ * @see TraceModelResetListener#modelResetting
+ * @see TraceModelResetListener#modelReset
+ */
+ @Override
+ public void reset() {
+ notifyModelResetting();
+ // Properties are removed, other extensions are left
+ removeExtensions(TraceObjectPropertyList.class);
+ groups.clear();
+ tracesByName.clear();
+ constantTables.clear();
+ fixedIds = null;
+ super.reset();
+ notifyModelReset();
+ }
+
+ /**
+ * Gets the group which has given ID
+ *
+ * @param id
+ * the id
+ * @return group or null
+ */
+ public TraceGroup findGroupByID(int id) {
+ TraceGroup retval = null;
+ for (TraceGroup group : groups) {
+ if (group.getID() == id) {
+ retval = group;
+ break;
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Locates a trace group which has the given name.
+ *
+ * @param name
+ * the name of the trace group
+ * @return the group or null if not found
+ * @see TraceObject#getName
+ */
+ public TraceGroup findGroupByName(String name) {
+ TraceGroup retval = null;
+ for (TraceGroup group : groups) {
+ if (group.getName().equals(name)) {
+ retval = group;
+ break;
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Locates a trace which has the given name.
+ *
+ * @param name
+ * the name of the trace
+ * @return the trace or null if not found
+ * @see TraceObject#getName
+ */
+ public Trace findTraceByName(String name) {
+ Trace retval;
+ int index = Collections.binarySearch(tracesByName, name,
+ TraceObjectUtils.traceToNameComparator);
+ if (index >= 0) {
+ retval = tracesByName.get(index);
+ } else {
+ retval = null;
+ }
+ return retval;
+ }
+
+ /**
+ * Returns the group at given index
+ *
+ * @param index
+ * the group index
+ * @return the group
+ */
+ public TraceGroup getGroupAt(int index) {
+ return groups.get(index);
+ }
+
+ /**
+ * Removes a constant table from this model. Creates objectRemoved event to
+ * model listeners
+ *
+ * @see TraceModelListener#objectRemoved(TraceObject, TraceObject)
+ * @param table
+ * the table to be removed
+ * @throws TraceCompilerException
+ */
+ public void removeConstantTable(TraceConstantTable table) throws TraceCompilerException {
+ if (constantTables.remove(table)) {
+ notifyObjectRemoved(this, table);
+ table.reset();
+ }
+ }
+
+ /**
+ * Gets the constant tables of this model
+ *
+ * @return the tables iterator
+ */
+ public Iterator<TraceConstantTable> getConstantTables() {
+ return constantTables.iterator();
+ }
+
+ /**
+ * Gets a constant table by ID
+ *
+ * @param id
+ * the ID
+ * @return the table or null
+ */
+ public TraceConstantTable findConstantTableByID(int id) {
+ TraceConstantTable retval = null;
+ for (TraceConstantTable table : constantTables) {
+ if (table.getID() == id) {
+ retval = table;
+ break;
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Gets a constant table by name
+ *
+ * @param tableName
+ * the name
+ * @return the table or null
+ */
+ public TraceConstantTable findConstantTableByName(String tableName) {
+ TraceConstantTable retval = null;
+ for (TraceConstantTable table : constantTables) {
+ if (table.getName().equals(tableName)) {
+ retval = table;
+ break;
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Checks if this model contains constant tables
+ *
+ * @return true if there are constant tables
+ */
+ public boolean hasConstantTables() {
+ return !constantTables.isEmpty();
+ }
+
+ /**
+ * Returns the constant table at given index
+ *
+ * @param index
+ * the group index
+ * @return the group
+ */
+ public TraceConstantTable getConstantTableAt(int index) {
+ return constantTables.get(index);
+ }
+
+ /**
+ * Adds a new trace group to this model. Creates objectAdded event to model
+ * listeners. This is only intended to be called from TraceGroup
+ * constructor, so this is not public.
+ *
+ * @see TraceModelListener#objectAdded(TraceObject, TraceObject)
+ * @param group
+ * the group to be added
+ */
+ void addGroup(TraceGroup group) {
+ groups.add(group);
+ notifyObjectAdded(this, group);
+ }
+
+ /**
+ * Adds a constant table to this model. Created objectAdded event to model
+ * listeners. This is only intended to be called from constant table
+ * constructor, so this is not public
+ *
+ * @see TraceModelListener#objectAdded(TraceObject, TraceObject)
+ * @param table
+ * the constant table
+ */
+ void addConstantTable(TraceConstantTable table) {
+ constantTables.add(table);
+ notifyObjectAdded(this, table);
+ }
+
+ /**
+ * Fires propertiesUpdated event. Called from trace objects when their
+ * properties change.
+ *
+ * @see TraceModelListener#propertyUpdated(TraceObject, int)
+ * @param source
+ * the object that changed
+ * @param property
+ * the property that changed
+ * @throws TraceCompilerException
+ */
+ void notifyPropertyUpdated(TraceObject source, int property) throws TraceCompilerException {
+ if (source instanceof Trace) {
+ if (property == TraceModelListener.NAME) {
+ Collections.sort(tracesByName,
+ TraceObjectUtils.traceObjectNameComparator);
+ }
+ ((Trace) source).getGroup().tracePropertyUpdated(source, property);
+ }
+ for (TraceModelListener l : modelListeners) {
+ l.propertyUpdated(source, property);
+ }
+ modelChangedDuringProcessing = true;
+ }
+
+ /**
+ * Fires objectAdded event to listeners
+ *
+ * @see TraceModelListener#objectAdded(TraceObject, TraceObject)
+ * @param owner
+ * the owner object
+ * @param object
+ * the object that was added
+ */
+ void notifyObjectAdded(TraceObject owner, TraceObject object) {
+ // List is sorted when the name is set to the trace
+ if (object instanceof Trace) {
+ tracesByName.add((Trace) object);
+ }
+ for (TraceModelListener l : modelListeners) {
+ l.objectAdded(owner, object);
+ }
+ modelChangedDuringProcessing = true;
+ }
+
+ /**
+ * Fires objectRemoved event to listeners
+ *
+ * @see TraceModelListener#objectRemoved(TraceObject, TraceObject)
+ * @param owner
+ * the owner object
+ * @param object
+ * the object that was removed
+ * @throws TraceCompilerException
+ */
+ void notifyObjectRemoved(TraceObject owner, TraceObject object) throws TraceCompilerException {
+ if (object instanceof Trace) {
+ int index = Collections.binarySearch(tracesByName, (Trace) object,
+ TraceObjectUtils.traceObjectNameComparator);
+ tracesByName.remove(index);
+ }
+ notifyOnDelete(object);
+ for (TraceModelListener l : modelListeners) {
+ l.objectRemoved(owner, object);
+ }
+ modelChangedDuringProcessing = true;
+ }
+
+ /**
+ * Notifies that an object creation is complete
+ *
+ * @see TraceModelListener#objectCreationComplete(TraceObject)
+ * @param object
+ * the object
+ * @throws TraceCompilerException
+ */
+ void notifyObjectCreationComplete(TraceObject object) throws TraceCompilerException {
+ for (TraceModelListener l : modelListeners) {
+ l.objectCreationComplete(object);
+ }
+ }
+
+ /**
+ * Fires modelResetting event to all listeners
+ *
+ * @see TraceModelResetListener#modelResetting()
+ */
+ private void notifyModelResetting() {
+ for (TraceModelResetListener l : resetListeners) {
+ l.modelResetting();
+ }
+ }
+
+ /**
+ * Fires modelReset event to all listeners
+ *
+ * @see TraceModelResetListener#modelReset()
+ */
+ private void notifyModelReset() {
+ for (TraceModelResetListener l : resetListeners) {
+ l.modelReset();
+ }
+ }
+
+ /**
+ * Fires extensionAdded event. Called from TraceObject when extension is
+ * added to it
+ *
+ * @see TraceModelExtensionListener#extensionAdded(TraceObject,
+ * TraceModelExtension)
+ * @param object
+ * the trace object
+ * @param extension
+ * the new extension
+ */
+ void notifyExtensionAdded(TraceObject object, TraceModelExtension extension) {
+ for (TraceModelExtensionListener l : extensionListeners) {
+ l.extensionAdded(object, extension);
+ }
+ modelChangedDuringProcessing = true;
+ }
+
+ /**
+ * Fires extensionRemoved event. Called from TraceObject when extension is
+ * removed from it
+ *
+ * @see TraceModelExtensionListener#extensionRemoved(TraceObject,
+ * TraceModelExtension)
+ * @param object
+ * the object
+ * @param extension
+ * the removed extension
+ */
+ void notifyExtensionRemoved(TraceObject object,
+ TraceModelExtension extension) {
+ for (TraceModelExtensionListener l : extensionListeners) {
+ l.extensionRemoved(object, extension);
+ }
+ modelChangedDuringProcessing = true;
+ }
+
+ /**
+ * Gets the validity flag of this model
+ *
+ * @return the validity flag
+ */
+ public boolean isValid() {
+ return valid;
+ }
+
+ /**
+ * Sets the validity flag
+ *
+ * @param valid
+ * new flag value
+ * @throws TraceCompilerException
+ */
+ public void setValid(boolean valid) throws TraceCompilerException {
+ if (valid != this.valid) {
+ this.valid = valid;
+ for (TraceModelResetListener l : resetListeners) {
+ l.modelValid(valid);
+ }
+ }
+ }
+
+ /**
+ * Gets the trace object factory
+ *
+ * @return the factory
+ */
+ public TraceObjectFactory getFactory() {
+ return factory;
+ }
+
+ /**
+ * Gets the object verifier interface. The verifier should be used before
+ * updating object properties
+ *
+ * @return the verifier
+ */
+ public TraceObjectPropertyVerifier getVerifier() {
+ return verifier;
+ }
+
+ /**
+ * Notifies the process listeners that a process the results in multiple
+ * listener updates is about to start
+ */
+ public void startProcessing() {
+ isProcessing++;
+ if (isProcessing == 1) {
+ modelChangedDuringProcessing = false;
+ for (TraceProcessingListener l : processingListeners) {
+ l.processingStarted();
+ }
+ }
+ }
+
+ /**
+ * Notifies the process listeners that a process the results in multiple
+ * listener updates has finished
+ */
+ public void processingComplete() {
+ isProcessing--;
+ if (isProcessing == 0) {
+ for (TraceProcessingListener l : processingListeners) {
+ l.processingComplete(modelChangedDuringProcessing);
+ }
+ modelChangedDuringProcessing = false;
+ }
+ }
+
+ /**
+ * Checks the state of the processing flag
+ *
+ * @return the processing flag
+ */
+ public boolean isProcessing() {
+ return isProcessing > 0;
+ }
+
+ /**
+ * Checks if model has traces
+ *
+ * @return true if there's traces, false if not
+ */
+ public boolean hasTraces() {
+ boolean retval = false;
+ for (TraceGroup group : groups) {
+ if (group.hasTraces()) {
+ retval = true;
+ break;
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Gets group ID from properties
+ *
+ * @param properties
+ * the properties
+ * @param group
+ * the group
+ * @return the group ID
+ * @throws TraceCompilerException
+ */
+ public int getGroupID(Properties properties, TraceGroup group)
+ throws TraceCompilerException {
+ String value = properties.getProperty(GROUP_PROPERTY_PREFIX
+ + group.getName());
+ int id;
+ if (value == null) {
+ // Not found, assign a proper ID
+ id = getNewIdForGroup(group);
+
+ } else {
+ try {
+ id = Integer.decode(value).intValue();
+ TraceGroup traceGroup = findGroupByID(id);
+ if (traceGroup != null && !traceGroup.equals(group)) {
+ // Id already in use, assign a proper ID
+ id = getNewIdForGroup(group);
+ }
+ } catch (NumberFormatException e) {
+ // Corrupted, assign a proper ID
+ id = getNewIdForGroup(group);
+ }
+ }
+ group.internalSetID(id);
+ return id;
+ }
+
+ /**
+ * Gets a new ID for this group
+ *
+ * @param group
+ * the group
+ * @return a new ID for this group
+ * @throws TraceCompilerException
+ */
+ private int getNewIdForGroup(TraceGroup group) throws TraceCompilerException {
+ int id = FormattingUtils.getGroupID(group.getModel(), group.getName());
+ return id;
+ }
+
+ /**
+ * Saves trace and group identifiers to given properties.
+ *
+ * @param properties
+ * the properties to use
+ */
+ public void saveIDs(Properties properties) {
+ properties.clear();
+ StringBuffer sb = new StringBuffer();
+ for (TraceGroup group : this) {
+ int groupId = group.getID();
+ properties.setProperty(GROUP_PROPERTY_PREFIX + group.getName(),
+ SourceConstants.HEX_PREFIX + Integer.toHexString(groupId));
+ for (Trace trace : group) {
+ int traceId = trace.getID();
+ properties.setProperty(TRACE_PROPERTY_PREFIX
+ + createTraceName(sb, group, trace),
+ SourceConstants.HEX_PREFIX
+ + Integer.toHexString(traceId));
+ }
+ }
+ }
+
+ /**
+ * Merges the group and trace names together
+ *
+ * @param sb
+ * the buffer where name is stored
+ * @param group
+ * group
+ * @param trace
+ * trace
+ * @return the trace name
+ */
+ public String createTraceName(StringBuffer sb, TraceGroup group, Trace trace) {
+ sb.setLength(0);
+ sb.append(group.getName());
+ sb.append(GROUP_ID_PREFIX);
+ int groupId = group.getID();
+ String groupIdString = SourceConstants.HEX_PREFIX
+ + Integer.toString(groupId, HEX_RADIX).toUpperCase();
+ sb.append(groupIdString);
+ sb.append(GROUP_ID_SUFFIX);
+ sb.append(SourceConstants.UNDERSCORE);
+ sb.append(trace.getName());
+ return sb.toString();
+ }
+
+ /**
+ * Gets fixed group and trace ids
+ *
+ * @return fixed Ids
+ */
+ public SortedProperties getFixedIds() {
+ return fixedIds;
+ }
+
+ /**
+ * Set fixed group and trace ids
+ *
+ * @param fixedIds
+ * fixed Ids
+ */
+ public void setFixedIds(SortedProperties fixedIds) {
+ this.fixedIds = fixedIds;
+ }
+
+ /**
+ * Gets next trace ID
+ *
+ * @param group
+ * the group
+ * @return the trace ID
+ * @throws TraceCompilerException
+ */
+ public int getNextTraceId(TraceGroup group) throws TraceCompilerException {
+ int currentMaxTraceID = 0;
+ int nextTraceId = 0;
+ // Check if there are some fixed Ids
+ if (fixedIds != null) {
+ Enumeration<Object> keys = this.fixedIds.keys();
+ String groupName = group.getName();
+ int groupId = group.getID();
+ String groupIdString = SourceConstants.HEX_PREFIX
+ + Integer.toString(groupId, HEX_RADIX).toUpperCase();
+ // Go through fixed Ids and check if there are fixed trace Ids to
+ // this group
+ while (keys.hasMoreElements()) {
+ String key = (String) keys.nextElement();
+ if (key.startsWith(TRACE_PROPERTY_PREFIX + groupName
+ + GROUP_ID_PREFIX + groupIdString + GROUP_ID_SUFFIX
+ + SourceConstants.UNDERSCORE)
+ || key.startsWith(OBSOLETE_PROPERTY_PREFIX
+ + TRACE_PROPERTY_PREFIX + groupName
+ + GROUP_ID_PREFIX + groupIdString
+ + GROUP_ID_SUFFIX + SourceConstants.UNDERSCORE)) {
+ // Fixed trace Id to in this group found. Try to covert it
+ // to int value.
+ String value = fixedIds.getProperty(key);
+ int fixedId = 0;
+ try {
+ fixedId = Integer.decode(value).intValue();
+ } catch (NumberFormatException e) {
+ // Corrupted. Get next trace Id later on.
+ nextTraceId = 0;
+ break;
+ }
+ // Check if found fixed Id is bigger than current max trace
+ // Id in this group
+ if (fixedId > currentMaxTraceID) {
+ currentMaxTraceID = fixedId;
+ }
+ }
+ }
+ // If there were fixed trace Ids to this group. Set next trace Id to
+ // be current max trace Id + 1
+ if (currentMaxTraceID != 0) {
+ nextTraceId = currentMaxTraceID + 1;
+ }
+ // If next trace Id is zero or smaller than trace Id that group
+ // suggest. Set it be same as group suggest. This is done in case
+ // that we have added more than one new trace to same group after
+ // last fixed Id update
+ if (nextTraceId == 0 || nextTraceId < group.getNextTraceID()) {
+ nextTraceId = group.getNextTraceID();
+ }
+ } else {
+ // No fixed Ids. Get next trace Id from group
+ nextTraceId = group.getNextTraceID();
+ }
+ // Check that next trace Id is not bigger than max trace Id
+ if (nextTraceId > TraceCompilerEngineGlobals.MAX_TRACE_ID) {
+ throw new TraceCompilerException(
+ TraceCompilerErrorCode.RUN_OUT_OF_TRACE_IDS);
+ }
+
+ return nextTraceId;
+ }
+
+}